2022-08-27 11:52:29 +05:30
|
|
|
// TODO
|
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
import { GlAlert, GlBadge, GlLoadingIcon, GlTabs } from '@gitlab/ui';
|
2022-08-27 11:52:29 +05:30
|
|
|
import { mount, shallowMount } from '@vue/test-utils';
|
2022-08-13 15:12:31 +05:30
|
|
|
import VueApollo from 'vue-apollo';
|
2021-12-11 22:18:48 +05:30
|
|
|
import Vue, { nextTick } from 'vue';
|
2022-08-13 15:12:31 +05:30
|
|
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
2021-12-11 22:18:48 +05:30
|
|
|
import setWindowLocation from 'helpers/set_window_location_helper';
|
2021-03-11 19:13:27 +05:30
|
|
|
import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
|
2022-07-23 23:45:48 +05:30
|
|
|
import CiValidate from '~/pipeline_editor/components/validate/ci_validate.vue';
|
|
|
|
import WalkthroughPopover from '~/pipeline_editor/components/popovers/walkthrough_popover.vue';
|
2021-03-11 19:13:27 +05:30
|
|
|
import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
|
2021-04-29 21:17:54 +05:30
|
|
|
import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue';
|
|
|
|
import {
|
2021-12-11 22:18:48 +05:30
|
|
|
CREATE_TAB,
|
2021-04-29 21:17:54 +05:30
|
|
|
EDITOR_APP_STATUS_EMPTY,
|
|
|
|
EDITOR_APP_STATUS_LOADING,
|
|
|
|
EDITOR_APP_STATUS_INVALID,
|
|
|
|
EDITOR_APP_STATUS_VALID,
|
2021-12-11 22:18:48 +05:30
|
|
|
TAB_QUERY_PARAM,
|
2022-08-13 15:12:31 +05:30
|
|
|
VALIDATE_TAB,
|
|
|
|
VALIDATE_TAB_BADGE_DISMISSED_KEY,
|
2021-04-29 21:17:54 +05:30
|
|
|
} from '~/pipeline_editor/constants';
|
2021-03-11 19:13:27 +05:30
|
|
|
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
|
2022-08-13 15:12:31 +05:30
|
|
|
import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
|
|
|
|
import {
|
|
|
|
mockBlobContentQueryResponse,
|
|
|
|
mockCiLintPath,
|
|
|
|
mockCiYml,
|
|
|
|
mockLintResponse,
|
|
|
|
mockLintResponseWithoutMerged,
|
|
|
|
} from '../mock_data';
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
Vue.use(VueApollo);
|
2021-12-11 22:18:48 +05:30
|
|
|
|
|
|
|
Vue.config.ignoredElements = ['gl-emoji'];
|
2021-03-11 19:13:27 +05:30
|
|
|
|
|
|
|
describe('Pipeline editor tabs component', () => {
|
|
|
|
let wrapper;
|
|
|
|
const MockTextEditor = {
|
|
|
|
template: '<div />',
|
|
|
|
};
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
const createComponent = ({
|
2021-12-11 22:18:48 +05:30
|
|
|
listeners = {},
|
2021-04-29 21:17:54 +05:30
|
|
|
props = {},
|
|
|
|
provide = {},
|
|
|
|
appStatus = EDITOR_APP_STATUS_VALID,
|
|
|
|
mountFn = shallowMount,
|
2022-08-13 15:12:31 +05:30
|
|
|
options = {},
|
2021-04-29 21:17:54 +05:30
|
|
|
} = {}) => {
|
2021-03-11 19:13:27 +05:30
|
|
|
wrapper = mountFn(PipelineEditorTabs, {
|
|
|
|
propsData: {
|
|
|
|
ciConfigData: mockLintResponse,
|
|
|
|
ciFileContent: mockCiYml,
|
2022-08-13 15:12:31 +05:30
|
|
|
currentTab: CREATE_TAB,
|
2021-12-11 22:18:48 +05:30
|
|
|
isNewCiConfigFile: true,
|
2022-06-21 17:19:12 +05:30
|
|
|
showDrawer: false,
|
2021-03-11 19:13:27 +05:30
|
|
|
...props,
|
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
appStatus,
|
|
|
|
};
|
|
|
|
},
|
2022-08-13 15:12:31 +05:30
|
|
|
provide: {
|
2022-08-27 11:52:29 +05:30
|
|
|
ciConfigPath: '/path/to/ci-config',
|
2022-08-13 15:12:31 +05:30
|
|
|
ciLintPath: mockCiLintPath,
|
2022-08-27 11:52:29 +05:30
|
|
|
currentBranch: 'main',
|
|
|
|
projectFullPath: '/path/to/project',
|
|
|
|
simulatePipelineHelpPagePath: 'path/to/help/page',
|
|
|
|
validateTabIllustrationPath: 'path/to/svg',
|
2022-08-13 15:12:31 +05:30
|
|
|
...provide,
|
|
|
|
},
|
2021-03-11 19:13:27 +05:30
|
|
|
stubs: {
|
|
|
|
TextEditor: MockTextEditor,
|
2021-04-29 21:17:54 +05:30
|
|
|
EditorTab,
|
2021-03-11 19:13:27 +05:30
|
|
|
},
|
2021-12-11 22:18:48 +05:30
|
|
|
listeners,
|
2022-08-13 15:12:31 +05:30
|
|
|
...options,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
let mockBlobContentData;
|
|
|
|
let mockApollo;
|
|
|
|
|
|
|
|
const createComponentWithApollo = ({ props, provide = {}, mountFn = shallowMount } = {}) => {
|
|
|
|
const handlers = [[getBlobContent, mockBlobContentData]];
|
|
|
|
mockApollo = createMockApollo(handlers);
|
|
|
|
|
|
|
|
createComponent({
|
|
|
|
props,
|
|
|
|
provide,
|
|
|
|
mountFn,
|
|
|
|
options: {
|
|
|
|
apolloProvider: mockApollo,
|
|
|
|
},
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const findEditorTab = () => wrapper.find('[data-testid="editor-tab"]');
|
|
|
|
const findMergedTab = () => wrapper.find('[data-testid="merged-tab"]');
|
2022-07-23 23:45:48 +05:30
|
|
|
const findValidateTab = () => wrapper.find('[data-testid="validate-tab"]');
|
2021-03-11 19:13:27 +05:30
|
|
|
const findVisualizationTab = () => wrapper.find('[data-testid="visualization-tab"]');
|
|
|
|
|
|
|
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
2022-08-13 15:12:31 +05:30
|
|
|
const findBadge = () => wrapper.findComponent(GlBadge);
|
2022-07-23 23:45:48 +05:30
|
|
|
const findCiValidate = () => wrapper.findComponent(CiValidate);
|
2021-12-11 22:18:48 +05:30
|
|
|
const findGlTabs = () => wrapper.findComponent(GlTabs);
|
2021-03-11 19:13:27 +05:30
|
|
|
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
|
|
|
const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
|
|
|
|
const findTextEditor = () => wrapper.findComponent(MockTextEditor);
|
|
|
|
const findMergedPreview = () => wrapper.findComponent(CiConfigMergedPreview);
|
2021-12-11 22:18:48 +05:30
|
|
|
const findWalkthroughPopover = () => wrapper.findComponent(WalkthroughPopover);
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
mockBlobContentData = jest.fn();
|
|
|
|
});
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
afterEach(() => {
|
|
|
|
wrapper.destroy();
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('editor tab', () => {
|
|
|
|
it('displays editor only after the tab is mounted', async () => {
|
2022-08-27 11:52:29 +05:30
|
|
|
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
|
|
|
|
createComponentWithApollo({ mountFn: mount });
|
2021-03-11 19:13:27 +05:30
|
|
|
|
|
|
|
expect(findTextEditor().exists()).toBe(false);
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
expect(findTextEditor().exists()).toBe(true);
|
|
|
|
expect(findEditorTab().exists()).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('visualization tab', () => {
|
2021-06-08 01:23:25 +05:30
|
|
|
describe('while loading', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('displays a loading icon if the lint query is loading', () => {
|
|
|
|
expect(findLoadingIcon().exists()).toBe(true);
|
|
|
|
expect(findPipelineGraph().exists()).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe('after loading', () => {
|
2021-03-11 19:13:27 +05:30
|
|
|
beforeEach(() => {
|
2021-06-08 01:23:25 +05:30
|
|
|
createComponent();
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('display the tab and visualization', () => {
|
|
|
|
expect(findVisualizationTab().exists()).toBe(true);
|
|
|
|
expect(findPipelineGraph().exists()).toBe(true);
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
describe('validate tab', () => {
|
2022-08-27 11:52:29 +05:30
|
|
|
describe('after loading', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent();
|
2022-07-23 23:45:48 +05:30
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
it('displays the tab and the validate component', () => {
|
|
|
|
expect(findValidateTab().exists()).toBe(true);
|
|
|
|
expect(findCiValidate().exists()).toBe(true);
|
2022-07-23 23:45:48 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
describe('NEW badge', () => {
|
|
|
|
describe('default', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
|
|
|
|
createComponentWithApollo({
|
|
|
|
mountFn: mount,
|
|
|
|
props: {
|
|
|
|
currentTab: VALIDATE_TAB,
|
2022-07-23 23:45:48 +05:30
|
|
|
},
|
2022-08-27 11:52:29 +05:30
|
|
|
});
|
2022-07-23 23:45:48 +05:30
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
it('renders badge by default', () => {
|
|
|
|
expect(findBadge().exists()).toBe(true);
|
|
|
|
expect(findBadge().text()).toBe(wrapper.vm.$options.i18n.new);
|
|
|
|
});
|
2022-07-23 23:45:48 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
it('hides badge when moving away from the validate tab', async () => {
|
|
|
|
expect(findBadge().exists()).toBe(true);
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
await findEditorTab().vm.$emit('click');
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
expect(findBadge().exists()).toBe(false);
|
|
|
|
});
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
describe('if badge has been dismissed before', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
localStorage.setItem(VALIDATE_TAB_BADGE_DISMISSED_KEY, 'true');
|
|
|
|
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
|
|
|
|
createComponentWithApollo({ mountFn: mount });
|
2022-07-23 23:45:48 +05:30
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
it('does not render badge if it has been dismissed before', () => {
|
|
|
|
expect(findBadge().exists()).toBe(false);
|
|
|
|
});
|
2022-07-23 23:45:48 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2022-08-27 11:52:29 +05:30
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
describe('merged tab', () => {
|
2021-06-08 01:23:25 +05:30
|
|
|
describe('while loading', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('displays a loading icon if the lint query is loading', () => {
|
|
|
|
expect(findLoadingIcon().exists()).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
describe('when there is a fetch error', () => {
|
|
|
|
beforeEach(() => {
|
2021-12-11 22:18:48 +05:30
|
|
|
createComponent({ props: { ciConfigData: mockLintResponseWithoutMerged } });
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('show an error message', () => {
|
|
|
|
expect(findAlert().exists()).toBe(true);
|
|
|
|
expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts.loadMergedYaml);
|
|
|
|
});
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('does not render the `merged_preview` component', () => {
|
|
|
|
expect(findMergedPreview().exists()).toBe(false);
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
});
|
2021-06-08 01:23:25 +05:30
|
|
|
|
|
|
|
describe('after loading', () => {
|
2021-03-11 19:13:27 +05:30
|
|
|
beforeEach(() => {
|
2021-06-08 01:23:25 +05:30
|
|
|
createComponent();
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
it('display the tab and the merged preview component', () => {
|
|
|
|
expect(findMergedTab().exists()).toBe(true);
|
|
|
|
expect(findMergedPreview().exists()).toBe(true);
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-04-29 21:17:54 +05:30
|
|
|
|
|
|
|
describe('show tab content based on status', () => {
|
|
|
|
it.each`
|
2022-08-27 11:52:29 +05:30
|
|
|
appStatus | editor | viz | validate | merged
|
2021-04-29 21:17:54 +05:30
|
|
|
${undefined} | ${true} | ${true} | ${true} | ${true}
|
2022-08-27 11:52:29 +05:30
|
|
|
${EDITOR_APP_STATUS_EMPTY} | ${true} | ${false} | ${true} | ${false}
|
2023-01-13 00:05:48 +05:30
|
|
|
${EDITOR_APP_STATUS_INVALID} | ${true} | ${false} | ${true} | ${true}
|
2021-04-29 21:17:54 +05:30
|
|
|
${EDITOR_APP_STATUS_VALID} | ${true} | ${true} | ${true} | ${true}
|
|
|
|
`(
|
2022-10-11 01:57:18 +05:30
|
|
|
'when status is $appStatus, we show - editor:$editor | viz:$viz | validate:$validate | merged:$merged',
|
2022-08-27 11:52:29 +05:30
|
|
|
({ appStatus, editor, viz, validate, merged }) => {
|
2021-04-29 21:17:54 +05:30
|
|
|
createComponent({ appStatus });
|
|
|
|
|
|
|
|
expect(findTextEditor().exists()).toBe(editor);
|
|
|
|
expect(findPipelineGraph().exists()).toBe(viz);
|
2022-08-27 11:52:29 +05:30
|
|
|
expect(findValidateTab().exists()).toBe(validate);
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(findMergedPreview().exists()).toBe(merged);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
|
|
|
describe('default tab based on url query param', () => {
|
|
|
|
const gitlabUrl = 'https://gitlab.test/ci/editor/';
|
|
|
|
const matchObject = {
|
|
|
|
hostname: 'gitlab.test',
|
|
|
|
pathname: '/ci/editor/',
|
|
|
|
search: '',
|
|
|
|
};
|
|
|
|
|
|
|
|
it(`is ${CREATE_TAB} if the query param ${TAB_QUERY_PARAM} is not present`, () => {
|
|
|
|
setWindowLocation(gitlabUrl);
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
expect(window.location).toMatchObject(matchObject);
|
|
|
|
});
|
|
|
|
|
|
|
|
it(`is ${CREATE_TAB} tab if the query param ${TAB_QUERY_PARAM} is invalid`, () => {
|
|
|
|
const queryValue = 'FOO';
|
|
|
|
setWindowLocation(`${gitlabUrl}?${TAB_QUERY_PARAM}=${queryValue}`);
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
// If the query param remains unchanged, then we have ignored it.
|
|
|
|
expect(window.location).toMatchObject({
|
|
|
|
...matchObject,
|
|
|
|
search: `?${TAB_QUERY_PARAM}=${queryValue}`,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('glTabs', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('passes the `sync-active-tab-with-query-params` prop', () => {
|
|
|
|
expect(findGlTabs().props('syncActiveTabWithQueryParams')).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('pipeline editor walkthrough', () => {
|
|
|
|
describe('when isNewCiConfigFile prop is true (default)', () => {
|
2022-08-27 11:52:29 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
createComponent();
|
2021-12-11 22:18:48 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('shows walkthrough popover', async () => {
|
|
|
|
expect(findWalkthroughPopover().exists()).toBe(true);
|
2021-12-11 22:18:48 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('when isNewCiConfigFile prop is false', () => {
|
|
|
|
it('does not show walkthrough popover', async () => {
|
2022-08-27 11:52:29 +05:30
|
|
|
createComponent({ props: { isNewCiConfigFile: false } });
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(findWalkthroughPopover().exists()).toBe(false);
|
2021-12-11 22:18:48 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets listeners on walkthrough popover', async () => {
|
|
|
|
const handler = jest.fn();
|
|
|
|
|
|
|
|
createComponent({
|
|
|
|
listeners: {
|
|
|
|
event: handler,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
findWalkthroughPopover().vm.$emit('event');
|
|
|
|
|
|
|
|
expect(handler).toHaveBeenCalled();
|
|
|
|
});
|
2021-03-11 19:13:27 +05:30
|
|
|
});
|