debian-mirror-gitlab/spec/frontend/pipelines/pipelines_spec.js

787 lines
27 KiB
JavaScript
Raw Normal View History

2021-06-08 01:23:25 +05:30
import '~/commons';
2021-04-29 21:17:54 +05:30
import { GlButton, GlEmptyState, GlFilteredSearch, GlLoadingIcon, GlPagination } from '@gitlab/ui';
2020-05-24 23:13:21 +05:30
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
2021-03-11 19:13:27 +05:30
import { chunk } from 'lodash';
import { nextTick } from 'vue';
2021-11-18 22:05:49 +05:30
import mockPipelinesResponse from 'test_fixtures/pipelines/pipelines.json';
2021-10-27 15:23:28 +05:30
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
2022-10-11 01:57:18 +05:30
import { mockTracking } from 'helpers/tracking_helper';
2021-03-11 19:13:27 +05:30
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
2020-05-24 23:13:21 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2020-10-24 23:57:45 +05:30
import Api from '~/api';
2023-05-27 22:25:52 +05:30
import { createAlert, VARIANT_WARNING } from '~/alert';
2020-10-24 23:57:45 +05:30
import axios from '~/lib/utils/axios_utils';
2023-04-23 21:23:45 +05:30
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
2021-03-11 19:13:27 +05:30
import NavigationControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
2020-07-28 23:09:34 +05:30
import PipelinesComponent from '~/pipelines/components/pipelines_list/pipelines.vue';
2022-06-21 17:19:12 +05:30
import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue';
2021-03-11 19:13:27 +05:30
import PipelinesTableComponent from '~/pipelines/components/pipelines_list/pipelines_table.vue';
2022-10-11 01:57:18 +05:30
import { RAW_TEXT_WARNING, TRACKING_CATEGORIES } from '~/pipelines/constants';
2020-05-24 23:13:21 +05:30
import Store from '~/pipelines/stores/pipelines_store';
2021-03-11 19:13:27 +05:30
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
2021-04-17 20:07:23 +05:30
import { stageReply, users, mockSearch, branches } from './mock_data';
2020-05-24 23:13:21 +05:30
2023-05-27 22:25:52 +05:30
jest.mock('~/alert');
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
const mockProjectPath = 'twitter/flight';
const mockProjectId = '21';
2022-05-07 20:08:51 +05:30
const mockDefaultBranchName = 'main';
2021-03-11 19:13:27 +05:30
const mockPipelinesEndpoint = `/${mockProjectPath}/pipelines.json`;
const mockPipelinesIds = mockPipelinesResponse.pipelines.map(({ id }) => id);
2021-04-17 20:07:23 +05:30
const mockPipelineWithStages = mockPipelinesResponse.pipelines.find(
(p) => p.details.stages && p.details.stages.length,
);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('Pipelines', () => {
2020-05-24 23:13:21 +05:30
let wrapper;
let mock;
2022-10-11 01:57:18 +05:30
let trackingSpy;
2020-05-24 23:13:21 +05:30
const paths = {
2023-07-09 08:55:56 +05:30
emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
2020-05-24 23:13:21 +05:30
errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
noPipelinesSvgPath: '/assets/illustrations/pipelines_pending.svg',
ciLintPath: '/ci/lint',
2021-03-11 19:13:27 +05:30
resetCachePath: `${mockProjectPath}/settings/ci_cd/reset_cache`,
newPipelinePath: `${mockProjectPath}/pipelines/new`,
2022-08-27 11:52:29 +05:30
2021-09-04 01:27:46 +05:30
ciRunnerSettingsPath: `${mockProjectPath}/-/settings/ci_cd#js-runners-settings`,
2020-05-24 23:13:21 +05:30
};
const noPermissions = {
2023-07-09 08:55:56 +05:30
emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
2020-05-24 23:13:21 +05:30
errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
noPipelinesSvgPath: '/assets/illustrations/pipelines_pending.svg',
};
const defaultProps = {
hasGitlabCi: true,
canCreatePipeline: true,
...paths,
};
2021-03-11 19:13:27 +05:30
const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
2021-04-29 21:17:54 +05:30
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
2021-03-11 19:13:27 +05:30
const findNavigationTabs = () => wrapper.findComponent(NavigationTabs);
const findNavigationControls = () => wrapper.findComponent(NavigationControls);
const findPipelinesTable = () => wrapper.findComponent(PipelinesTableComponent);
const findTablePagination = () => wrapper.findComponent(TablePagination);
const findTab = (tab) => wrapper.findByTestId(`pipelines-tab-${tab}`);
2023-03-17 16:20:25 +05:30
const findPipelineKeyCollapsibleBox = () => wrapper.findByTestId('pipeline-key-collapsible-box');
2021-03-11 19:13:27 +05:30
const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button');
2021-04-17 20:07:23 +05:30
const findStagesDropdownToggle = () =>
wrapper.find('[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle');
2021-03-11 19:13:27 +05:30
const findPipelineUrlLinks = () => wrapper.findAll('[data-testid="pipeline-url-link"]');
2020-05-24 23:13:21 +05:30
2021-03-08 18:12:59 +05:30
const createComponent = (props = defaultProps) => {
2021-03-11 19:13:27 +05:30
wrapper = extendedWrapper(
mount(PipelinesComponent, {
2021-09-30 23:02:18 +05:30
provide: {
pipelineEditorPath: '',
suggestedCiTemplates: [],
2022-07-16 23:28:13 +05:30
ciRunnerSettingsPath: paths.ciRunnerSettingsPath,
anyRunnersAvailable: true,
2021-09-30 23:02:18 +05:30
},
2021-03-11 19:13:27 +05:30
propsData: {
store: new Store(),
projectId: mockProjectId,
2022-05-07 20:08:51 +05:30
defaultBranchName: mockDefaultBranchName,
2021-03-11 19:13:27 +05:30
endpoint: mockPipelinesEndpoint,
params: {},
...props,
},
}),
);
2020-05-24 23:13:21 +05:30
};
2021-10-27 15:23:28 +05:30
beforeEach(() => {
setWindowLocation(TEST_HOST);
2021-03-08 18:12:59 +05:30
});
beforeEach(() => {
2020-05-24 23:13:21 +05:30
mock = new MockAdapter(axios);
2021-03-11 19:13:27 +05:30
jest.spyOn(window.history, 'pushState');
2020-05-24 23:13:21 +05:30
jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
});
afterEach(() => {
2021-03-11 19:13:27 +05:30
mock.reset();
window.history.pushState.mockReset();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when pipelines are not yet loaded', () => {
beforeEach(async () => {
createComponent();
await nextTick();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('shows loading state when the app is loading', () => {
2022-10-11 01:57:18 +05:30
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('does not display tabs when the first request has not yet been made', () => {
expect(findNavigationTabs().exists()).toBe(false);
});
it('does not display buttons', () => {
expect(findNavigationControls().exists()).toBe(false);
});
});
describe('when there are pipelines in the project', () => {
beforeEach(() => {
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
2023-04-23 21:23:45 +05:30
.reply(HTTP_STATUS_OK, mockPipelinesResponse);
2021-03-11 19:13:27 +05:30
});
describe('when user has no permissions', () => {
beforeEach(async () => {
createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders "All" tab with count different from "0"', () => {
expect(findTab('all').text()).toMatchInterpolatedText('All 3');
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('does not render buttons', () => {
expect(findNavigationControls().exists()).toBe(false);
expect(findRunPipelineButton().exists()).toBe(false);
expect(findCiLintButton().exists()).toBe(false);
expect(findCleanCacheButton().exists()).toBe(false);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders pipelines in a table', () => {
expect(findPipelinesTable().exists()).toBe(true);
expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
2020-05-24 23:13:21 +05:30
});
});
2021-03-11 19:13:27 +05:30
describe('when user has permissions', () => {
beforeEach(async () => {
2020-05-24 23:13:21 +05:30
createComponent();
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should set up navigation tabs', () => {
expect(findNavigationTabs().props('tabs')).toEqual([
{ name: 'All', scope: 'all', count: '3', isActive: true },
{ name: 'Finished', scope: 'finished', count: undefined, isActive: false },
{ name: 'Branches', scope: 'branches', isActive: false },
{ name: 'Tags', scope: 'tags', isActive: false },
]);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders "All" tab with count different from "0"', () => {
expect(findTab('all').text()).toMatchInterpolatedText('All 3');
});
it('should render other navigation tabs', () => {
expect(findTab('finished').text()).toBe('Finished');
expect(findTab('branches').text()).toBe('Branches');
expect(findTab('tags').text()).toBe('Tags');
});
it('shows navigation controls', () => {
expect(findNavigationControls().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('renders Run pipeline link', () => {
2021-01-03 14:25:43 +05:30
expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('renders CI lint link', () => {
2021-01-03 14:25:43 +05:30
expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('renders Clear runner cache button', () => {
expect(findCleanCacheButton().text()).toBe('Clear runner caches');
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders pipelines in a table', () => {
expect(findPipelinesTable().exists()).toBe(true);
2021-01-03 14:25:43 +05:30
2021-03-11 19:13:27 +05:30
expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when user goes to a tab', () => {
const goToTab = (tab) => {
findNavigationTabs().vm.$emit('onChangeTab', tab);
};
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when the scope in the tab has pipelines', () => {
const mockFinishedPipeline = mockPipelinesResponse.pipelines[0];
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
beforeEach(async () => {
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
2023-04-23 21:23:45 +05:30
.reply(HTTP_STATUS_OK, {
2021-03-11 19:13:27 +05:30
pipelines: [mockFinishedPipeline],
count: mockPipelinesResponse.count,
});
2020-05-24 23:13:21 +05:30
2022-10-11 01:57:18 +05:30
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
2021-03-11 19:13:27 +05:30
goToTab('finished');
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it('should filter pipelines', () => {
2021-03-11 19:13:27 +05:30
expect(findPipelinesTable().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
expect(findPipelineUrlLinks()).toHaveLength(1);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFinishedPipeline.id}`);
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should update browser bar', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?scope=finished&page=1`,
);
});
2022-10-11 01:57:18 +05:30
2022-11-25 23:54:43 +05:30
it.each(['all', 'finished', 'branches', 'tags'])('tracks %p tab click', async (scope) => {
goToTab(scope);
await waitForPromises();
2022-10-11 01:57:18 +05:30
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filter_tabs', {
label: TRACKING_CATEGORIES.tabs,
2022-11-25 23:54:43 +05:30
property: scope,
2022-10-11 01:57:18 +05:30
});
});
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when the scope in the tab is empty', () => {
beforeEach(async () => {
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'branches', page: '1' } })
2023-04-23 21:23:45 +05:30
.reply(HTTP_STATUS_OK, {
2021-03-11 19:13:27 +05:30
pipelines: [],
count: mockPipelinesResponse.count,
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
goToTab('branches');
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it('should filter pipelines', () => {
2021-04-29 21:17:54 +05:30
expect(findEmptyState().text()).toBe('There are currently no pipelines.');
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should update browser bar', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?scope=branches&page=1`,
);
});
});
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when user triggers a filtered search', () => {
const mockFilteredPipeline = mockPipelinesResponse.pipelines[1];
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
let expectedParams;
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
beforeEach(async () => {
expectedParams = {
page: '1',
scope: 'all',
username: 'root',
2021-06-08 01:23:25 +05:30
ref: 'main',
2021-03-11 19:13:27 +05:30
status: 'pending',
};
mock
.onGet(mockPipelinesEndpoint, {
params: expectedParams,
})
2023-04-23 21:23:45 +05:30
.replyOnce(HTTP_STATUS_OK, {
2021-03-11 19:13:27 +05:30
pipelines: [mockFilteredPipeline],
count: mockPipelinesResponse.count,
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
findFilteredSearch().vm.$emit('submit', mockSearch);
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2023-06-20 00:43:36 +05:30
it('requests data with query params on filter submit', () => {
2021-03-11 19:13:27 +05:30
expect(mock.history.get[1].params).toEqual(expectedParams);
});
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it('renders filtered pipelines', () => {
2021-03-11 19:13:27 +05:30
expect(findPipelineUrlLinks()).toHaveLength(1);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.id}`);
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should update browser bar', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
2021-06-08 01:23:25 +05:30
`${window.location.pathname}?page=1&scope=all&username=root&ref=main&status=pending`,
2021-03-11 19:13:27 +05:30
);
});
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when user triggers a filtered search with raw text', () => {
beforeEach(async () => {
findFilteredSearch().vm.$emit('submit', ['rawText']);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it('requests data with query params on filter submit', () => {
2021-03-11 19:13:27 +05:30
expect(mock.history.get[1].params).toEqual({ page: '1', scope: 'all' });
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('displays a warning message if raw text search is used', () => {
2022-11-25 23:54:43 +05:30
expect(createAlert).toHaveBeenCalledTimes(1);
expect(createAlert).toHaveBeenCalledWith({
message: RAW_TEXT_WARNING,
variant: VARIANT_WARNING,
});
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should update browser bar', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?page=1&scope=all`,
);
});
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
});
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when there are multiple pages of pipelines', () => {
const mockPageSize = 2;
const mockPageHeaders = ({ page = 1 } = {}) => {
return {
'X-PER-PAGE': `${mockPageSize}`,
'X-PREV-PAGE': `${page - 1}`,
'X-PAGE': `${page}`,
'X-NEXT-PAGE': `${page + 1}`,
};
};
const [firstPage, secondPage] = chunk(mockPipelinesResponse.pipelines, mockPageSize);
const goToPage = (page) => {
2022-10-11 01:57:18 +05:30
findTablePagination().findComponent(GlPagination).vm.$emit('input', page);
2021-03-11 19:13:27 +05:30
};
beforeEach(async () => {
mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } }).reply(
2023-04-23 21:23:45 +05:30
HTTP_STATUS_OK,
2021-03-11 19:13:27 +05:30
{
pipelines: firstPage,
count: mockPipelinesResponse.count,
},
mockPageHeaders({ page: 1 }),
);
mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '2' } }).reply(
2023-04-23 21:23:45 +05:30
HTTP_STATUS_OK,
2021-03-11 19:13:27 +05:30
{
pipelines: secondPage,
count: mockPipelinesResponse.count,
},
mockPageHeaders({ page: 2 }),
);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
createComponent();
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('shows the first page of pipelines', () => {
expect(findPipelineUrlLinks()).toHaveLength(firstPage.length);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${firstPage[0].id}`);
expect(findPipelineUrlLinks().at(1).text()).toBe(`#${firstPage[1].id}`);
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('should not update browser bar', () => {
expect(window.history.pushState).not.toHaveBeenCalled();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when user goes to next page', () => {
beforeEach(async () => {
goToPage(2);
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('should update page and keep scope the same scope', () => {
expect(findPipelineUrlLinks()).toHaveLength(secondPage.length);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${secondPage[0].id}`);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('should update browser bar', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?page=2&scope=all`,
2020-05-24 23:13:21 +05:30
);
});
2023-04-23 21:23:45 +05:30
it('should reset page to 1 when filtering pipelines', () => {
expect(window.history.pushState).toHaveBeenCalledTimes(1);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?page=2&scope=all`,
);
findFilteredSearch().vm.$emit('submit', [
{ type: 'status', value: { data: 'success', operator: '=' } },
]);
expect(window.history.pushState).toHaveBeenCalledTimes(2);
expect(window.history.pushState).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
`${window.location.pathname}?page=1&scope=all&status=success`,
);
});
2020-05-24 23:13:21 +05:30
});
});
2021-03-11 19:13:27 +05:30
describe('when pipelines can be polled', () => {
beforeEach(() => {
const emptyResponse = {
pipelines: [],
count: { all: '0' },
};
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
// Mock no pipelines in the first attempt
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
2023-04-23 21:23:45 +05:30
.replyOnce(HTTP_STATUS_OK, emptyResponse, {
2021-03-11 19:13:27 +05:30
'POLL-INTERVAL': 100,
});
// Mock pipelines in the next attempt
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
2023-04-23 21:23:45 +05:30
.reply(HTTP_STATUS_OK, mockPipelinesResponse, {
2021-03-11 19:13:27 +05:30
'POLL-INTERVAL': 100,
});
});
describe('data is loaded for the first time', () => {
beforeEach(async () => {
2020-05-24 23:13:21 +05:30
createComponent();
2021-03-11 19:13:27 +05:30
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('shows tabs', () => {
expect(findNavigationTabs().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('should update page and keep scope the same scope', () => {
expect(findPipelineUrlLinks()).toHaveLength(0);
2021-01-03 14:25:43 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('data is loaded for a second time', () => {
beforeEach(async () => {
jest.runOnlyPendingTimers();
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('shows tabs', () => {
expect(findNavigationTabs().exists()).toBe(true);
});
2020-05-24 23:13:21 +05:30
2023-06-20 00:43:36 +05:30
it('is loading after a time', () => {
2021-03-11 19:13:27 +05:30
expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
2020-05-24 23:13:21 +05:30
});
});
});
});
2021-03-11 19:13:27 +05:30
describe('when no pipelines exist', () => {
2020-05-24 23:13:21 +05:30
beforeEach(() => {
2023-04-23 21:23:45 +05:30
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
.reply(HTTP_STATUS_OK, {
pipelines: [],
count: { all: '0' },
});
2021-01-03 14:25:43 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when CI is enabled and user has permissions', () => {
beforeEach(async () => {
createComponent();
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('renders tab with count of "0"', () => {
expect(findNavigationTabs().exists()).toBe(true);
expect(findTab('all').text()).toMatchInterpolatedText('All 0');
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('renders Run pipeline link', () => {
2021-03-11 19:13:27 +05:30
expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
});
2020-05-24 23:13:21 +05:30
2021-04-29 21:17:54 +05:30
it('renders CI lint link', () => {
2021-03-11 19:13:27 +05:30
expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('renders Clear runner cache button', () => {
expect(findCleanCacheButton().text()).toBe('Clear runner caches');
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('renders empty state', () => {
2021-04-29 21:17:54 +05:30
expect(findEmptyState().text()).toBe('There are currently no pipelines.');
});
it('renders filtered search', () => {
expect(findFilteredSearch().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
2023-03-17 16:20:25 +05:30
it('renders the pipeline key collapsible box', () => {
expect(findPipelineKeyCollapsibleBox().exists()).toBe(true);
2021-10-27 15:23:28 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders tab empty state finished scope', async () => {
2023-04-23 21:23:45 +05:30
mock
.onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
.reply(HTTP_STATUS_OK, {
pipelines: [],
count: { all: '0' },
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
findNavigationTabs().vm.$emit('onChangeTab', 'finished');
2021-01-03 14:25:43 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
2020-05-24 23:13:21 +05:30
2021-04-29 21:17:54 +05:30
expect(findEmptyState().text()).toBe('There are currently no finished pipelines.');
2021-03-11 19:13:27 +05:30
});
2021-01-03 14:25:43 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when CI is not enabled and user has permissions', () => {
beforeEach(async () => {
createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...paths });
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-09-30 23:02:18 +05:30
it('renders the CI/CD templates', () => {
2021-12-11 22:18:48 +05:30
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
2021-04-29 21:17:54 +05:30
it('does not render filtered search', () => {
expect(findFilteredSearch().exists()).toBe(false);
});
2021-10-27 15:23:28 +05:30
it('does not render the pipeline key dropdown', () => {
2023-03-17 16:20:25 +05:30
expect(findPipelineKeyCollapsibleBox().exists()).toBe(false);
2021-10-27 15:23:28 +05:30
});
2021-03-11 19:13:27 +05:30
it('does not render tabs nor buttons', () => {
expect(findNavigationTabs().exists()).toBe(false);
expect(findTab('all').exists()).toBe(false);
expect(findRunPipelineButton().exists()).toBe(false);
expect(findCiLintButton().exists()).toBe(false);
expect(findCleanCacheButton().exists()).toBe(false);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when CI is not enabled and user has no permissions', () => {
beforeEach(async () => {
createComponent({ hasGitlabCi: false, canCreatePipeline: false, ...noPermissions });
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders empty state without button to set CI', () => {
expect(findEmptyState().text()).toBe(
'This project is not currently set up to run pipelines.',
);
2020-05-24 23:13:21 +05:30
2022-10-11 01:57:18 +05:30
expect(findEmptyState().findComponent(GlButton).exists()).toBe(false);
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('does not render tabs or buttons', () => {
expect(findTab('all').exists()).toBe(false);
expect(findRunPipelineButton().exists()).toBe(false);
expect(findCiLintButton().exists()).toBe(false);
expect(findCleanCacheButton().exists()).toBe(false);
2020-05-24 23:13:21 +05:30
});
});
2021-03-11 19:13:27 +05:30
describe('when CI is enabled and user has no permissions', () => {
beforeEach(() => {
createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
return waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('renders tab with count of "0"', () => {
expect(findTab('all').text()).toMatchInterpolatedText('All 0');
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('does not render buttons', () => {
expect(findRunPipelineButton().exists()).toBe(false);
expect(findCiLintButton().exists()).toBe(false);
expect(findCleanCacheButton().exists()).toBe(false);
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('renders empty state', () => {
2021-04-29 21:17:54 +05:30
expect(findEmptyState().text()).toBe('There are currently no pipelines.');
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
});
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when a pipeline with stages exists', () => {
describe('updates results when a staged is clicked', () => {
let stopMock;
let restartMock;
let cancelMock;
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
beforeEach(() => {
mock.onGet(mockPipelinesEndpoint, { scope: 'all', page: '1' }).reply(
2023-04-23 21:23:45 +05:30
HTTP_STATUS_OK,
2021-03-11 19:13:27 +05:30
{
2021-04-17 20:07:23 +05:30
pipelines: [mockPipelineWithStages],
2021-03-11 19:13:27 +05:30
count: { all: '1' },
},
{
'POLL-INTERVAL': 100,
},
);
2021-04-17 20:07:23 +05:30
2023-04-23 21:23:45 +05:30
mock
.onGet(mockPipelineWithStages.details.stages[0].dropdown_path)
.reply(HTTP_STATUS_OK, stageReply);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
createComponent();
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
stopMock = jest.spyOn(wrapper.vm.poll, 'stop');
restartMock = jest.spyOn(wrapper.vm.poll, 'restart');
cancelMock = jest.spyOn(wrapper.vm.service.cancelationSource, 'cancel');
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when a request is being made', () => {
beforeEach(async () => {
2023-04-23 21:23:45 +05:30
mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_OK, mockPipelinesResponse);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('stops polling, cancels the request, & restarts polling', async () => {
// Mock init a polling cycle
wrapper.vm.poll.options.notificationCallback(true);
2022-08-27 11:52:29 +05:30
await findStagesDropdownToggle().trigger('click');
jest.runOnlyPendingTimers();
// cancelMock is getting overwritten in pipelines_service.js#L29
// so we have to spy on it again here
cancelMock = jest.spyOn(wrapper.vm.service.cancelationSource, 'cancel');
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
expect(cancelMock).toHaveBeenCalled();
expect(stopMock).toHaveBeenCalled();
expect(restartMock).toHaveBeenCalled();
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
it('stops polling & restarts polling', async () => {
2022-08-27 11:52:29 +05:30
await findStagesDropdownToggle().trigger('click');
jest.runOnlyPendingTimers();
2021-04-17 20:07:23 +05:30
await waitForPromises();
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
expect(cancelMock).not.toHaveBeenCalled();
expect(stopMock).toHaveBeenCalled();
expect(restartMock).toHaveBeenCalled();
2020-05-24 23:13:21 +05:30
});
});
});
});
2021-03-11 19:13:27 +05:30
describe('when pipelines cannot be loaded', () => {
2023-06-20 00:43:36 +05:30
beforeEach(() => {
2023-04-23 21:23:45 +05:30
mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, {});
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
describe('when user has no permissions', () => {
beforeEach(async () => {
createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...noPermissions });
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('renders tabs', () => {
expect(findNavigationTabs().exists()).toBe(true);
expect(findTab('all').text()).toBe('All');
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('does not render buttons', () => {
expect(findRunPipelineButton().exists()).toBe(false);
expect(findCiLintButton().exists()).toBe(false);
expect(findCleanCacheButton().exists()).toBe(false);
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('shows error state', () => {
2023-07-09 08:55:56 +05:30
expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
expect(findEmptyState().props('description')).toBe(
'Try again in a few moments or contact your support team.',
2021-03-11 19:13:27 +05:30
);
});
2020-05-24 23:13:21 +05:30
});
2021-03-11 19:13:27 +05:30
describe('when user has permissions', () => {
beforeEach(async () => {
createComponent();
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
await waitForPromises();
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('renders tabs', () => {
expect(findTab('all').text()).toBe('All');
});
it('renders buttons', () => {
expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
2021-04-29 21:17:54 +05:30
expect(findCleanCacheButton().text()).toBe('Clear runner caches');
2021-03-11 19:13:27 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-11 19:13:27 +05:30
it('shows error state', () => {
2023-07-09 08:55:56 +05:30
expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
expect(findEmptyState().props('description')).toBe(
'Try again in a few moments or contact your support team.',
2021-03-11 19:13:27 +05:30
);
});
2020-05-24 23:13:21 +05:30
});
});
});