Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pipeline_editor')
-rw-r--r--spec/frontend/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js61
-rw-r--r--spec/frontend/pipeline_editor/components/commit/commit_form_spec.js158
-rw-r--r--spec/frontend/pipeline_editor/components/commit/commit_section_spec.js287
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js60
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/cards/getting_started_card_spec.js26
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js89
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js26
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js27
-rw-r--r--spec/frontend/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js27
-rw-r--r--spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js69
-rw-r--r--spec/frontend/pipeline_editor/components/editor/ci_editor_header_spec.js115
-rw-r--r--spec/frontend/pipeline_editor/components/editor/text_editor_spec.js134
-rw-r--r--spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js432
-rw-r--r--spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js126
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/container_spec.js138
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js52
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js53
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js109
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js132
-rw-r--r--spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js109
-rw-r--r--spec/frontend/pipeline_editor/components/header/validation_segment_spec.js197
-rw-r--r--spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js177
-rw-r--r--spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js54
-rw-r--r--spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js342
-rw-r--r--spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js56
-rw-r--r--spec/frontend/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js43
-rw-r--r--spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js29
-rw-r--r--spec/frontend/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js42
-rw-r--r--spec/frontend/pipeline_editor/components/ui/editor_tab_spec.js200
-rw-r--r--spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js92
-rw-r--r--spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js149
-rw-r--r--spec/frontend/pipeline_editor/components/validate/ci_validate_spec.js314
-rw-r--r--spec/frontend/pipeline_editor/graphql/__snapshots__/resolvers_spec.js.snap73
-rw-r--r--spec/frontend/pipeline_editor/graphql/resolvers_spec.js52
-rw-r--r--spec/frontend/pipeline_editor/mock_data.js541
-rw-r--r--spec/frontend/pipeline_editor/pipeline_editor_app_spec.js589
-rw-r--r--spec/frontend/pipeline_editor/pipeline_editor_home_spec.js330
37 files changed, 0 insertions, 5510 deletions
diff --git a/spec/frontend/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js b/spec/frontend/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js
deleted file mode 100644
index d03f12bc249..00000000000
--- a/spec/frontend/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { within } from '@testing-library/dom';
-import { mount } from '@vue/test-utils';
-import { merge } from 'lodash';
-import { TEST_HOST } from 'helpers/test_constants';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import CodeSnippetAlert from '~/pipeline_editor/components/code_snippet_alert/code_snippet_alert.vue';
-import { CODE_SNIPPET_SOURCE_API_FUZZING } from '~/pipeline_editor/components/code_snippet_alert/constants';
-
-const apiFuzzingConfigurationPath = '/namespace/project/-/security/configuration/api_fuzzing';
-
-describe('EE - CodeSnippetAlert', () => {
- let wrapper;
-
- const createWrapper = (options) => {
- wrapper = extendedWrapper(
- mount(
- CodeSnippetAlert,
- merge(
- {
- provide: {
- configurationPaths: {
- [CODE_SNIPPET_SOURCE_API_FUZZING]: apiFuzzingConfigurationPath,
- },
- },
- propsData: {
- source: CODE_SNIPPET_SOURCE_API_FUZZING,
- },
- },
- options,
- ),
- ),
- );
- };
-
- const withinComponent = () => within(wrapper.element);
- const findDocsLink = () => withinComponent().getByRole('link', { name: /read documentation/i });
- const findConfigurationLink = () =>
- withinComponent().getByRole('link', { name: /Go back to configuration/i });
-
- beforeEach(() => {
- createWrapper();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it("provides a link to the feature's documentation", () => {
- const docsLink = findDocsLink();
-
- expect(docsLink).not.toBe(null);
- expect(docsLink.href).toBe(`${TEST_HOST}/help/user/application_security/api_fuzzing/index`);
- });
-
- it("provides a link to the feature's configuration form", () => {
- const configurationLink = findConfigurationLink();
-
- expect(configurationLink).not.toBe(null);
- expect(configurationLink.href).toBe(TEST_HOST + apiFuzzingConfigurationPath);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js
deleted file mode 100644
index 0ee6da9d329..00000000000
--- a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js
+++ /dev/null
@@ -1,158 +0,0 @@
-import { nextTick } from 'vue';
-import { GlFormInput, GlFormTextarea } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-
-import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
-
-import { mockCommitMessage, mockDefaultBranch } from '../../mock_data';
-
-const scrollIntoViewMock = jest.fn();
-HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
-
-describe('Pipeline Editor | Commit Form', () => {
- let wrapper;
-
- const createComponent = ({ props = {} } = {}, mountFn = shallowMount) => {
- wrapper = mountFn(CommitForm, {
- propsData: {
- defaultMessage: mockCommitMessage,
- currentBranch: mockDefaultBranch,
- hasUnsavedChanges: true,
- isNewCiConfigFile: false,
- ...props,
- },
-
- // attachTo is required for input/submit events
- attachTo: mountFn === mount ? document.body : null,
- });
- };
-
- const findCommitTextarea = () => wrapper.findComponent(GlFormTextarea);
- const findBranchInput = () => wrapper.findComponent(GlFormInput);
- const findNewMrCheckbox = () => wrapper.find('[data-testid="new-mr-checkbox"]');
- const findSubmitBtn = () => wrapper.find('[type="submit"]');
- const findCancelBtn = () => wrapper.find('[type="reset"]');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when the form is displayed', () => {
- beforeEach(async () => {
- createComponent();
- });
-
- it('shows a default commit message', () => {
- expect(findCommitTextarea().attributes('value')).toBe(mockCommitMessage);
- });
-
- it('shows current branch', () => {
- expect(findBranchInput().attributes('value')).toBe(mockDefaultBranch);
- });
-
- it('shows buttons', () => {
- expect(findSubmitBtn().exists()).toBe(true);
- expect(findCancelBtn().exists()).toBe(true);
- });
-
- it('does not show a new MR checkbox by default', () => {
- expect(findNewMrCheckbox().exists()).toBe(false);
- });
- });
-
- describe('when buttons are clicked', () => {
- beforeEach(async () => {
- createComponent({}, mount);
- });
-
- it('emits an event when the form submits', () => {
- findSubmitBtn().trigger('click');
-
- expect(wrapper.emitted('submit')[0]).toEqual([
- {
- message: mockCommitMessage,
- sourceBranch: mockDefaultBranch,
- openMergeRequest: false,
- },
- ]);
- });
-
- it('emits an event when the form resets', () => {
- findCancelBtn().trigger('click');
-
- expect(wrapper.emitted('resetContent')).toHaveLength(1);
- });
- });
-
- describe('submit button', () => {
- it.each`
- hasUnsavedChanges | isNewCiConfigFile | isDisabled | btnState
- ${false} | ${false} | ${true} | ${'disabled'}
- ${true} | ${false} | ${false} | ${'enabled'}
- ${true} | ${true} | ${false} | ${'enabled'}
- ${false} | ${true} | ${false} | ${'enabled'}
- `(
- 'is $btnState when hasUnsavedChanges:$hasUnsavedChanges and isNewCiConfigfile:$isNewCiConfigFile',
- ({ hasUnsavedChanges, isNewCiConfigFile, isDisabled }) => {
- createComponent({ props: { hasUnsavedChanges, isNewCiConfigFile } });
-
- if (isDisabled) {
- expect(findSubmitBtn().attributes('disabled')).toBe('true');
- } else {
- expect(findSubmitBtn().attributes('disabled')).toBeUndefined();
- }
- },
- );
- });
-
- describe('when user inputs values', () => {
- const anotherMessage = 'Another commit message';
- const anotherBranch = 'my-branch';
-
- beforeEach(() => {
- createComponent({}, mount);
-
- findCommitTextarea().setValue(anotherMessage);
- findBranchInput().setValue(anotherBranch);
- });
-
- it('shows a new MR checkbox', () => {
- expect(findNewMrCheckbox().exists()).toBe(true);
- });
-
- it('emits an event with values', async () => {
- await findNewMrCheckbox().setChecked();
- await findSubmitBtn().trigger('click');
-
- expect(wrapper.emitted('submit')[0]).toEqual([
- {
- message: anotherMessage,
- sourceBranch: anotherBranch,
- openMergeRequest: true,
- },
- ]);
- });
-
- it('when the commit message is empty, submit button is disabled', async () => {
- await findCommitTextarea().setValue('');
-
- expect(findSubmitBtn().attributes('disabled')).toBe('disabled');
- });
- });
-
- describe('when scrollToCommitForm becomes true', () => {
- beforeEach(async () => {
- createComponent();
- wrapper.setProps({ scrollToCommitForm: true });
- await nextTick();
- });
-
- it('scrolls into view', () => {
- expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth' });
- });
-
- it('emits "scrolled-to-commit-form"', () => {
- expect(wrapper.emitted()['scrolled-to-commit-form']).toHaveLength(1);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js
deleted file mode 100644
index 744b0378a75..00000000000
--- a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js
+++ /dev/null
@@ -1,287 +0,0 @@
-import VueApollo from 'vue-apollo';
-import { GlFormTextarea, GlFormInput, GlLoadingIcon } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
-import CommitSection from '~/pipeline_editor/components/commit/commit_section.vue';
-import {
- COMMIT_ACTION_CREATE,
- COMMIT_ACTION_UPDATE,
- COMMIT_SUCCESS,
- COMMIT_SUCCESS_WITH_REDIRECT,
-} from '~/pipeline_editor/constants';
-import { resolvers } from '~/pipeline_editor/graphql/resolvers';
-import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql';
-import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql';
-import updatePipelineEtag from '~/pipeline_editor/graphql/mutations/client/update_pipeline_etag.mutation.graphql';
-
-import {
- mockCiConfigPath,
- mockCiYml,
- mockCommitCreateResponse,
- mockCommitCreateResponseNewEtag,
- mockCommitSha,
- mockCommitMessage,
- mockDefaultBranch,
- mockProjectFullPath,
-} from '../../mock_data';
-
-const mockVariables = {
- action: COMMIT_ACTION_UPDATE,
- projectPath: mockProjectFullPath,
- startBranch: mockDefaultBranch,
- message: mockCommitMessage,
- filePath: mockCiConfigPath,
- content: mockCiYml,
- lastCommitId: mockCommitSha,
-};
-
-const mockProvide = {
- ciConfigPath: mockCiConfigPath,
- projectFullPath: mockProjectFullPath,
-};
-
-describe('Pipeline Editor | Commit section', () => {
- let wrapper;
- let mockApollo;
- const mockMutateCommitData = jest.fn();
-
- const defaultProps = {
- ciFileContent: mockCiYml,
- commitSha: mockCommitSha,
- hasUnsavedChanges: true,
- isNewCiConfigFile: false,
- };
-
- const createComponent = ({ apolloConfig = {}, props = {}, options = {}, provide = {} } = {}) => {
- wrapper = mount(CommitSection, {
- propsData: { ...defaultProps, ...props },
- provide: { ...mockProvide, ...provide },
- data() {
- return {
- currentBranch: mockDefaultBranch,
- };
- },
- attachTo: document.body,
- ...apolloConfig,
- ...options,
- });
- };
-
- const createComponentWithApollo = (options) => {
- const handlers = [[commitCreate, mockMutateCommitData]];
- Vue.use(VueApollo);
- mockApollo = createMockApollo(handlers, resolvers);
-
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getCurrentBranch,
- data: {
- workBranches: {
- __typename: 'BranchList',
- current: {
- __typename: 'WorkBranch',
- name: mockDefaultBranch,
- },
- },
- },
- });
-
- const apolloConfig = {
- apolloProvider: mockApollo,
- };
-
- createComponent({ ...options, apolloConfig });
- };
-
- const findCommitForm = () => wrapper.findComponent(CommitForm);
- const findCommitBtnLoadingIcon = () =>
- wrapper.find('[type="submit"]').findComponent(GlLoadingIcon);
-
- const submitCommit = async ({
- message = mockCommitMessage,
- branch = mockDefaultBranch,
- openMergeRequest = false,
- } = {}) => {
- await findCommitForm().findComponent(GlFormTextarea).setValue(message);
- await findCommitForm().findComponent(GlFormInput).setValue(branch);
- if (openMergeRequest) {
- await findCommitForm().find('[data-testid="new-mr-checkbox"]').setChecked(openMergeRequest);
- }
- await findCommitForm().find('[type="submit"]').trigger('click');
- await waitForPromises();
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when the user commits a new file', () => {
- beforeEach(async () => {
- mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
- createComponentWithApollo({ props: { isNewCiConfigFile: true } });
- await submitCommit();
- });
-
- it('calls the mutation with the CREATE action', () => {
- expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
- expect(mockMutateCommitData).toHaveBeenCalledWith({
- ...mockVariables,
- action: COMMIT_ACTION_CREATE,
- branch: mockDefaultBranch,
- });
- });
- });
-
- describe('when the user commits an update to an existing file', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await submitCommit();
- });
-
- it('calls the mutation with the UPDATE action', () => {
- expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
- expect(mockMutateCommitData).toHaveBeenCalledWith({
- ...mockVariables,
- action: COMMIT_ACTION_UPDATE,
- branch: mockDefaultBranch,
- });
- });
- });
-
- describe('when the user commits changes to the current branch', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await submitCommit();
- });
-
- it('calls the mutation with the current branch', () => {
- expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
- expect(mockMutateCommitData).toHaveBeenCalledWith({
- ...mockVariables,
- branch: mockDefaultBranch,
- });
- });
-
- it('emits an event to communicate the commit was successful', () => {
- expect(wrapper.emitted('commit')).toHaveLength(1);
- expect(wrapper.emitted('commit')[0]).toEqual([{ type: COMMIT_SUCCESS }]);
- });
-
- it('emits an event to refetch the commit sha', () => {
- expect(wrapper.emitted('updateCommitSha')).toHaveLength(1);
- });
-
- it('shows no saving state', () => {
- expect(findCommitBtnLoadingIcon().exists()).toBe(false);
- });
-
- it('a second commit submits the latest sha, keeping the form updated', async () => {
- await submitCommit();
-
- expect(mockMutateCommitData).toHaveBeenCalledTimes(2);
- expect(mockMutateCommitData).toHaveBeenCalledWith({
- ...mockVariables,
- branch: mockDefaultBranch,
- });
- });
- });
-
- describe('when the user commits changes to a new branch', () => {
- const newBranch = 'new-branch';
-
- beforeEach(async () => {
- createComponentWithApollo();
- await submitCommit({
- branch: newBranch,
- });
- });
-
- it('calls the mutation with the new branch', () => {
- expect(mockMutateCommitData).toHaveBeenCalledWith({
- ...mockVariables,
- branch: newBranch,
- });
- });
-
- it('does not emit an event to refetch the commit sha', () => {
- expect(wrapper.emitted('updateCommitSha')).toBeUndefined();
- });
- });
-
- describe('when the user commits changes to open a new merge request', () => {
- const newBranch = 'new-branch';
-
- beforeEach(async () => {
- mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
- createComponentWithApollo();
- mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
- await submitCommit({
- branch: newBranch,
- openMergeRequest: true,
- });
- });
-
- it('emits a commit event with the right type, sourceBranch and targetBranch', () => {
- expect(wrapper.emitted('commit')).toHaveLength(1);
- expect(wrapper.emitted('commit')[0]).toMatchObject([
- {
- type: COMMIT_SUCCESS_WITH_REDIRECT,
- params: { sourceBranch: newBranch, targetBranch: mockDefaultBranch },
- },
- ]);
- });
- });
-
- describe('when the commit is ocurring', () => {
- beforeEach(() => {
- createComponentWithApollo();
- });
-
- it('shows a saving state', async () => {
- mockMutateCommitData.mockImplementationOnce(() => {
- expect(findCommitBtnLoadingIcon().exists()).toBe(true);
- return Promise.resolve();
- });
-
- await submitCommit({
- message: mockCommitMessage,
- branch: mockDefaultBranch,
- openMergeRequest: false,
- });
- });
- });
-
- describe('when the commit returns a different etag path', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- jest.spyOn(wrapper.vm.$apollo, 'mutate');
- mockMutateCommitData.mockResolvedValue(mockCommitCreateResponseNewEtag);
- await submitCommit();
- });
-
- it('calls the client mutation to update the etag', () => {
- // 1:Commit submission, 2:etag update, 3:currentBranch update, 4:lastCommit update
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(4);
- expect(wrapper.vm.$apollo.mutate).toHaveBeenNthCalledWith(2, {
- mutation: updatePipelineEtag,
- variables: {
- pipelineEtag: mockCommitCreateResponseNewEtag.data.commitCreate.commitPipelinePath,
- },
- });
- });
- });
-
- it('sets listeners on commit form', () => {
- const handler = jest.fn();
- createComponent({ options: { listeners: { event: handler } } });
- findCommitForm().vm.$emit('event');
- expect(handler).toHaveBeenCalled();
- });
-
- it('passes down scroll-to-commit-form prop to commit form', () => {
- createComponent({ props: { 'scroll-to-commit-form': true } });
- expect(findCommitForm().props('scrollToCommitForm')).toBe(true);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js b/spec/frontend/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js
deleted file mode 100644
index 7e1e5004d91..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { getByRole } from '@testing-library/dom';
-import { mount } from '@vue/test-utils';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import FirstPipelineCard from '~/pipeline_editor/components/drawer/cards/first_pipeline_card.vue';
-import { pipelineEditorTrackingOptions } from '~/pipeline_editor/constants';
-
-describe('First pipeline card', () => {
- let wrapper;
- let trackingSpy;
-
- const createComponent = () => {
- wrapper = mount(FirstPipelineCard);
- };
-
- const getLinkByName = (name) => getByRole(wrapper.element, 'link', { name });
- const findRunnersLink = () => getLinkByName(/make sure your instance has runners available/i);
- const findInstructionsList = () => wrapper.find('ol');
- const findAllInstructions = () => findInstructionsList().findAll('li');
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the title', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
- });
-
- it('renders the content', () => {
- expect(findInstructionsList().exists()).toBe(true);
- expect(findAllInstructions()).toHaveLength(3);
- });
-
- it('renders the link', () => {
- expect(findRunnersLink().href).toBe(wrapper.vm.$options.RUNNER_HELP_URL);
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- createComponent();
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks runners help page click', async () => {
- const { label } = pipelineEditorTrackingOptions;
- const { runners } = pipelineEditorTrackingOptions.actions.helpDrawerLinks;
-
- await findRunnersLink().click();
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, runners, { label });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/cards/getting_started_card_spec.js b/spec/frontend/pipeline_editor/components/drawer/cards/getting_started_card_spec.js
deleted file mode 100644
index c592e959068..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/cards/getting_started_card_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import GettingStartedCard from '~/pipeline_editor/components/drawer/cards/getting_started_card.vue';
-
-describe('Getting started card', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(GettingStartedCard);
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the title', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
- });
-
- it('renders the content', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.firstParagraph);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js b/spec/frontend/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js
deleted file mode 100644
index 49177befe0e..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import { getByRole } from '@testing-library/dom';
-import { mount } from '@vue/test-utils';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import PipelineConfigReferenceCard from '~/pipeline_editor/components/drawer/cards/pipeline_config_reference_card.vue';
-import { pipelineEditorTrackingOptions } from '~/pipeline_editor/constants';
-
-describe('Pipeline config reference card', () => {
- let wrapper;
- let trackingSpy;
-
- const defaultProvide = {
- ciExamplesHelpPagePath: 'help/ci/examples/',
- ciHelpPagePath: 'help/ci/introduction',
- needsHelpPagePath: 'help/ci/yaml#needs',
- ymlHelpPagePath: 'help/ci/yaml',
- };
-
- const createComponent = () => {
- wrapper = mount(PipelineConfigReferenceCard, {
- provide: {
- ...defaultProvide,
- },
- });
- };
-
- const getLinkByName = (name) => getByRole(wrapper.element, 'link', { name });
- const findCiExamplesLink = () => getLinkByName(/CI\/CD examples and templates/i);
- const findCiIntroLink = () => getLinkByName(/GitLab CI\/CD concepts/i);
- const findNeedsLink = () => getLinkByName(/Needs keyword/i);
- const findYmlSyntaxLink = () => getLinkByName(/.gitlab-ci.yml syntax reference/i);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the title', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
- });
-
- it('renders the content', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.firstParagraph);
- });
-
- it('renders the links', () => {
- expect(findCiExamplesLink().href).toContain(defaultProvide.ciExamplesHelpPagePath);
- expect(findCiIntroLink().href).toContain(defaultProvide.ciHelpPagePath);
- expect(findNeedsLink().href).toContain(defaultProvide.needsHelpPagePath);
- expect(findYmlSyntaxLink().href).toContain(defaultProvide.ymlHelpPagePath);
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- createComponent();
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- const testTracker = async (element, expectedAction) => {
- const { label } = pipelineEditorTrackingOptions;
-
- await element.click();
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, expectedAction, {
- label,
- });
- };
-
- it('tracks help page links', async () => {
- const {
- CI_EXAMPLES_LINK,
- CI_HELP_LINK,
- CI_NEEDS_LINK,
- CI_YAML_LINK,
- } = pipelineEditorTrackingOptions.actions.helpDrawerLinks;
-
- testTracker(findCiExamplesLink(), CI_EXAMPLES_LINK);
- testTracker(findCiIntroLink(), CI_HELP_LINK);
- testTracker(findNeedsLink(), CI_NEEDS_LINK);
- testTracker(findYmlSyntaxLink(), CI_YAML_LINK);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js b/spec/frontend/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js
deleted file mode 100644
index bebd2484c1d..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import VisualizeAndLintCard from '~/pipeline_editor/components/drawer/cards/getting_started_card.vue';
-
-describe('Visual and Lint card', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(VisualizeAndLintCard);
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the title', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
- });
-
- it('renders the content', () => {
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.firstParagraph);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js b/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js
deleted file mode 100644
index 33b53bf6a56..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlDrawer } from '@gitlab/ui';
-import PipelineEditorDrawer from '~/pipeline_editor/components/drawer/pipeline_editor_drawer.vue';
-
-describe('Pipeline editor drawer', () => {
- let wrapper;
-
- const findDrawer = () => wrapper.findComponent(GlDrawer);
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineEditorDrawer);
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('emits close event when closing the drawer', () => {
- createComponent();
-
- expect(wrapper.emitted('close-drawer')).toBeUndefined();
-
- findDrawer().vm.$emit('close');
-
- expect(wrapper.emitted('close-drawer')).toHaveLength(1);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js b/spec/frontend/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js
deleted file mode 100644
index edd2b45569a..00000000000
--- a/spec/frontend/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import DemoJobPill from '~/pipeline_editor/components/drawer/ui/demo_job_pill.vue';
-
-describe('Demo job pill', () => {
- let wrapper;
- const jobName = 'my-build-job';
-
- const createComponent = () => {
- wrapper = shallowMount(DemoJobPill, {
- propsData: {
- jobName,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the jobName', () => {
- expect(wrapper.text()).toContain(jobName);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js b/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
deleted file mode 100644
index 7dd8a77d055..00000000000
--- a/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-
-import { EDITOR_READY_EVENT } from '~/editor/constants';
-import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
-import { mockLintResponse, mockCiConfigPath } from '../../mock_data';
-
-describe('Text editor component', () => {
- let wrapper;
-
- const MockSourceEditor = {
- template: '<div/>',
- props: ['value', 'fileName', 'editorOptions'],
- mounted() {
- this.$emit(EDITOR_READY_EVENT);
- },
- };
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(CiConfigMergedPreview, {
- propsData: {
- ciConfigData: mockLintResponse,
- ...props,
- },
- provide: {
- ciConfigPath: mockCiConfigPath,
- },
- stubs: {
- SourceEditor: MockSourceEditor,
- },
- });
- };
-
- const findIcon = () => wrapper.findComponent(GlIcon);
- const findEditor = () => wrapper.findComponent(MockSourceEditor);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when status is valid', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows an information message that the section is not editable', () => {
- expect(findIcon().exists()).toBe(true);
- expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.viewOnlyMessage);
- });
-
- it('contains an editor', () => {
- expect(findEditor().exists()).toBe(true);
- });
-
- it('editor contains the value provided', () => {
- expect(findEditor().props('value')).toBe(mockLintResponse.mergedYaml);
- });
-
- it('editor is configured for the CI config path', () => {
- expect(findEditor().props('fileName')).toBe(mockCiConfigPath);
- });
-
- it('editor is readonly', () => {
- expect(findEditor().props('editorOptions')).toMatchObject({
- readOnly: true,
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/editor/ci_editor_header_spec.js b/spec/frontend/pipeline_editor/components/editor/ci_editor_header_spec.js
deleted file mode 100644
index 930f08ef545..00000000000
--- a/spec/frontend/pipeline_editor/components/editor/ci_editor_header_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import CiEditorHeader from '~/pipeline_editor/components/editor/ci_editor_header.vue';
-import {
- pipelineEditorTrackingOptions,
- TEMPLATE_REPOSITORY_URL,
-} from '~/pipeline_editor/constants';
-
-describe('CI Editor Header', () => {
- let wrapper;
- let trackingSpy = null;
-
- const createComponent = ({ showDrawer = false } = {}) => {
- wrapper = extendedWrapper(
- shallowMount(CiEditorHeader, {
- propsData: {
- showDrawer,
- },
- }),
- );
- };
-
- const findLinkBtn = () => wrapper.findByTestId('template-repo-link');
- const findHelpBtn = () => wrapper.findByTestId('drawer-toggle');
-
- afterEach(() => {
- wrapper.destroy();
- unmockTracking();
- });
-
- const testTracker = async (element, expectedAction) => {
- const { label } = pipelineEditorTrackingOptions;
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- await element.vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, expectedAction, {
- label,
- });
- };
-
- describe('link button', () => {
- beforeEach(() => {
- createComponent();
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- it('finds the browse template button', () => {
- expect(findLinkBtn().exists()).toBe(true);
- });
-
- it('contains the link to the template repo', () => {
- expect(findLinkBtn().attributes('href')).toBe(TEMPLATE_REPOSITORY_URL);
- });
-
- it('has the external-link icon', () => {
- expect(findLinkBtn().props('icon')).toBe('external-link');
- });
-
- it('tracks the click on the browse button', async () => {
- const { browseTemplates } = pipelineEditorTrackingOptions.actions;
-
- testTracker(findLinkBtn(), browseTemplates);
- });
- });
-
- describe('help button', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('finds the help button', () => {
- expect(findHelpBtn().exists()).toBe(true);
- });
-
- it('has the information-o icon', () => {
- expect(findHelpBtn().props('icon')).toBe('information-o');
- });
-
- describe('when pipeline editor drawer is closed', () => {
- beforeEach(() => {
- createComponent({ showDrawer: false });
- });
-
- it('emits open drawer event when clicked', () => {
- expect(wrapper.emitted('open-drawer')).toBeUndefined();
-
- findHelpBtn().vm.$emit('click');
-
- expect(wrapper.emitted('open-drawer')).toHaveLength(1);
- });
-
- it('tracks open help drawer action', async () => {
- const { actions } = pipelineEditorTrackingOptions;
-
- testTracker(findHelpBtn(), actions.openHelpDrawer);
- });
- });
-
- describe('when pipeline editor drawer is open', () => {
- beforeEach(() => {
- createComponent({ showDrawer: true });
- });
-
- it('emits close drawer event when clicked', () => {
- expect(wrapper.emitted('close-drawer')).toBeUndefined();
-
- findHelpBtn().vm.$emit('click');
-
- expect(wrapper.emitted('close-drawer')).toHaveLength(1);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/editor/text_editor_spec.js b/spec/frontend/pipeline_editor/components/editor/text_editor_spec.js
deleted file mode 100644
index 6cdf9a93d55..00000000000
--- a/spec/frontend/pipeline_editor/components/editor/text_editor_spec.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-
-import { EDITOR_READY_EVENT } from '~/editor/constants';
-import { SOURCE_EDITOR_DEBOUNCE } from '~/pipeline_editor/constants';
-import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue';
-import {
- mockCiConfigPath,
- mockCiYml,
- mockCommitSha,
- mockProjectPath,
- mockProjectNamespace,
- mockDefaultBranch,
-} from '../../mock_data';
-
-describe('Pipeline Editor | Text editor component', () => {
- let wrapper;
-
- let editorReadyListener;
- let mockUse;
- let mockRegisterCiSchema;
- let mockEditorInstance;
- let editorInstanceDetail;
-
- const MockSourceEditor = {
- template: '<div/>',
- props: ['value', 'fileName', 'editorOptions', 'debounceValue'],
- };
-
- const createComponent = (glFeatures = {}, mountFn = shallowMount) => {
- wrapper = mountFn(TextEditor, {
- provide: {
- projectPath: mockProjectPath,
- projectNamespace: mockProjectNamespace,
- ciConfigPath: mockCiConfigPath,
- defaultBranch: mockDefaultBranch,
- glFeatures,
- },
- propsData: {
- commitSha: mockCommitSha,
- },
- attrs: {
- value: mockCiYml,
- },
- listeners: {
- [EDITOR_READY_EVENT]: editorReadyListener,
- },
- stubs: {
- SourceEditor: MockSourceEditor,
- },
- });
- };
-
- const findEditor = () => wrapper.findComponent(MockSourceEditor);
-
- beforeEach(() => {
- editorReadyListener = jest.fn();
- mockUse = jest.fn();
- mockRegisterCiSchema = jest.fn();
- mockEditorInstance = {
- use: mockUse,
- registerCiSchema: mockRegisterCiSchema,
- };
- editorInstanceDetail = {
- detail: {
- instance: mockEditorInstance,
- },
- };
- });
-
- afterEach(() => {
- wrapper.destroy();
-
- mockUse.mockClear();
- mockRegisterCiSchema.mockClear();
- });
-
- describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('contains an editor', () => {
- expect(findEditor().exists()).toBe(true);
- });
-
- it('editor contains the value provided', () => {
- expect(findEditor().props('value')).toBe(mockCiYml);
- });
-
- it('editor is configured for the CI config path', () => {
- expect(findEditor().props('fileName')).toBe(mockCiConfigPath);
- });
-
- it('passes down editor configs options', () => {
- expect(findEditor().props('editorOptions')).toEqual({ quickSuggestions: true });
- });
-
- it('passes down editor debounce value', () => {
- expect(findEditor().props('debounceValue')).toBe(SOURCE_EDITOR_DEBOUNCE);
- });
-
- it('bubbles up events', () => {
- findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
-
- expect(editorReadyListener).toHaveBeenCalled();
- });
- });
-
- describe('CI schema', () => {
- describe('when `schema_linting` feature flag is on', () => {
- beforeEach(() => {
- createComponent({ schemaLinting: true });
- findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
- });
-
- it('configures editor with syntax highlight', () => {
- expect(mockUse).toHaveBeenCalledTimes(1);
- expect(mockRegisterCiSchema).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when `schema_linting` feature flag is off', () => {
- beforeEach(() => {
- createComponent();
- findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
- });
-
- it('does not call the register CI schema function', () => {
- expect(mockUse).not.toHaveBeenCalled();
- expect(mockRegisterCiSchema).not.toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
deleted file mode 100644
index f0347ad19ac..00000000000
--- a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
+++ /dev/null
@@ -1,432 +0,0 @@
-import {
- GlDropdown,
- GlDropdownItem,
- GlInfiniteScroll,
- GlLoadingIcon,
- GlSearchBoxByType,
-} from '@gitlab/ui';
-import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue';
-import { DEFAULT_FAILURE } from '~/pipeline_editor/constants';
-import getAvailableBranchesQuery from '~/pipeline_editor/graphql/queries/available_branches.query.graphql';
-import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql';
-import getLastCommitBranch from '~/pipeline_editor/graphql/queries/client/last_commit_branch.query.graphql';
-import { resolvers } from '~/pipeline_editor/graphql/resolvers';
-
-import {
- mockBranchPaginationLimit,
- mockDefaultBranch,
- mockEmptySearchBranches,
- mockProjectBranches,
- mockProjectFullPath,
- mockSearchBranches,
- mockTotalBranches,
- mockTotalBranchResults,
- mockTotalSearchResults,
-} from '../../mock_data';
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-describe('Pipeline editor branch switcher', () => {
- let wrapper;
- let mockApollo;
- let mockAvailableBranchQuery;
-
- const createComponent = ({
- currentBranch = mockDefaultBranch,
- availableBranches = ['main'],
- isQueryLoading = false,
- mountFn = shallowMount,
- options = {},
- props = {},
- } = {}) => {
- wrapper = mountFn(BranchSwitcher, {
- propsData: {
- ...props,
- paginationLimit: mockBranchPaginationLimit,
- },
- provide: {
- projectFullPath: mockProjectFullPath,
- totalBranches: mockTotalBranches,
- },
- mocks: {
- $apollo: {
- queries: {
- availableBranches: {
- loading: isQueryLoading,
- },
- },
- },
- },
- data() {
- return {
- availableBranches,
- currentBranch,
- };
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = ({
- mountFn = shallowMount,
- props = {},
- availableBranches = ['main'],
- } = {}) => {
- const handlers = [[getAvailableBranchesQuery, mockAvailableBranchQuery]];
- mockApollo = createMockApollo(handlers, resolvers);
-
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getCurrentBranch,
- data: {
- workBranches: {
- __typename: 'BranchList',
- current: {
- __typename: 'WorkBranch',
- name: mockDefaultBranch,
- },
- },
- },
- });
-
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getLastCommitBranch,
- data: {
- workBranches: {
- __typename: 'BranchList',
- lastCommit: {
- __typename: 'WorkBranch',
- name: '',
- },
- },
- },
- });
-
- createComponent({
- mountFn,
- props,
- availableBranches,
- options: {
- localVue,
- apolloProvider: mockApollo,
- mocks: {},
- },
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findInfiniteScroll = () => wrapper.findComponent(GlInfiniteScroll);
- const defaultBranchInDropdown = () => findDropdownItems().at(0);
-
- const setAvailableBranchesMock = (availableBranches) => {
- mockAvailableBranchQuery.mockResolvedValue(availableBranches);
- };
-
- beforeEach(() => {
- mockAvailableBranchQuery = jest.fn();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const testErrorHandling = () => {
- expect(wrapper.emitted('showError')).toBeDefined();
- expect(wrapper.emitted('showError')[0]).toEqual([
- {
- reasons: [wrapper.vm.$options.i18n.fetchError],
- type: DEFAULT_FAILURE,
- },
- ]);
- };
-
- describe('when querying for the first time', () => {
- beforeEach(() => {
- createComponentWithApollo({ availableBranches: [] });
- });
-
- it('disables the dropdown', () => {
- expect(findDropdown().props('disabled')).toBe(true);
- });
- });
-
- describe('after querying', () => {
- beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
- });
-
- it('renders search box', () => {
- expect(findSearchBox().exists()).toBe(true);
- });
-
- it('renders list of branches', () => {
- expect(findDropdown().exists()).toBe(true);
- expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
- });
-
- it('renders current branch with a check mark', () => {
- expect(defaultBranchInDropdown().text()).toBe(mockDefaultBranch);
- expect(defaultBranchInDropdown().props('isChecked')).toBe(true);
- });
-
- it('does not render check mark for other branches', () => {
- const nonDefaultBranch = findDropdownItems().at(1);
-
- expect(nonDefaultBranch.text()).not.toBe(mockDefaultBranch);
- expect(nonDefaultBranch.props('isChecked')).toBe(false);
- });
- });
-
- describe('on fetch error', () => {
- beforeEach(async () => {
- setAvailableBranchesMock(new Error());
- createComponentWithApollo({ availableBranches: [] });
- await waitForPromises();
- });
-
- it('does not render dropdown', () => {
- expect(findDropdown().props('disabled')).toBe(true);
- });
-
- it('shows an error message', () => {
- testErrorHandling();
- });
- });
-
- describe('when switching branches', () => {
- beforeEach(async () => {
- jest.spyOn(window.history, 'pushState').mockImplementation(() => {});
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
- });
-
- it('updates session history when selecting a different branch', async () => {
- const branch = findDropdownItems().at(1);
- branch.vm.$emit('click');
- await waitForPromises();
-
- expect(window.history.pushState).toHaveBeenCalled();
- expect(window.history.pushState.mock.calls[0][2]).toContain(`?branch_name=${branch.text()}`);
- });
-
- it('does not update session history when selecting current branch', async () => {
- const branch = findDropdownItems().at(0);
- branch.vm.$emit('click');
- await waitForPromises();
-
- expect(branch.text()).toBe(mockDefaultBranch);
- expect(window.history.pushState).not.toHaveBeenCalled();
- });
-
- it('emits the refetchContent event when selecting a different branch', async () => {
- const branch = findDropdownItems().at(1);
-
- expect(branch.text()).not.toBe(mockDefaultBranch);
- expect(wrapper.emitted('refetchContent')).toBeUndefined();
-
- branch.vm.$emit('click');
- await waitForPromises();
-
- expect(wrapper.emitted('refetchContent')).toBeDefined();
- expect(wrapper.emitted('refetchContent')).toHaveLength(1);
- });
-
- it('does not emit the refetchContent event when selecting the current branch', async () => {
- const branch = findDropdownItems().at(0);
-
- expect(branch.text()).toBe(mockDefaultBranch);
- expect(wrapper.emitted('refetchContent')).toBeUndefined();
-
- branch.vm.$emit('click');
- await waitForPromises();
-
- expect(wrapper.emitted('refetchContent')).toBeUndefined();
- });
-
- describe('with unsaved changes', () => {
- beforeEach(async () => {
- createComponentWithApollo({ mountFn: mount, props: { hasUnsavedChanges: true } });
- await waitForPromises();
- });
-
- it('emits `select-branch` event and does not switch branch', async () => {
- expect(wrapper.emitted('select-branch')).toBeUndefined();
-
- const branch = findDropdownItems().at(1);
- await branch.vm.$emit('click');
-
- expect(wrapper.emitted('select-branch')).toEqual([[branch.text()]]);
- expect(wrapper.emitted('refetchContent')).toBeUndefined();
- });
- });
- });
-
- describe('when searching', () => {
- beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
- });
-
- afterEach(() => {
- mockAvailableBranchQuery.mockClear();
- });
-
- it('shows error message on fetch error', async () => {
- mockAvailableBranchQuery.mockResolvedValue(new Error());
-
- findSearchBox().vm.$emit('input', 'te');
- await waitForPromises();
-
- testErrorHandling();
- });
-
- describe('with a search term', () => {
- beforeEach(async () => {
- mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches);
- });
-
- it('calls query with correct variables', async () => {
- findSearchBox().vm.$emit('input', 'te');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
- limit: mockTotalBranches, // fetch all branches
- offset: 0,
- projectFullPath: mockProjectFullPath,
- searchPattern: '*te*',
- });
- });
-
- it('fetches new list of branches', async () => {
- expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
-
- findSearchBox().vm.$emit('input', 'te');
- await waitForPromises();
-
- expect(findDropdownItems()).toHaveLength(mockTotalSearchResults);
- });
-
- it('does not hide dropdown when search result is empty', async () => {
- mockAvailableBranchQuery.mockResolvedValue(mockEmptySearchBranches);
- findSearchBox().vm.$emit('input', 'aaaaa');
- await waitForPromises();
-
- expect(findDropdown().exists()).toBe(true);
- expect(findDropdownItems()).toHaveLength(0);
- });
- });
-
- describe('without a search term', () => {
- beforeEach(async () => {
- mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches);
- findSearchBox().vm.$emit('input', 'te');
- await waitForPromises();
-
- mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
- });
-
- it('calls query with correct variables', async () => {
- findSearchBox().vm.$emit('input', '');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
- limit: mockBranchPaginationLimit, // only fetch first n branches first
- offset: 0,
- projectFullPath: mockProjectFullPath,
- searchPattern: '*',
- });
- });
-
- it('fetches new list of branches', async () => {
- expect(findDropdownItems()).toHaveLength(mockTotalSearchResults);
-
- findSearchBox().vm.$emit('input', '');
- await waitForPromises();
-
- expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
- });
- });
- });
-
- describe('loading icon', () => {
- it.each`
- isQueryLoading | isRendered
- ${true} | ${true}
- ${false} | ${false}
- `('checks if query is loading before rendering', ({ isQueryLoading, isRendered }) => {
- createComponent({ isQueryLoading, mountFn: mount });
-
- expect(findLoadingIcon().exists()).toBe(isRendered);
- });
- });
-
- describe('when scrolling to the bottom of the list', () => {
- beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo();
- await waitForPromises();
- });
-
- afterEach(() => {
- mockAvailableBranchQuery.mockClear();
- });
-
- describe('when search term is empty', () => {
- it('fetches more branches', async () => {
- expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1);
-
- findInfiniteScroll().vm.$emit('bottomReached');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2);
- });
-
- it('calls the query with the correct variables', async () => {
- findInfiniteScroll().vm.$emit('bottomReached');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
- limit: mockBranchPaginationLimit,
- offset: mockBranchPaginationLimit, // offset changed
- projectFullPath: mockProjectFullPath,
- searchPattern: '*',
- });
- });
-
- it('shows error message on fetch error', async () => {
- mockAvailableBranchQuery.mockResolvedValue(new Error());
-
- findInfiniteScroll().vm.$emit('bottomReached');
- await waitForPromises();
-
- testErrorHandling();
- });
- });
-
- describe('when search term exists', () => {
- it('does not fetch more branches', async () => {
- findSearchBox().vm.$emit('input', 'te');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2);
- mockAvailableBranchQuery.mockClear();
-
- findInfiniteScroll().vm.$emit('bottomReached');
- await waitForPromises();
-
- expect(mockAvailableBranchQuery).not.toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
deleted file mode 100644
index d503aff40b8..00000000000
--- a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue';
-import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue';
-import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue';
-import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-import {
- EDITOR_APP_STATUS_EMPTY,
- EDITOR_APP_STATUS_LOADING,
- EDITOR_APP_STATUS_VALID,
-} from '~/pipeline_editor/constants';
-
-Vue.use(VueApollo);
-
-describe('Pipeline editor file nav', () => {
- let wrapper;
-
- const mockApollo = createMockApollo();
-
- const createComponent = ({
- appStatus = EDITOR_APP_STATUS_VALID,
- isNewCiConfigFile = false,
- } = {}) => {
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getAppStatus,
- data: {
- app: {
- __typename: 'PipelineEditorApp',
- status: appStatus,
- },
- },
- });
-
- wrapper = extendedWrapper(
- shallowMount(PipelineEditorFileNav, {
- apolloProvider: mockApollo,
- propsData: {
- isNewCiConfigFile,
- },
- }),
- );
- };
-
- const findBranchSwitcher = () => wrapper.findComponent(BranchSwitcher);
- const findFileTreeBtn = () => wrapper.findByTestId('file-tree-toggle');
- const findPopoverContainer = () => wrapper.findComponent(FileTreePopover);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the branch switcher', () => {
- expect(findBranchSwitcher().exists()).toBe(true);
- });
- });
-
- describe('file tree', () => {
- describe('when editor is in the empty state', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_EMPTY, isNewCiConfigFile: false });
- });
-
- it('does not render the file tree button', () => {
- expect(findFileTreeBtn().exists()).toBe(false);
- });
-
- it('does not render the file tree popover', () => {
- expect(findPopoverContainer().exists()).toBe(false);
- });
- });
-
- describe('when user is about to create their config file for the first time', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_VALID, isNewCiConfigFile: true });
- });
-
- it('does not render the file tree button', () => {
- expect(findFileTreeBtn().exists()).toBe(false);
- });
-
- it('does not render the file tree popover', () => {
- expect(findPopoverContainer().exists()).toBe(false);
- });
- });
-
- describe('when app is in a global loading state', () => {
- it('renders the file tree button with a loading icon', () => {
- createComponent({ appStatus: EDITOR_APP_STATUS_LOADING, isNewCiConfigFile: false });
-
- expect(findFileTreeBtn().exists()).toBe(true);
- expect(findFileTreeBtn().attributes('loading')).toBe('true');
- });
- });
-
- describe('when editor has a non-empty config file open', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_VALID, isNewCiConfigFile: false });
- });
-
- it('renders the file tree button', () => {
- expect(findFileTreeBtn().exists()).toBe(true);
- expect(findFileTreeBtn().props('icon')).toBe('file-tree');
- });
-
- it('renders the file tree popover', () => {
- expect(findPopoverContainer().exists()).toBe(true);
- });
-
- it('file tree button emits toggle-file-tree event', () => {
- expect(wrapper.emitted('toggle-file-tree')).toBe(undefined);
-
- findFileTreeBtn().vm.$emit('click');
-
- expect(wrapper.emitted('toggle-file-tree')).toHaveLength(1);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
deleted file mode 100644
index f79074f1e0f..00000000000
--- a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import { nextTick } from 'vue';
-import { shallowMount } from '@vue/test-utils';
-import { GlAlert } from '@gitlab/ui';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { createMockDirective } from 'helpers/vue_mock_directive';
-import PipelineEditorFileTreeContainer from '~/pipeline_editor/components/file_tree/container.vue';
-import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue';
-import { FILE_TREE_TIP_DISMISSED_KEY } from '~/pipeline_editor/constants';
-import { mockCiConfigPath, mockIncludes, mockIncludesHelpPagePath } from '../../mock_data';
-
-describe('Pipeline editor file nav', () => {
- let wrapper;
-
- const createComponent = ({ includes = mockIncludes, stubs } = {}) => {
- wrapper = extendedWrapper(
- shallowMount(PipelineEditorFileTreeContainer, {
- provide: {
- ciConfigPath: mockCiConfigPath,
- includesHelpPagePath: mockIncludesHelpPagePath,
- },
- propsData: {
- includes,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- stubs,
- }),
- );
- };
-
- const findTip = () => wrapper.findComponent(GlAlert);
- const findCurrentConfigFilename = () => wrapper.findByTestId('current-config-filename');
- const fileTreeItems = () => wrapper.findAllComponents(PipelineEditorFileTreeItem);
-
- afterEach(() => {
- localStorage.clear();
- wrapper.destroy();
- });
-
- describe('template', () => {
- beforeEach(() => {
- createComponent({ stubs: { GlAlert } });
- });
-
- it('renders config file as a file item', () => {
- expect(findCurrentConfigFilename().text()).toBe(mockCiConfigPath);
- });
- });
-
- describe('when includes list is empty', () => {
- describe('when dismiss state is not saved in local storage', () => {
- beforeEach(() => {
- createComponent({
- includes: [],
- stubs: { GlAlert },
- });
- });
-
- it('does not render filenames', () => {
- expect(fileTreeItems().exists()).toBe(false);
- });
-
- it('renders alert tip', async () => {
- expect(findTip().exists()).toBe(true);
- });
-
- it('renders learn more link', async () => {
- expect(findTip().props('secondaryButtonLink')).toBe(mockIncludesHelpPagePath);
- });
-
- it('can dismiss the tip', async () => {
- expect(findTip().exists()).toBe(true);
-
- findTip().vm.$emit('dismiss');
- await nextTick();
-
- expect(findTip().exists()).toBe(false);
- });
- });
-
- describe('when dismiss state is saved in local storage', () => {
- beforeEach(() => {
- localStorage.setItem(FILE_TREE_TIP_DISMISSED_KEY, 'true');
- createComponent({
- includes: [],
- stubs: { GlAlert },
- });
- });
-
- it('does not render alert tip', async () => {
- expect(findTip().exists()).toBe(false);
- });
- });
-
- describe('when component receives new props with includes files', () => {
- beforeEach(() => {
- createComponent({ includes: [] });
- });
-
- it('hides tip and renders list of files', async () => {
- expect(findTip().exists()).toBe(true);
- expect(fileTreeItems()).toHaveLength(0);
-
- await wrapper.setProps({ includes: mockIncludes });
-
- expect(findTip().exists()).toBe(false);
- expect(fileTreeItems()).toHaveLength(mockIncludes.length);
- });
- });
- });
-
- describe('when there are includes files', () => {
- beforeEach(() => {
- createComponent({ stubs: { GlAlert } });
- });
-
- it('does not render alert tip', () => {
- expect(findTip().exists()).toBe(false);
- });
-
- it('renders the list of files', () => {
- expect(fileTreeItems()).toHaveLength(mockIncludes.length);
- });
-
- describe('when component receives new props with empty includes', () => {
- it('shows tip and does not render list of files', async () => {
- expect(findTip().exists()).toBe(false);
- expect(fileTreeItems()).toHaveLength(mockIncludes.length);
-
- await wrapper.setProps({ includes: [] });
-
- expect(findTip().exists()).toBe(true);
- expect(fileTreeItems()).toHaveLength(0);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js b/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js
deleted file mode 100644
index f12ac14c6be..00000000000
--- a/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import FileIcon from '~/vue_shared/components/file_icon.vue';
-import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue';
-import { mockIncludesWithBlob, mockDefaultIncludes } from '../../mock_data';
-
-describe('Pipeline editor file nav', () => {
- let wrapper;
-
- const createComponent = ({ file = mockDefaultIncludes } = {}) => {
- wrapper = shallowMount(PipelineEditorFileTreeItem, {
- propsData: {
- file,
- },
- });
- };
-
- const fileIcon = () => wrapper.findComponent(FileIcon);
- const link = () => wrapper.findComponent(GlLink);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders file icon', () => {
- expect(fileIcon().exists()).toBe(true);
- });
-
- it('renders file name', () => {
- expect(wrapper.text()).toBe(mockDefaultIncludes.location);
- });
-
- it('links to raw path by default', () => {
- expect(link().attributes('href')).toBe(mockDefaultIncludes.raw);
- });
- });
-
- describe('when file has blob link', () => {
- beforeEach(() => {
- createComponent({ file: mockIncludesWithBlob });
- });
-
- it('links to blob path', () => {
- expect(link().attributes('href')).toBe(mockIncludesWithBlob.blob);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js
deleted file mode 100644
index e1dc08b637f..00000000000
--- a/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_editor_header.vue';
-import PipelineStatus from '~/pipeline_editor/components/header/pipeline_status.vue';
-import ValidationSegment from '~/pipeline_editor/components/header/validation_segment.vue';
-
-import { mockCiYml, mockLintResponse } from '../../mock_data';
-
-describe('Pipeline editor header', () => {
- let wrapper;
-
- const createComponent = ({ provide = {}, props = {} } = {}) => {
- wrapper = shallowMount(PipelineEditorHeader, {
- provide: {
- ...provide,
- },
- propsData: {
- ciConfigData: mockLintResponse,
- ciFileContent: mockCiYml,
- isCiConfigDataLoading: false,
- isNewCiConfigFile: false,
- ...props,
- },
- });
- };
-
- const findPipelineStatus = () => wrapper.findComponent(PipelineStatus);
- const findValidationSegment = () => wrapper.findComponent(ValidationSegment);
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('template', () => {
- it('hides the pipeline status for new projects without a CI file', () => {
- createComponent({ props: { isNewCiConfigFile: true } });
-
- expect(findPipelineStatus().exists()).toBe(false);
- });
-
- it('renders the pipeline status when CI file exists', () => {
- createComponent({ props: { isNewCiConfigFile: false } });
-
- expect(findPipelineStatus().exists()).toBe(true);
- });
-
- it('renders the validation segment', () => {
- createComponent();
-
- expect(findValidationSegment().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
deleted file mode 100644
index d40a9cc8100..00000000000
--- a/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
-import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
-import { PIPELINE_FAILURE } from '~/pipeline_editor/constants';
-import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline Status', () => {
- let wrapper;
- let mockApollo;
- let mockLinkedPipelinesQuery;
-
- const createComponent = ({ hasStages = true, options } = {}) => {
- wrapper = shallowMount(PipelineEditorMiniGraph, {
- provide: {
- dataMethod: 'graphql',
- projectFullPath: mockProjectFullPath,
- },
- propsData: {
- pipeline: mockProjectPipeline({ hasStages }).pipeline,
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = (hasStages = true) => {
- const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]];
- mockApollo = createMockApollo(handlers);
-
- createComponent({
- hasStages,
- options: {
- apolloProvider: mockApollo,
- },
- });
- };
-
- const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
-
- beforeEach(() => {
- mockLinkedPipelinesQuery = jest.fn();
- });
-
- afterEach(() => {
- mockLinkedPipelinesQuery.mockReset();
- wrapper.destroy();
- });
-
- describe('when there are stages', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(true);
- });
- });
-
- describe('when there are no stages', () => {
- beforeEach(() => {
- createComponent({ hasStages: false });
- });
-
- it('does not render pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(false);
- });
- });
-
- describe('when querying upstream and downstream pipelines', () => {
- describe('when query succeeds', () => {
- beforeEach(() => {
- mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
- createComponentWithApollo();
- });
-
- it('should call the query with the correct variables', () => {
- expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1);
- expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({
- fullPath: mockProjectFullPath,
- iid: mockProjectPipeline().pipeline.iid,
- });
- });
- });
-
- describe('when query fails', () => {
- beforeEach(async () => {
- mockLinkedPipelinesQuery.mockRejectedValue(new Error());
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('should emit an error event when query fails', async () => {
- expect(wrapper.emitted('showError')).toHaveLength(1);
- expect(wrapper.emitted('showError')[0]).toEqual([
- {
- type: PIPELINE_FAILURE,
- reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError],
- },
- ]);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js
deleted file mode 100644
index 35315db39f8..00000000000
--- a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import { GlIcon, GlLink, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelineStatus, { i18n } from '~/pipeline_editor/components/header/pipeline_status.vue';
-import getPipelineQuery from '~/pipeline_editor/graphql/queries/pipeline.query.graphql';
-import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import { mockCommitSha, mockProjectPipeline, mockProjectFullPath } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline Status', () => {
- let wrapper;
- let mockApollo;
- let mockPipelineQuery;
-
- const createComponentWithApollo = () => {
- const handlers = [[getPipelineQuery, mockPipelineQuery]];
- mockApollo = createMockApollo(handlers);
-
- wrapper = shallowMount(PipelineStatus, {
- apolloProvider: mockApollo,
- propsData: {
- commitSha: mockCommitSha,
- },
- provide: {
- projectFullPath: mockProjectFullPath,
- },
- stubs: { GlLink, GlSprintf },
- });
- };
-
- const findIcon = () => wrapper.findComponent(GlIcon);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findPipelineEditorMiniGraph = () => wrapper.findComponent(PipelineEditorMiniGraph);
- const findPipelineId = () => wrapper.find('[data-testid="pipeline-id"]');
- const findPipelineCommit = () => wrapper.find('[data-testid="pipeline-commit"]');
- const findPipelineErrorMsg = () => wrapper.find('[data-testid="pipeline-error-msg"]');
- const findPipelineLoadingMsg = () => wrapper.find('[data-testid="pipeline-loading-msg"]');
- const findPipelineViewBtn = () => wrapper.find('[data-testid="pipeline-view-btn"]');
- const findStatusIcon = () => wrapper.find('[data-testid="pipeline-status-icon"]');
-
- beforeEach(() => {
- mockPipelineQuery = jest.fn();
- });
-
- afterEach(() => {
- mockPipelineQuery.mockReset();
- wrapper.destroy();
- });
-
- describe('loading icon', () => {
- it('renders while query is being fetched', () => {
- createComponentWithApollo();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findPipelineLoadingMsg().text()).toBe(i18n.fetchLoading);
- });
-
- it('does not render if query is no longer loading', async () => {
- createComponentWithApollo();
- await waitForPromises();
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('when querying data', () => {
- describe('when data is set', () => {
- beforeEach(async () => {
- mockPipelineQuery.mockResolvedValue({
- data: { project: mockProjectPipeline() },
- });
-
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('query is called with correct variables', async () => {
- expect(mockPipelineQuery).toHaveBeenCalledTimes(1);
- expect(mockPipelineQuery).toHaveBeenCalledWith({
- fullPath: mockProjectFullPath,
- sha: mockCommitSha,
- });
- });
-
- it('does not render error', () => {
- expect(findPipelineErrorMsg().exists()).toBe(false);
- });
-
- it('renders pipeline data', () => {
- const {
- id,
- commit: { title },
- detailedStatus: { detailsPath },
- } = mockProjectPipeline().pipeline;
-
- expect(findStatusIcon().exists()).toBe(true);
- expect(findPipelineId().text()).toBe(`#${id.match(/\d+/g)[0]}`);
- expect(findPipelineCommit().text()).toBe(`${mockCommitSha}: ${title}`);
- expect(findPipelineViewBtn().attributes('href')).toBe(detailsPath);
- });
-
- it('renders the pipeline mini graph', () => {
- expect(findPipelineEditorMiniGraph().exists()).toBe(true);
- });
- });
-
- describe('when data cannot be fetched', () => {
- beforeEach(async () => {
- mockPipelineQuery.mockRejectedValue(new Error());
-
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('renders error', () => {
- expect(findIcon().attributes('name')).toBe('warning-solid');
- expect(findPipelineErrorMsg().text()).toBe(i18n.fetchError);
- });
-
- it('does not render pipeline data', () => {
- expect(findStatusIcon().exists()).toBe(false);
- expect(findPipelineId().exists()).toBe(false);
- expect(findPipelineCommit().exists()).toBe(false);
- expect(findPipelineViewBtn().exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js
deleted file mode 100644
index d40a9cc8100..00000000000
--- a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
-import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
-import { PIPELINE_FAILURE } from '~/pipeline_editor/constants';
-import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline Status', () => {
- let wrapper;
- let mockApollo;
- let mockLinkedPipelinesQuery;
-
- const createComponent = ({ hasStages = true, options } = {}) => {
- wrapper = shallowMount(PipelineEditorMiniGraph, {
- provide: {
- dataMethod: 'graphql',
- projectFullPath: mockProjectFullPath,
- },
- propsData: {
- pipeline: mockProjectPipeline({ hasStages }).pipeline,
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = (hasStages = true) => {
- const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]];
- mockApollo = createMockApollo(handlers);
-
- createComponent({
- hasStages,
- options: {
- apolloProvider: mockApollo,
- },
- });
- };
-
- const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
-
- beforeEach(() => {
- mockLinkedPipelinesQuery = jest.fn();
- });
-
- afterEach(() => {
- mockLinkedPipelinesQuery.mockReset();
- wrapper.destroy();
- });
-
- describe('when there are stages', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(true);
- });
- });
-
- describe('when there are no stages', () => {
- beforeEach(() => {
- createComponent({ hasStages: false });
- });
-
- it('does not render pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(false);
- });
- });
-
- describe('when querying upstream and downstream pipelines', () => {
- describe('when query succeeds', () => {
- beforeEach(() => {
- mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
- createComponentWithApollo();
- });
-
- it('should call the query with the correct variables', () => {
- expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1);
- expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({
- fullPath: mockProjectFullPath,
- iid: mockProjectPipeline().pipeline.iid,
- });
- });
- });
-
- describe('when query fails', () => {
- beforeEach(async () => {
- mockLinkedPipelinesQuery.mockRejectedValue(new Error());
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('should emit an error event when query fails', async () => {
- expect(wrapper.emitted('showError')).toHaveLength(1);
- expect(wrapper.emitted('showError')[0]).toEqual([
- {
- type: PIPELINE_FAILURE,
- reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError],
- },
- ]);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js b/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js
deleted file mode 100644
index 1ad621e6f45..00000000000
--- a/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js
+++ /dev/null
@@ -1,197 +0,0 @@
-import VueApollo from 'vue-apollo';
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import { escape } from 'lodash';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { sprintf } from '~/locale';
-import ValidationSegment, {
- i18n,
-} from '~/pipeline_editor/components/header/validation_segment.vue';
-import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-import {
- CI_CONFIG_STATUS_INVALID,
- EDITOR_APP_STATUS_EMPTY,
- EDITOR_APP_STATUS_INVALID,
- EDITOR_APP_STATUS_LOADING,
- EDITOR_APP_STATUS_LINT_UNAVAILABLE,
- EDITOR_APP_STATUS_VALID,
-} from '~/pipeline_editor/constants';
-import {
- mergeUnwrappedCiConfig,
- mockCiYml,
- mockLintUnavailableHelpPagePath,
- mockYmlHelpPagePath,
-} from '../../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Validation segment component', () => {
- let wrapper;
-
- const mockApollo = createMockApollo();
-
- const createComponent = ({ props = {}, appStatus = EDITOR_APP_STATUS_INVALID }) => {
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getAppStatus,
- data: {
- app: {
- __typename: 'PipelineEditorApp',
- status: appStatus,
- },
- },
- });
-
- wrapper = extendedWrapper(
- shallowMount(ValidationSegment, {
- apolloProvider: mockApollo,
- provide: {
- ymlHelpPagePath: mockYmlHelpPagePath,
- lintUnavailableHelpPagePath: mockLintUnavailableHelpPagePath,
- },
- propsData: {
- ciConfig: mergeUnwrappedCiConfig(),
- ciFileContent: mockCiYml,
- ...props,
- },
- }),
- );
- };
-
- const findIcon = () => wrapper.findComponent(GlIcon);
- const findLearnMoreLink = () => wrapper.findByTestId('learnMoreLink');
- const findValidationMsg = () => wrapper.findByTestId('validationMsg');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('shows the loading state', () => {
- createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
-
- expect(wrapper.text()).toBe(i18n.loading);
- });
-
- describe('when config is empty', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_EMPTY });
- });
-
- it('has check icon', () => {
- expect(findIcon().props('name')).toBe('check');
- });
-
- it('shows a message for empty state', () => {
- expect(findValidationMsg().text()).toBe(i18n.empty);
- });
- });
-
- describe('when config is valid', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_VALID });
- });
-
- it('has check icon', () => {
- expect(findIcon().props('name')).toBe('check');
- });
-
- it('shows a message for valid state', () => {
- expect(findValidationMsg().text()).toContain(i18n.valid);
- });
-
- it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockYmlHelpPagePath);
- expect(findLearnMoreLink().text()).toBe(i18n.learnMore);
- });
- });
-
- describe('when config is invalid', () => {
- beforeEach(() => {
- createComponent({
- appStatus: EDITOR_APP_STATUS_INVALID,
- });
- });
-
- it('has warning icon', () => {
- expect(findIcon().props('name')).toBe('warning-solid');
- });
-
- it('has message for invalid state', () => {
- expect(findValidationMsg().text()).toBe(i18n.invalid);
- });
-
- it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockYmlHelpPagePath);
- expect(findLearnMoreLink().text()).toBe('Learn more');
- });
-
- describe('with multiple errors', () => {
- const firstError = 'First Error';
- const secondError = 'Second Error';
-
- beforeEach(() => {
- createComponent({
- props: {
- ciConfig: mergeUnwrappedCiConfig({
- status: CI_CONFIG_STATUS_INVALID,
- errors: [firstError, secondError],
- }),
- },
- });
- });
- it('shows an invalid state with an error', () => {
- // Test the error is shown _and_ the string matches
- expect(findValidationMsg().text()).toContain(firstError);
- expect(findValidationMsg().text()).toBe(
- sprintf(i18n.invalidWithReason, { reason: firstError }),
- );
- });
- });
-
- describe('with XSS inside the error', () => {
- const evilError = '<script>evil();</script>';
-
- beforeEach(() => {
- createComponent({
- props: {
- ciConfig: mergeUnwrappedCiConfig({
- status: CI_CONFIG_STATUS_INVALID,
- errors: [evilError],
- }),
- },
- });
- });
- it('shows an invalid state with an error while preventing XSS', () => {
- const { innerHTML } = findValidationMsg().element;
-
- expect(innerHTML).not.toContain(evilError);
- expect(innerHTML).toContain(escape(evilError));
- });
- });
- });
-
- describe('when the lint service is unavailable', () => {
- beforeEach(() => {
- createComponent({
- appStatus: EDITOR_APP_STATUS_LINT_UNAVAILABLE,
- props: {
- ciConfig: {},
- },
- });
- });
-
- it('show a message that the service is unavailable', () => {
- expect(findValidationMsg().text()).toBe(i18n.unavailableValidation);
- });
-
- it('shows the time-out icon', () => {
- expect(findIcon().props('name')).toBe('time-out');
- });
-
- it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockLintUnavailableHelpPagePath);
- expect(findLearnMoreLink().text()).toBe(i18n.learnMore);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js b/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js
deleted file mode 100644
index 7f89eda4dff..00000000000
--- a/spec/frontend/pipeline_editor/components/lint/ci_lint_results_spec.js
+++ /dev/null
@@ -1,177 +0,0 @@
-import { GlTableLite, GlLink } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
-import CiLintResults from '~/pipeline_editor/components/lint/ci_lint_results.vue';
-import { mockJobs, mockErrors, mockWarnings } from '../../mock_data';
-
-describe('CI Lint Results', () => {
- let wrapper;
- const defaultProps = {
- isValid: true,
- jobs: mockJobs,
- errors: [],
- warnings: [],
- dryRun: false,
- lintHelpPagePath: '/help',
- };
-
- const createComponent = (props = {}, mountFn = shallowMount) => {
- wrapper = mountFn(CiLintResults, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- const findTable = () => wrapper.findComponent(GlTableLite);
- const findByTestId = (selector) => () => wrapper.find(`[data-testid="ci-lint-${selector}"]`);
- const findAllByTestId = (selector) => () =>
- wrapper.findAll(`[data-testid="ci-lint-${selector}"]`);
- const findLinkToDoc = () => wrapper.findComponent(GlLink);
- const findErrors = findByTestId('errors');
- const findWarnings = findByTestId('warnings');
- const findStatus = findByTestId('status');
- const findOnlyExcept = findByTestId('only-except');
- const findLintParameters = findAllByTestId('parameter');
- const findLintValues = findAllByTestId('value');
- const findBeforeScripts = findAllByTestId('before-script');
- const findScripts = findAllByTestId('script');
- const findAfterScripts = findAllByTestId('after-script');
- const filterEmptyScripts = (property) => mockJobs.filter((job) => job[property].length !== 0);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('Empty results', () => {
- it('renders with no jobs, errors or warnings defined', () => {
- createComponent({ jobs: undefined, errors: undefined, warnings: undefined }, shallowMount);
- expect(findTable().exists()).toBe(true);
- });
-
- it('renders when job has no properties defined', () => {
- // job with no attributes such as `tagList` or `environment`
- const job = {
- stage: 'Stage Name',
- name: 'test job',
- };
- createComponent({ jobs: [job] }, mount);
-
- const param = findLintParameters().at(0);
- const value = findLintValues().at(0);
-
- expect(param.text()).toBe(`${job.stage} Job - ${job.name}`);
-
- // This test should be updated once properties of each job are shown
- // See https://gitlab.com/gitlab-org/gitlab/-/issues/291031
- expect(value.text()).toBe('');
- });
- });
-
- describe('Invalid results', () => {
- beforeEach(() => {
- createComponent({ isValid: false, errors: mockErrors, warnings: mockWarnings }, mount);
- });
-
- it('does not display the table', () => {
- expect(findTable().exists()).toBe(false);
- });
-
- it('displays the invalid status', () => {
- expect(findStatus().text()).toContain(`Status: ${wrapper.vm.$options.incorrect.text}`);
- expect(findStatus().props('variant')).toBe(wrapper.vm.$options.incorrect.variant);
- });
-
- it('contains the link to documentation', () => {
- expect(findLinkToDoc().text()).toBe('More information');
- expect(findLinkToDoc().attributes('href')).toBe(defaultProps.lintHelpPagePath);
- });
-
- it('displays the error message', () => {
- const [expectedError] = mockErrors;
-
- expect(findErrors().text()).toBe(expectedError);
- });
-
- it('displays the warning message', () => {
- const [expectedWarning] = mockWarnings;
-
- expect(findWarnings().exists()).toBe(true);
- expect(findWarnings().text()).toContain(expectedWarning);
- });
- });
-
- describe('Valid results with dry run', () => {
- beforeEach(() => {
- createComponent({ dryRun: true }, mount);
- });
-
- it('displays table', () => {
- expect(findTable().exists()).toBe(true);
- });
-
- it('displays the valid status', () => {
- expect(findStatus().text()).toContain(wrapper.vm.$options.correct.text);
- expect(findStatus().props('variant')).toBe(wrapper.vm.$options.correct.variant);
- });
-
- it('does not display only/expect values with dry run', () => {
- expect(findOnlyExcept().exists()).toBe(false);
- });
-
- it('contains the link to documentation', () => {
- expect(findLinkToDoc().text()).toBe('More information');
- expect(findLinkToDoc().attributes('href')).toBe(defaultProps.lintHelpPagePath);
- });
- });
-
- describe('Lint results', () => {
- beforeEach(() => {
- createComponent({}, mount);
- });
-
- it('formats parameter value', () => {
- findLintParameters().wrappers.forEach((job, index) => {
- const { stage } = mockJobs[index];
- const { name } = mockJobs[index];
-
- expect(job.text()).toBe(`${capitalizeFirstCharacter(stage)} Job - ${name}`);
- });
- });
-
- it('only shows before scripts when data is present', () => {
- expect(findBeforeScripts()).toHaveLength(filterEmptyScripts('beforeScript').length);
- });
-
- it('only shows script when data is present', () => {
- expect(findScripts()).toHaveLength(filterEmptyScripts('script').length);
- });
-
- it('only shows after script when data is present', () => {
- expect(findAfterScripts()).toHaveLength(filterEmptyScripts('afterScript').length);
- });
- });
-
- describe('Hide Alert', () => {
- it('hides alert on success if hide-alert prop is true', async () => {
- await createComponent({ dryRun: true, hideAlert: true }, mount);
-
- expect(findStatus().exists()).toBe(false);
- });
-
- it('hides alert on error if hide-alert prop is true', async () => {
- await createComponent(
- {
- hideAlert: true,
- isValid: false,
- errors: mockErrors,
- warnings: mockWarnings,
- },
- mount,
- );
-
- expect(findStatus().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js b/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js
deleted file mode 100644
index 36052a2e16a..00000000000
--- a/spec/frontend/pipeline_editor/components/lint/ci_lint_warnings_spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { GlAlert, GlSprintf } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { trimText } from 'helpers/text_helper';
-import CiLintWarnings from '~/pipeline_editor/components/lint/ci_lint_warnings.vue';
-
-const warnings = ['warning 1', 'warning 2', 'warning 3'];
-
-describe('CI lint warnings', () => {
- let wrapper;
-
- const createComponent = (limit = 25) => {
- wrapper = mount(CiLintWarnings, {
- propsData: {
- warnings,
- maxWarnings: limit,
- },
- });
- };
-
- const findWarningAlert = () => wrapper.findComponent(GlAlert);
- const findWarnings = () => wrapper.findAll('[data-testid="ci-lint-warning"]');
- const findWarningMessage = () => trimText(wrapper.findComponent(GlSprintf).text());
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('displays the warning alert', () => {
- createComponent();
-
- expect(findWarningAlert().exists()).toBe(true);
- });
-
- it('displays all the warnings', () => {
- createComponent();
-
- expect(findWarnings()).toHaveLength(warnings.length);
- });
-
- it('shows the correct message when the limit is not passed', () => {
- createComponent();
-
- expect(findWarningMessage()).toBe(`${warnings.length} warnings found:`);
- });
-
- it('shows the correct message when the limit is passed', () => {
- const limit = 2;
-
- createComponent(limit);
-
- expect(findWarningMessage()).toBe(`${warnings.length} warnings found: showing first ${limit}`);
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
deleted file mode 100644
index 27707f8b01a..00000000000
--- a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
+++ /dev/null
@@ -1,342 +0,0 @@
-// TODO
-
-import { GlAlert, GlBadge, GlLoadingIcon, GlTabs } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import Vue, { nextTick } from 'vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
-import CiValidate from '~/pipeline_editor/components/validate/ci_validate.vue';
-import WalkthroughPopover from '~/pipeline_editor/components/popovers/walkthrough_popover.vue';
-import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
-import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue';
-import {
- CREATE_TAB,
- EDITOR_APP_STATUS_EMPTY,
- EDITOR_APP_STATUS_LOADING,
- EDITOR_APP_STATUS_INVALID,
- EDITOR_APP_STATUS_VALID,
- TAB_QUERY_PARAM,
- VALIDATE_TAB,
- VALIDATE_TAB_BADGE_DISMISSED_KEY,
-} from '~/pipeline_editor/constants';
-import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
-import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
-import {
- mockBlobContentQueryResponse,
- mockCiLintPath,
- mockCiYml,
- mockLintResponse,
- mockLintResponseWithoutMerged,
-} from '../mock_data';
-
-Vue.use(VueApollo);
-
-Vue.config.ignoredElements = ['gl-emoji'];
-
-describe('Pipeline editor tabs component', () => {
- let wrapper;
- const MockTextEditor = {
- template: '<div />',
- };
-
- const createComponent = ({
- listeners = {},
- props = {},
- provide = {},
- appStatus = EDITOR_APP_STATUS_VALID,
- mountFn = shallowMount,
- options = {},
- } = {}) => {
- wrapper = mountFn(PipelineEditorTabs, {
- propsData: {
- ciConfigData: mockLintResponse,
- ciFileContent: mockCiYml,
- currentTab: CREATE_TAB,
- isNewCiConfigFile: true,
- showDrawer: false,
- ...props,
- },
- data() {
- return {
- appStatus,
- };
- },
- provide: {
- ciConfigPath: '/path/to/ci-config',
- ciLintPath: mockCiLintPath,
- currentBranch: 'main',
- projectFullPath: '/path/to/project',
- simulatePipelineHelpPagePath: 'path/to/help/page',
- validateTabIllustrationPath: 'path/to/svg',
- ...provide,
- },
- stubs: {
- TextEditor: MockTextEditor,
- EditorTab,
- },
- listeners,
- ...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,
- },
- });
- };
-
- const findEditorTab = () => wrapper.find('[data-testid="editor-tab"]');
- const findMergedTab = () => wrapper.find('[data-testid="merged-tab"]');
- const findValidateTab = () => wrapper.find('[data-testid="validate-tab"]');
- const findVisualizationTab = () => wrapper.find('[data-testid="visualization-tab"]');
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findBadge = () => wrapper.findComponent(GlBadge);
- const findCiValidate = () => wrapper.findComponent(CiValidate);
- const findGlTabs = () => wrapper.findComponent(GlTabs);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
- const findTextEditor = () => wrapper.findComponent(MockTextEditor);
- const findMergedPreview = () => wrapper.findComponent(CiConfigMergedPreview);
- const findWalkthroughPopover = () => wrapper.findComponent(WalkthroughPopover);
-
- beforeEach(() => {
- mockBlobContentData = jest.fn();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('editor tab', () => {
- it('displays editor only after the tab is mounted', async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- createComponentWithApollo({ mountFn: mount });
-
- expect(findTextEditor().exists()).toBe(false);
-
- await nextTick();
-
- expect(findTextEditor().exists()).toBe(true);
- expect(findEditorTab().exists()).toBe(true);
- });
- });
-
- describe('visualization tab', () => {
- describe('while loading', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
- });
-
- it('displays a loading icon if the lint query is loading', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findPipelineGraph().exists()).toBe(false);
- });
- });
- describe('after loading', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('display the tab and visualization', () => {
- expect(findVisualizationTab().exists()).toBe(true);
- expect(findPipelineGraph().exists()).toBe(true);
- });
- });
- });
-
- describe('validate tab', () => {
- describe('after loading', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the tab and the validate component', () => {
- expect(findValidateTab().exists()).toBe(true);
- expect(findCiValidate().exists()).toBe(true);
- });
- });
-
- describe('NEW badge', () => {
- describe('default', () => {
- beforeEach(() => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- createComponentWithApollo({
- mountFn: mount,
- props: {
- currentTab: VALIDATE_TAB,
- },
- });
- });
-
- it('renders badge by default', () => {
- expect(findBadge().exists()).toBe(true);
- expect(findBadge().text()).toBe(wrapper.vm.$options.i18n.new);
- });
-
- it('hides badge when moving away from the validate tab', async () => {
- expect(findBadge().exists()).toBe(true);
-
- await findEditorTab().vm.$emit('click');
-
- expect(findBadge().exists()).toBe(false);
- });
- });
-
- describe('if badge has been dismissed before', () => {
- beforeEach(() => {
- localStorage.setItem(VALIDATE_TAB_BADGE_DISMISSED_KEY, 'true');
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- createComponentWithApollo({ mountFn: mount });
- });
-
- it('does not render badge if it has been dismissed before', () => {
- expect(findBadge().exists()).toBe(false);
- });
- });
- });
- });
-
- describe('merged tab', () => {
- describe('while loading', () => {
- beforeEach(() => {
- createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
- });
-
- it('displays a loading icon if the lint query is loading', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- });
- });
-
- describe('when there is a fetch error', () => {
- beforeEach(() => {
- createComponent({ props: { ciConfigData: mockLintResponseWithoutMerged } });
- });
-
- it('show an error message', () => {
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts.loadMergedYaml);
- });
-
- it('does not render the `merged_preview` component', () => {
- expect(findMergedPreview().exists()).toBe(false);
- });
- });
-
- describe('after loading', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('display the tab and the merged preview component', () => {
- expect(findMergedTab().exists()).toBe(true);
- expect(findMergedPreview().exists()).toBe(true);
- });
- });
- });
-
- describe('show tab content based on status', () => {
- it.each`
- appStatus | editor | viz | validate | merged
- ${undefined} | ${true} | ${true} | ${true} | ${true}
- ${EDITOR_APP_STATUS_EMPTY} | ${true} | ${false} | ${true} | ${false}
- ${EDITOR_APP_STATUS_INVALID} | ${true} | ${false} | ${true} | ${true}
- ${EDITOR_APP_STATUS_VALID} | ${true} | ${true} | ${true} | ${true}
- `(
- 'when status is $appStatus, we show - editor:$editor | viz:$viz | validate:$validate | merged:$merged',
- ({ appStatus, editor, viz, validate, merged }) => {
- createComponent({ appStatus });
-
- expect(findTextEditor().exists()).toBe(editor);
- expect(findPipelineGraph().exists()).toBe(viz);
- expect(findValidateTab().exists()).toBe(validate);
- expect(findMergedPreview().exists()).toBe(merged);
- },
- );
- });
-
- 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);
- });
- });
-
- describe('pipeline editor walkthrough', () => {
- describe('when isNewCiConfigFile prop is true (default)', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows walkthrough popover', async () => {
- expect(findWalkthroughPopover().exists()).toBe(true);
- });
- });
-
- describe('when isNewCiConfigFile prop is false', () => {
- it('does not show walkthrough popover', async () => {
- createComponent({ props: { isNewCiConfigFile: false } });
- expect(findWalkthroughPopover().exists()).toBe(false);
- });
- });
- });
-
- it('sets listeners on walkthrough popover', async () => {
- const handler = jest.fn();
-
- createComponent({
- listeners: {
- event: handler,
- },
- });
- await nextTick();
-
- findWalkthroughPopover().vm.$emit('event');
-
- expect(handler).toHaveBeenCalled();
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js
deleted file mode 100644
index 98ce3f6ea40..00000000000
--- a/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { nextTick } from 'vue';
-import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue';
-import { FILE_TREE_POPOVER_DISMISSED_KEY } from '~/pipeline_editor/constants';
-import { mockIncludesHelpPagePath } from '../../mock_data';
-
-describe('FileTreePopover component', () => {
- let wrapper;
-
- const findPopover = () => wrapper.findComponent(GlPopover);
- const findLink = () => findPopover().findComponent(GlLink);
-
- const createComponent = ({ stubs } = {}) => {
- wrapper = shallowMount(FileTreePopover, {
- provide: {
- includesHelpPagePath: mockIncludesHelpPagePath,
- },
- stubs,
- });
- };
-
- afterEach(() => {
- localStorage.clear();
- wrapper.destroy();
- });
-
- describe('default', () => {
- beforeEach(async () => {
- createComponent({ stubs: { GlSprintf } });
- });
-
- it('renders dismissable popover', async () => {
- expect(findPopover().exists()).toBe(true);
-
- findPopover().vm.$emit('close-button-clicked');
- await nextTick();
-
- expect(findPopover().exists()).toBe(false);
- });
-
- it('renders learn more link', () => {
- expect(findLink().exists()).toBe(true);
- expect(findLink().attributes('href')).toBe(mockIncludesHelpPagePath);
- });
- });
-
- describe('when popover has already been dismissed before', () => {
- it('does not render popover', async () => {
- localStorage.setItem(FILE_TREE_POPOVER_DISMISSED_KEY, 'true');
- createComponent();
-
- expect(findPopover().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js
deleted file mode 100644
index 97f785a71bc..00000000000
--- a/spec/frontend/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { GlLink, GlSprintf } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ValidatePopover from '~/pipeline_editor/components/popovers/validate_pipeline_popover.vue';
-import { VALIDATE_TAB_FEEDBACK_URL } from '~/pipeline_editor/constants';
-import { mockSimulatePipelineHelpPagePath } from '../../mock_data';
-
-describe('ValidatePopover component', () => {
- let wrapper;
-
- const createComponent = ({ stubs } = {}) => {
- wrapper = shallowMountExtended(ValidatePopover, {
- provide: {
- simulatePipelineHelpPagePath: mockSimulatePipelineHelpPagePath,
- },
- stubs,
- });
- };
-
- const findHelpLink = () => wrapper.findByTestId('help-link');
- const findFeedbackLink = () => wrapper.findByTestId('feedback-link');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('template', () => {
- beforeEach(async () => {
- createComponent({
- stubs: { GlLink, GlSprintf },
- });
- });
-
- it('renders help link', () => {
- expect(findHelpLink().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(mockSimulatePipelineHelpPagePath);
- });
-
- it('renders feedback link', () => {
- expect(findFeedbackLink().exists()).toBe(true);
- expect(findFeedbackLink().attributes('href')).toBe(VALIDATE_TAB_FEEDBACK_URL);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js
deleted file mode 100644
index b86c82850c5..00000000000
--- a/spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { mount, shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import WalkthroughPopover from '~/pipeline_editor/components/popovers/walkthrough_popover.vue';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-
-Vue.config.ignoredElements = ['gl-emoji'];
-
-describe('WalkthroughPopover component', () => {
- let wrapper;
-
- const createComponent = (mountFn = shallowMount) => {
- return extendedWrapper(mountFn(WalkthroughPopover));
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('CTA button clicked', () => {
- beforeEach(async () => {
- wrapper = createComponent(mount);
- await wrapper.findByTestId('ctaBtn').trigger('click');
- });
-
- it('emits "walkthrough-popover-cta-clicked" event', async () => {
- expect(wrapper.emitted()['walkthrough-popover-cta-clicked']).toHaveLength(1);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js b/spec/frontend/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js
deleted file mode 100644
index 44fda2812d8..00000000000
--- a/spec/frontend/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import ConfirmDialog from '~/pipeline_editor/components/ui/confirm_unsaved_changes_dialog.vue';
-
-describe('pipeline_editor/components/ui/confirm_unsaved_changes_dialog', () => {
- let beforeUnloadEvent;
- let setDialogContent;
- let wrapper;
-
- const createComponent = (propsData = {}) => {
- wrapper = shallowMount(ConfirmDialog, {
- propsData,
- });
- };
-
- beforeEach(() => {
- beforeUnloadEvent = new Event('beforeunload');
- jest.spyOn(beforeUnloadEvent, 'preventDefault');
- setDialogContent = jest.spyOn(beforeUnloadEvent, 'returnValue', 'set');
- });
-
- afterEach(() => {
- beforeUnloadEvent.preventDefault.mockRestore();
- setDialogContent.mockRestore();
- wrapper.destroy();
- });
-
- it('shows confirmation dialog when there are unsaved changes', () => {
- createComponent({ hasUnsavedChanges: true });
- window.dispatchEvent(beforeUnloadEvent);
-
- expect(beforeUnloadEvent.preventDefault).toHaveBeenCalled();
- expect(setDialogContent).toHaveBeenCalledWith('');
- });
-
- it('does not show confirmation dialog when there are no unsaved changes', () => {
- createComponent({ hasUnsavedChanges: false });
- window.dispatchEvent(beforeUnloadEvent);
-
- expect(beforeUnloadEvent.preventDefault).not.toHaveBeenCalled();
- expect(setDialogContent).not.toHaveBeenCalled();
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/ui/editor_tab_spec.js b/spec/frontend/pipeline_editor/components/ui/editor_tab_spec.js
deleted file mode 100644
index 24f27e8c5fb..00000000000
--- a/spec/frontend/pipeline_editor/components/ui/editor_tab_spec.js
+++ /dev/null
@@ -1,200 +0,0 @@
-import { GlAlert, GlBadge, GlTabs } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue';
-
-const mockContent1 = 'MOCK CONTENT 1';
-const mockContent2 = 'MOCK CONTENT 2';
-
-const MockSourceEditor = {
- template: '<div>EDITOR</div>',
-};
-
-describe('~/pipeline_editor/components/ui/editor_tab.vue', () => {
- let wrapper;
- let mockChildMounted = jest.fn();
-
- const MockChild = {
- props: ['content'],
- template: '<div>{{content}}</div>',
- mounted() {
- mockChildMounted(this.content);
- },
- };
-
- const MockTabbedContent = {
- components: {
- EditorTab,
- GlTabs,
- MockChild,
- },
- template: `
- <gl-tabs>
- <editor-tab title="Tab 1" :title-link-attributes="{ 'data-testid': 'tab1-btn' }" :lazy="true">
- <mock-child content="${mockContent1}"/>
- </editor-tab>
- <editor-tab title="Tab 2" :title-link-attributes="{ 'data-testid': 'tab2-btn' }" :lazy="true" badge-title="NEW">
- <mock-child content="${mockContent2}"/>
- </editor-tab>
- </gl-tabs>
- `,
- };
-
- const createMockedWrapper = () => {
- wrapper = mount(MockTabbedContent);
- };
-
- const createWrapper = ({ props } = {}) => {
- wrapper = mount(EditorTab, {
- propsData: {
- title: 'Tab 1',
- ...props,
- },
- slots: {
- default: MockSourceEditor,
- },
- });
- };
-
- const findSlotComponent = () => wrapper.findComponent(MockSourceEditor);
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findBadges = () => wrapper.findAllComponents(GlBadge);
-
- beforeEach(() => {
- mockChildMounted = jest.fn();
- });
-
- it('tabs are mounted lazily', async () => {
- createMockedWrapper();
-
- expect(mockChildMounted).toHaveBeenCalledTimes(0);
- });
-
- it('first tab is only mounted after nextTick', async () => {
- createMockedWrapper();
-
- await nextTick();
-
- expect(mockChildMounted).toHaveBeenCalledTimes(1);
- expect(mockChildMounted).toHaveBeenCalledWith(mockContent1);
- });
-
- describe('alerts', () => {
- describe('unavailable state', () => {
- beforeEach(() => {
- createWrapper({ props: { isUnavailable: true } });
- });
-
- it('shows the invalid alert when the status is invalid', () => {
- const alert = findAlert();
-
- expect(alert.exists()).toBe(true);
- expect(alert.text()).toContain(wrapper.vm.$options.i18n.unavailable);
- });
- });
-
- describe('invalid state', () => {
- beforeEach(() => {
- createWrapper({ props: { isInvalid: true } });
- });
-
- it('shows the invalid alert when the status is invalid', () => {
- const alert = findAlert();
-
- expect(alert.exists()).toBe(true);
- expect(alert.text()).toBe(wrapper.vm.$options.i18n.invalid);
- });
- });
-
- describe('empty state', () => {
- const text = 'my custom alert message';
-
- beforeEach(() => {
- createWrapper({
- props: { isEmpty: true, emptyMessage: text },
- });
- });
-
- it('displays an empty message', () => {
- createWrapper({
- props: { isEmpty: true },
- });
-
- const alert = findAlert();
-
- expect(alert.exists()).toBe(true);
- expect(alert.text()).toBe(
- 'This tab will be usable when the CI/CD configuration file is populated with valid syntax.',
- );
- });
-
- it('can have a custom empty message', () => {
- const alert = findAlert();
-
- expect(alert.exists()).toBe(true);
- expect(alert.text()).toBe(text);
- });
- });
- });
-
- describe('showing the tab content depending on `isEmpty`, `isUnavailable` and `isInvalid`', () => {
- it.each`
- isEmpty | isUnavailable | isInvalid | showSlotComponent | text
- ${undefined} | ${undefined} | ${undefined} | ${true} | ${'renders'}
- ${false} | ${false} | ${false} | ${true} | ${'renders'}
- ${undefined} | ${true} | ${true} | ${false} | ${'hides'}
- ${true} | ${false} | ${false} | ${false} | ${'hides'}
- ${false} | ${true} | ${false} | ${false} | ${'hides'}
- ${false} | ${false} | ${true} | ${false} | ${'hides'}
- `(
- '$text the slot component when isEmpty:$isEmpty, isUnavailable:$isUnavailable and isInvalid:$isInvalid',
- ({ isEmpty, isUnavailable, isInvalid, showSlotComponent }) => {
- createWrapper({
- props: { isEmpty, isUnavailable, isInvalid },
- });
- expect(findSlotComponent().exists()).toBe(showSlotComponent);
- expect(findAlert().exists()).toBe(!showSlotComponent);
- },
- );
- });
-
- describe('user interaction', () => {
- const clickTab = async (testid) => {
- wrapper.find(`[data-testid="${testid}"]`).trigger('click');
- await nextTick();
- };
-
- beforeEach(() => {
- createMockedWrapper();
- });
-
- it('mounts a tab once after selecting it', async () => {
- await clickTab('tab2-btn');
-
- expect(mockChildMounted).toHaveBeenCalledTimes(2);
- expect(mockChildMounted).toHaveBeenNthCalledWith(1, mockContent1);
- expect(mockChildMounted).toHaveBeenNthCalledWith(2, mockContent2);
- });
-
- it('mounts each tab once after selecting each', async () => {
- await clickTab('tab2-btn');
- await clickTab('tab1-btn');
- await clickTab('tab2-btn');
-
- expect(mockChildMounted).toHaveBeenCalledTimes(2);
- expect(mockChildMounted).toHaveBeenNthCalledWith(1, mockContent1);
- expect(mockChildMounted).toHaveBeenNthCalledWith(2, mockContent2);
- });
- });
-
- describe('valid state', () => {
- beforeEach(() => {
- createMockedWrapper();
- });
-
- it('renders correct number of badges', async () => {
- expect(findBadges()).toHaveLength(1);
- expect(findBadges().at(0).text()).toBe('NEW');
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
deleted file mode 100644
index c76c3460e99..00000000000
--- a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { GlButton, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue';
-import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
-
-describe('Pipeline editor empty state', () => {
- let wrapper;
- const defaultProvide = {
- emptyStateIllustrationPath: 'my/svg/path',
- usesExternalConfig: false,
- };
-
- const createComponent = ({ provide } = {}) => {
- wrapper = shallowMount(PipelineEditorEmptyState, {
- provide: { ...defaultProvide, ...provide },
- });
- };
-
- const findFileNav = () => wrapper.findComponent(PipelineEditorFileNav);
- const findSvgImage = () => wrapper.find('img');
- const findTitle = () => wrapper.find('h1');
- const findExternalCiInstructions = () => wrapper.find('p');
- const findConfirmButton = () => wrapper.findComponent(GlButton);
- const findDescription = () => wrapper.findComponent(GlSprintf);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when project uses an external CI config', () => {
- beforeEach(() => {
- createComponent({
- provide: { usesExternalConfig: true },
- });
- });
-
- it('renders an svg image', () => {
- expect(findSvgImage().exists()).toBe(true);
- });
-
- it('renders the correct title and instructions', () => {
- expect(findTitle().exists()).toBe(true);
- expect(findExternalCiInstructions().exists()).toBe(true);
-
- expect(findExternalCiInstructions().html()).toContain(
- wrapper.vm.$options.i18n.externalCiInstructions,
- );
- expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.externalCiNote);
- });
-
- it('does not render the CTA button', () => {
- expect(findConfirmButton().exists()).toBe(false);
- });
- });
-
- describe('when project uses an accessible CI config', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders an svg image', () => {
- expect(findSvgImage().exists()).toBe(true);
- });
-
- it('renders a title', () => {
- expect(findTitle().exists()).toBe(true);
- expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.title);
- });
-
- it('renders a description', () => {
- expect(findDescription().exists()).toBe(true);
- expect(findDescription().html()).toContain(wrapper.vm.$options.i18n.body);
- });
-
- it('renders the file nav', () => {
- expect(findFileNav().exists()).toBe(true);
- });
-
- it('renders a CTA button', () => {
- expect(findConfirmButton().exists()).toBe(true);
- expect(findConfirmButton().text()).toBe(wrapper.vm.$options.i18n.btnText);
- });
-
- it('emits an event when clicking on the CTA', async () => {
- const expectedEvent = 'createEmptyConfigFile';
- expect(wrapper.emitted(expectedEvent)).toBeUndefined();
-
- await findConfirmButton().vm.$emit('click');
- expect(wrapper.emitted(expectedEvent)).toHaveLength(1);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js
deleted file mode 100644
index d9ecee31e83..00000000000
--- a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js
+++ /dev/null
@@ -1,149 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import CodeSnippetAlert from '~/pipeline_editor/components/code_snippet_alert/code_snippet_alert.vue';
-import { CODE_SNIPPET_SOURCES } from '~/pipeline_editor/components/code_snippet_alert/constants';
-import PipelineEditorMessages from '~/pipeline_editor/components/ui/pipeline_editor_messages.vue';
-import {
- COMMIT_FAILURE,
- COMMIT_SUCCESS,
- COMMIT_SUCCESS_WITH_REDIRECT,
- DEFAULT_FAILURE,
- DEFAULT_SUCCESS,
- LOAD_FAILURE_UNKNOWN,
- PIPELINE_FAILURE,
-} from '~/pipeline_editor/constants';
-
-beforeEach(() => {
- setWindowLocation(TEST_HOST);
-});
-
-describe('Pipeline Editor messages', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(PipelineEditorMessages, {
- propsData: props,
- });
- };
-
- const findCodeSnippetAlert = () => wrapper.findComponent(CodeSnippetAlert);
- const findAlert = () => wrapper.findComponent(GlAlert);
-
- describe('success alert', () => {
- it('shows a message for successful commit type', () => {
- createComponent({ successType: COMMIT_SUCCESS, showSuccess: true });
-
- expect(findAlert().text()).toBe(wrapper.vm.$options.success[COMMIT_SUCCESS]);
- });
-
- it('shows a message for successful commit with redirect type', () => {
- createComponent({ successType: COMMIT_SUCCESS_WITH_REDIRECT, showSuccess: true });
-
- expect(findAlert().text()).toBe(wrapper.vm.$options.success[COMMIT_SUCCESS_WITH_REDIRECT]);
- });
-
- it('does not show alert when there is a successType but visibility is off', () => {
- createComponent({ successType: COMMIT_SUCCESS, showSuccess: false });
-
- expect(findAlert().exists()).toBe(false);
- });
-
- it('shows a success alert with default copy if `showSuccess` is true and the `successType` is not valid,', () => {
- createComponent({ successType: 'random', showSuccess: true });
-
- expect(findAlert().text()).toBe(wrapper.vm.$options.success[DEFAULT_SUCCESS]);
- });
-
- it('emit `hide-success` event when clicking on the dismiss button', async () => {
- const expectedEvent = 'hide-success';
-
- createComponent({ successType: COMMIT_SUCCESS, showSuccess: true });
- expect(wrapper.emitted(expectedEvent)).not.toBeDefined();
-
- await findAlert().vm.$emit('dismiss');
-
- expect(wrapper.emitted(expectedEvent)).toBeDefined();
- });
- });
-
- describe('failure alert', () => {
- it.each`
- failureType | message | expectedFailureType
- ${COMMIT_FAILURE} | ${'failed commit'} | ${COMMIT_FAILURE}
- ${LOAD_FAILURE_UNKNOWN} | ${'loading failure'} | ${LOAD_FAILURE_UNKNOWN}
- ${PIPELINE_FAILURE} | ${'pipeline failure'} | ${PIPELINE_FAILURE}
- ${'random'} | ${'error without a specified type'} | ${DEFAULT_FAILURE}
- `('shows a message for $message', ({ failureType, expectedFailureType }) => {
- createComponent({ failureType, showFailure: true });
-
- expect(findAlert().text()).toBe(wrapper.vm.$options.errors[expectedFailureType]);
- });
-
- it('show failure reasons when there are some', () => {
- const failureReasons = ['There was a problem', 'ouppps'];
- createComponent({ failureType: COMMIT_FAILURE, failureReasons, showFailure: true });
-
- expect(wrapper.html()).toContain(failureReasons[0]);
- expect(wrapper.html()).toContain(failureReasons[1]);
- });
-
- it('does not show a message for error with a disabled visibility', () => {
- createComponent({ failureType: 'random', showFailure: false });
-
- expect(findAlert().exists()).toBe(false);
- });
-
- it('emit `hide-failure` event when clicking on the dismiss button', async () => {
- const expectedEvent = 'hide-failure';
-
- createComponent({ failureType: COMMIT_FAILURE, showFailure: true });
- expect(wrapper.emitted(expectedEvent)).not.toBeDefined();
-
- await findAlert().vm.$emit('dismiss');
-
- expect(wrapper.emitted(expectedEvent)).toBeDefined();
- });
- });
-
- describe('code snippet alert', () => {
- const setCodeSnippetUrlParam = (value) => {
- setWindowLocation(`${TEST_HOST}/?code_snippet_copied_from=${value}`);
- };
-
- it('does not show by default', () => {
- createComponent();
-
- expect(findCodeSnippetAlert().exists()).toBe(false);
- });
-
- it.each(CODE_SNIPPET_SOURCES)('shows if URL param is %s, and cleans up URL', (source) => {
- jest.spyOn(window.history, 'replaceState');
- setCodeSnippetUrlParam(source);
- createComponent();
-
- expect(findCodeSnippetAlert().exists()).toBe(true);
- expect(window.history.replaceState).toHaveBeenCalledWith({}, document.title, `${TEST_HOST}/`);
- });
-
- it('does not show if URL param is invalid', () => {
- setCodeSnippetUrlParam('foo_bar');
- createComponent();
-
- expect(findCodeSnippetAlert().exists()).toBe(false);
- });
-
- it('disappears on dismiss', async () => {
- setCodeSnippetUrlParam('api_fuzzing');
- createComponent();
- const alert = findCodeSnippetAlert();
-
- expect(alert.exists()).toBe(true);
-
- await alert.vm.$emit('dismiss');
-
- expect(alert.exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/validate/ci_validate_spec.js b/spec/frontend/pipeline_editor/components/validate/ci_validate_spec.js
deleted file mode 100644
index 09d4f9736ad..00000000000
--- a/spec/frontend/pipeline_editor/components/validate/ci_validate_spec.js
+++ /dev/null
@@ -1,314 +0,0 @@
-import { GlAlert, GlDropdown, GlIcon, GlLoadingIcon, GlPopover } from '@gitlab/ui';
-import { nextTick } from 'vue';
-import { createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import CiLintResults from '~/pipeline_editor/components/lint/ci_lint_results.vue';
-import CiValidate, { i18n } from '~/pipeline_editor/components/validate/ci_validate.vue';
-import ValidatePipelinePopover from '~/pipeline_editor/components/popovers/validate_pipeline_popover.vue';
-import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
-import lintCIMutation from '~/pipeline_editor/graphql/mutations/client/lint_ci.mutation.graphql';
-import { pipelineEditorTrackingOptions } from '~/pipeline_editor/constants';
-import {
- mockBlobContentQueryResponse,
- mockCiLintPath,
- mockCiYml,
- mockSimulatePipelineHelpPagePath,
-} from '../../mock_data';
-import { mockLintDataError, mockLintDataValid } from '../../../ci_lint/mock_data';
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-describe('Pipeline Editor Validate Tab', () => {
- let wrapper;
- let mockApollo;
- let mockBlobContentData;
- let trackingSpy;
-
- const createComponent = ({
- props,
- stubs,
- options,
- isBlobLoading = false,
- isSimulationLoading = false,
- } = {}) => {
- wrapper = shallowMountExtended(CiValidate, {
- propsData: {
- ciFileContent: mockCiYml,
- ...props,
- },
- provide: {
- ciConfigPath: '/path/to/ci-config',
- ciLintPath: mockCiLintPath,
- currentBranch: 'main',
- projectFullPath: '/path/to/project',
- validateTabIllustrationPath: '/path/to/img',
- simulatePipelineHelpPagePath: mockSimulatePipelineHelpPagePath,
- },
- stubs,
- mocks: {
- $apollo: {
- queries: {
- initialBlobContent: {
- loading: isBlobLoading,
- },
- },
- mutations: {
- lintCiMutation: {
- loading: isSimulationLoading,
- },
- },
- },
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = ({ props, stubs } = {}) => {
- const handlers = [[getBlobContent, mockBlobContentData]];
- mockApollo = createMockApollo(handlers);
-
- createComponent({
- props,
- stubs,
- options: {
- localVue,
- apolloProvider: mockApollo,
- mocks: {},
- },
- });
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findCancelBtn = () => wrapper.findByTestId('cancel-simulation');
- const findContentChangeStatus = () => wrapper.findByTestId('content-status');
- const findCta = () => wrapper.findByTestId('simulate-pipeline-button');
- const findDisabledCtaTooltip = () => wrapper.findByTestId('cta-tooltip');
- const findHelpIcon = () => wrapper.findComponent(GlIcon);
- const findIllustration = () => wrapper.findByRole('img');
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findPipelineSource = () => wrapper.findComponent(GlDropdown);
- const findPopover = () => wrapper.findComponent(GlPopover);
- const findCiLintResults = () => wrapper.findComponent(CiLintResults);
- const findResultsCta = () => wrapper.findByTestId('resimulate-pipeline-button');
-
- beforeEach(() => {
- mockBlobContentData = jest.fn();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('while initial CI content is loading', () => {
- beforeEach(() => {
- createComponent({ isBlobLoading: true });
- });
-
- it('renders disabled CTA with tooltip', () => {
- expect(findCta().props('disabled')).toBe(true);
- expect(findDisabledCtaTooltip().exists()).toBe(true);
- });
- });
-
- describe('after initial CI content is loaded', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- await createComponentWithApollo({ stubs: { GlPopover, ValidatePipelinePopover } });
- });
-
- it('renders disabled pipeline source dropdown', () => {
- expect(findPipelineSource().exists()).toBe(true);
- expect(findPipelineSource().attributes('text')).toBe(i18n.pipelineSourceDefault);
- expect(findPipelineSource().props('disabled')).toBe(true);
- });
-
- it('renders enabled CTA without tooltip', () => {
- expect(findCta().exists()).toBe(true);
- expect(findCta().props('disabled')).toBe(false);
- expect(findDisabledCtaTooltip().exists()).toBe(false);
- });
-
- it('popover is set to render when hovering over help icon', () => {
- expect(findPopover().props('target')).toBe(findHelpIcon().attributes('id'));
- expect(findPopover().props('triggers')).toBe('hover focus');
- });
- });
-
- describe('simulating the pipeline', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- await createComponentWithApollo();
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockLintDataValid);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks the simulation event', () => {
- const {
- label,
- actions: { simulatePipeline },
- } = pipelineEditorTrackingOptions;
- findCta().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, simulatePipeline, { label });
- });
-
- it('renders loading state while simulation is ongoing', async () => {
- findCta().vm.$emit('click');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findCancelBtn().exists()).toBe(true);
- expect(findCta().props('loading')).toBe(true);
- });
-
- it('calls mutation with the correct input', async () => {
- await findCta().vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: lintCIMutation,
- variables: {
- dry: true,
- content: mockCiYml,
- endpoint: mockCiLintPath,
- },
- });
- });
-
- describe('when results are successful', () => {
- beforeEach(async () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockLintDataValid);
- await findCta().vm.$emit('click');
- });
-
- it('renders success alert', () => {
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().attributes('variant')).toBe('success');
- expect(findAlert().attributes('title')).toBe(i18n.successAlertTitle);
- });
-
- it('does not render content change status or CTA for results page', () => {
- expect(findContentChangeStatus().exists()).toBe(false);
- expect(findResultsCta().exists()).toBe(false);
- });
-
- it('renders CI lint results with correct props', () => {
- expect(findCiLintResults().exists()).toBe(true);
- expect(findCiLintResults().props()).toMatchObject({
- dryRun: true,
- hideAlert: true,
- isValid: true,
- jobs: mockLintDataValid.data.lintCI.jobs,
- });
- });
- });
-
- describe('when results have errors', () => {
- beforeEach(async () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockLintDataError);
- await findCta().vm.$emit('click');
- });
-
- it('renders error alert', () => {
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().attributes('variant')).toBe('danger');
- expect(findAlert().attributes('title')).toBe(i18n.errorAlertTitle);
- });
-
- it('renders CI lint results with correct props', () => {
- expect(findCiLintResults().exists()).toBe(true);
- expect(findCiLintResults().props()).toMatchObject({
- dryRun: true,
- hideAlert: true,
- isValid: false,
- errors: mockLintDataError.data.lintCI.errors,
- warnings: mockLintDataError.data.lintCI.warnings,
- });
- });
- });
- });
-
- describe('when CI content has changed after a simulation', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- await createComponentWithApollo();
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockLintDataValid);
- await findCta().vm.$emit('click');
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks the second simulation event', async () => {
- const {
- label,
- actions: { resimulatePipeline },
- } = pipelineEditorTrackingOptions;
-
- await wrapper.setProps({ ciFileContent: 'new yaml content' });
- findResultsCta().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, resimulatePipeline, { label });
- });
-
- it('renders content change status', async () => {
- await wrapper.setProps({ ciFileContent: 'new yaml content' });
-
- expect(findContentChangeStatus().exists()).toBe(true);
- expect(findResultsCta().exists()).toBe(true);
- });
-
- it('calls mutation with new content', async () => {
- await wrapper.setProps({ ciFileContent: 'new yaml content' });
- await findResultsCta().vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(2);
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: lintCIMutation,
- variables: {
- dry: true,
- content: 'new yaml content',
- endpoint: mockCiLintPath,
- },
- });
- });
- });
-
- describe('canceling a simulation', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- await createComponentWithApollo();
- });
-
- it('returns to init state', async () => {
- // init state
- expect(findIllustration().exists()).toBe(true);
- expect(findCiLintResults().exists()).toBe(false);
-
- // mutations should have successful results
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockLintDataValid);
- findCta().vm.$emit('click');
- await nextTick();
-
- // cancel before simulation succeeds
- expect(findCancelBtn().exists()).toBe(true);
- await findCancelBtn().vm.$emit('click');
-
- // should still render init state
- expect(findIllustration().exists()).toBe(true);
- expect(findCiLintResults().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/graphql/__snapshots__/resolvers_spec.js.snap b/spec/frontend/pipeline_editor/graphql/__snapshots__/resolvers_spec.js.snap
deleted file mode 100644
index ee5a3cb288f..00000000000
--- a/spec/frontend/pipeline_editor/graphql/__snapshots__/resolvers_spec.js.snap
+++ /dev/null
@@ -1,73 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`~/pipeline_editor/graphql/resolvers Mutation lintCI lint data is as expected 1`] = `
-Object {
- "__typename": "CiLintContent",
- "errors": Array [],
- "jobs": Array [
- Object {
- "__typename": "CiLintJob",
- "afterScript": Array [
- "echo 'after script 1",
- ],
- "allowFailure": false,
- "beforeScript": Array [
- "echo 'before script 1'",
- ],
- "environment": "prd",
- "except": Object {
- "refs": Array [
- "main@gitlab-org/gitlab",
- "/^release/.*$/@gitlab-org/gitlab",
- ],
- },
- "name": "job_1",
- "only": null,
- "script": Array [
- "echo 'script 1'",
- ],
- "stage": "test",
- "tags": Array [
- "tag 1",
- ],
- "when": "on_success",
- },
- Object {
- "__typename": "CiLintJob",
- "afterScript": Array [
- "echo 'after script 2",
- ],
- "allowFailure": true,
- "beforeScript": Array [
- "echo 'before script 2'",
- ],
- "environment": "stg",
- "except": Object {
- "refs": Array [
- "main@gitlab-org/gitlab",
- "/^release/.*$/@gitlab-org/gitlab",
- ],
- },
- "name": "job_2",
- "only": Object {
- "__typename": "CiLintJobOnlyPolicy",
- "refs": Array [
- "web",
- "chat",
- "pushes",
- ],
- },
- "script": Array [
- "echo 'script 2'",
- ],
- "stage": "test",
- "tags": Array [
- "tag 2",
- ],
- "when": "on_success",
- },
- ],
- "valid": true,
- "warnings": Array [],
-}
-`;
diff --git a/spec/frontend/pipeline_editor/graphql/resolvers_spec.js b/spec/frontend/pipeline_editor/graphql/resolvers_spec.js
deleted file mode 100644
index 76ae96c623a..00000000000
--- a/spec/frontend/pipeline_editor/graphql/resolvers_spec.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import httpStatus from '~/lib/utils/http_status';
-import { resolvers } from '~/pipeline_editor/graphql/resolvers';
-import { mockLintResponse } from '../mock_data';
-
-jest.mock('~/api', () => {
- return {
- getRawFile: jest.fn(),
- };
-});
-
-describe('~/pipeline_editor/graphql/resolvers', () => {
- describe('Mutation', () => {
- describe('lintCI', () => {
- let mock;
- let result;
-
- const endpoint = '/ci/lint';
-
- beforeEach(async () => {
- mock = new MockAdapter(axios);
- mock.onPost(endpoint).reply(httpStatus.OK, mockLintResponse);
-
- result = await resolvers.Mutation.lintCI(null, {
- endpoint,
- content: 'content',
- dry_run: true,
- });
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- /* eslint-disable no-underscore-dangle */
- it('lint data has correct type names', async () => {
- expect(result.__typename).toBe('CiLintContent');
-
- expect(result.jobs[0].__typename).toBe('CiLintJob');
- expect(result.jobs[1].__typename).toBe('CiLintJob');
-
- expect(result.jobs[1].only.__typename).toBe('CiLintJobOnlyPolicy');
- });
- /* eslint-enable no-underscore-dangle */
-
- it('lint data is as expected', () => {
- expect(result).toMatchSnapshot();
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/mock_data.js b/spec/frontend/pipeline_editor/mock_data.js
deleted file mode 100644
index 2ea580b7b53..00000000000
--- a/spec/frontend/pipeline_editor/mock_data.js
+++ /dev/null
@@ -1,541 +0,0 @@
-import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/pipeline_editor/constants';
-import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
-
-export const mockProjectNamespace = 'user1';
-export const mockProjectPath = 'project1';
-export const mockProjectFullPath = `${mockProjectNamespace}/${mockProjectPath}`;
-export const mockDefaultBranch = 'main';
-export const mockNewBranch = 'new-branch';
-export const mockNewMergeRequestPath = '/-/merge_requests/new';
-export const mockCiLintPath = '/-/ci/lint';
-export const mockCommitSha = 'aabbccdd';
-export const mockCommitNextSha = 'eeffgghh';
-export const mockIncludesHelpPagePath = '/-/includes/help';
-export const mockLintHelpPagePath = '/-/lint-help';
-export const mockLintUnavailableHelpPagePath = '/-/pipeline-editor/troubleshoot';
-export const mockSimulatePipelineHelpPagePath = '/-/simulate-pipeline-help';
-export const mockYmlHelpPagePath = '/-/yml-help';
-export const mockCommitMessage = 'My commit message';
-
-export const mockCiConfigPath = '.gitlab-ci.yml';
-export const mockCiYml = `
-stages:
- - test
- - build
-
-job_test_1:
- stage: test
- script:
- - echo "test 1"
-
-job_test_2:
- stage: test
- script:
- - echo "test 2"
-
-job_build:
- stage: build
- script:
- - echo "build"
- needs: ["job_test_2"]
-`;
-
-export const mockCiTemplateQueryResponse = {
- data: {
- project: {
- id: 'project-1',
- ciTemplate: {
- content: mockCiYml,
- },
- },
- },
-};
-
-export const mockBlobContentQueryResponse = {
- data: {
- project: {
- id: 'project-1',
- repository: { blobs: { nodes: [{ id: 'blob-1', rawBlob: mockCiYml }] } },
- },
- },
-};
-
-export const mockBlobContentQueryResponseNoCiFile = {
- data: {
- project: { id: 'project-1', repository: { blobs: { nodes: [] } } },
- },
-};
-
-export const mockBlobContentQueryResponseEmptyCiFile = {
- data: {
- project: { id: 'project-1', repository: { blobs: { nodes: [{ rawBlob: '' }] } } },
- },
-};
-
-const mockJobFields = {
- beforeScript: [],
- afterScript: [],
- environment: null,
- allowFailure: false,
- tags: [],
- when: 'on_success',
- only: { refs: ['branches', 'tags'], __typename: 'CiJobLimitType' },
- except: null,
- needs: { nodes: [], __typename: 'CiConfigNeedConnection' },
- __typename: 'CiConfigJob',
-};
-
-export const mockIncludesWithBlob = {
- location: 'test-include.yml',
- type: 'local',
- blob:
- 'http://gdk.test:3000/root/upstream/-/blob/dd54f00bb3645f8ddce7665d2ffb3864540399cb/test-include.yml',
- raw:
- 'http://gdk.test:3000/root/upstream/-/raw/dd54f00bb3645f8ddce7665d2ffb3864540399cb/test-include.yml',
- __typename: 'CiConfigInclude',
-};
-
-export const mockDefaultIncludes = {
- location: 'npm.gitlab-ci.yml',
- type: 'template',
- blob: null,
- raw:
- 'https://gitlab.com/gitlab-org/gitlab/-/raw/master/lib/gitlab/ci/templates/npm.gitlab-ci.yml',
- __typename: 'CiConfigInclude',
-};
-
-export const mockIncludes = [
- mockDefaultIncludes,
- mockIncludesWithBlob,
- {
- location: 'a_really_really_long_name_for_includes_file.yml',
- type: 'local',
- blob:
- 'http://gdk.test:3000/root/upstream/-/blob/dd54f00bb3645f8ddce7665d2ffb3864540399cb/a_really_really_long_name_for_includes_file.yml',
- raw:
- 'http://gdk.test:3000/root/upstream/-/raw/dd54f00bb3645f8ddce7665d2ffb3864540399cb/a_really_really_long_name_for_includes_file.yml',
- __typename: 'CiConfigInclude',
- },
-];
-
-// Mock result of the graphql query at:
-// app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql
-export const mockCiConfigQueryResponse = {
- data: {
- ciConfig: {
- errors: [],
- includes: mockIncludes,
- mergedYaml: mockCiYml,
- status: CI_CONFIG_STATUS_VALID,
- stages: {
- __typename: 'CiConfigStageConnection',
- nodes: [
- {
- name: 'test',
- groups: {
- nodes: [
- {
- id: 'group-1',
- name: 'job_test_1',
- size: 1,
- jobs: {
- nodes: [
- {
- name: 'job_test_1',
- script: ['echo "test 1"'],
- ...mockJobFields,
- },
- ],
- __typename: 'CiConfigJobConnection',
- },
- __typename: 'CiConfigGroup',
- },
- {
- id: 'group-2',
- name: 'job_test_2',
- size: 1,
- jobs: {
- nodes: [
- {
- name: 'job_test_2',
- script: ['echo "test 2"'],
- ...mockJobFields,
- },
- ],
- __typename: 'CiConfigJobConnection',
- },
- __typename: 'CiConfigGroup',
- },
- ],
- __typename: 'CiConfigGroupConnection',
- },
- __typename: 'CiConfigStage',
- },
- {
- name: 'build',
- groups: {
- nodes: [
- {
- name: 'job_build',
- size: 1,
- jobs: {
- nodes: [
- {
- name: 'job_build',
- script: ['echo "build"'],
- ...mockJobFields,
- },
- ],
- __typename: 'CiConfigJobConnection',
- },
- __typename: 'CiConfigGroup',
- },
- ],
- __typename: 'CiConfigGroupConnection',
- },
- __typename: 'CiConfigStage',
- },
- ],
- },
- __typename: 'CiConfig',
- },
- },
-};
-
-export const mergeUnwrappedCiConfig = (mergedConfig) => {
- const { ciConfig } = mockCiConfigQueryResponse.data;
- return {
- ...ciConfig,
- stages: unwrapStagesWithNeeds(ciConfig.stages.nodes),
- ...mergedConfig,
- };
-};
-
-export const mockCommitShaResults = {
- data: {
- project: {
- id: '1',
- repository: {
- tree: {
- lastCommit: {
- id: 'commit-1',
- sha: mockCommitSha,
- },
- },
- },
- },
- },
-};
-
-export const mockNewCommitShaResults = {
- data: {
- project: {
- id: '1',
- repository: {
- tree: {
- lastCommit: {
- id: 'commit-1',
- sha: 'eeff1122',
- },
- },
- },
- },
- },
-};
-
-export const mockEmptyCommitShaResults = {
- data: {
- project: {
- id: '1',
- repository: {
- tree: {
- lastCommit: {
- id: 'commit-1',
- sha: '',
- },
- },
- },
- },
- },
-};
-
-export const mockProjectBranches = {
- data: {
- project: {
- id: '1',
- repository: {
- branchNames: [
- 'main',
- 'develop',
- 'production',
- 'test',
- 'better-feature',
- 'feature-abc',
- 'update-ci',
- 'mock-feature',
- 'test-merge-request',
- 'staging',
- ],
- },
- },
- },
-};
-
-export const mockTotalBranchResults =
- mockProjectBranches.data.project.repository.branchNames.length;
-
-export const mockSearchBranches = {
- data: {
- project: {
- id: '1',
- repository: {
- branchNames: ['test', 'better-feature', 'update-ci', 'test-merge-request'],
- },
- },
- },
-};
-
-export const mockTotalSearchResults = mockSearchBranches.data.project.repository.branchNames.length;
-
-export const mockEmptySearchBranches = {
- data: {
- project: {
- id: '1',
- repository: {
- branchNames: [],
- },
- },
- },
-};
-
-export const mockBranchPaginationLimit = 10;
-export const mockTotalBranches = 20; // must be greater than mockBranchPaginationLimit to test pagination
-
-export const mockProjectPipeline = ({ hasStages = true } = {}) => {
- const stages = hasStages
- ? {
- edges: [
- {
- node: {
- id: 'gid://gitlab/Ci::Stage/605',
- name: 'prepare',
- status: 'success',
- detailedStatus: {
- detailsPath: '/root/sample-ci-project/-/pipelines/268#prepare',
- group: 'success',
- hasDetails: true,
- icon: 'status_success',
- id: 'success-605-605',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- },
- },
- ],
- }
- : null;
-
- return {
- id: '1',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/118',
- iid: '28',
- shortSha: mockCommitSha,
- status: 'SUCCESS',
- commit: {
- id: 'commit-1',
- title: 'Update .gitlabe-ci.yml',
- webPath: '/-/commit/aabbccdd',
- },
- detailedStatus: {
- id: 'status-1',
- detailsPath: '/root/sample-ci-project/-/pipelines/118',
- group: 'success',
- icon: 'status_success',
- text: 'passed',
- },
- stages,
- },
- };
-};
-
-export const mockLinkedPipelines = ({ hasDownstream = true, hasUpstream = true } = {}) => {
- let upstream = null;
- let downstream = {
- nodes: [],
- __typename: 'PipelineConnection',
- };
-
- if (hasDownstream) {
- downstream = {
- nodes: [
- {
- id: 'gid://gitlab/Ci::Pipeline/612',
- path: '/root/job-log-sections/-/pipelines/612',
- project: { name: 'job-log-sections', __typename: 'Project' },
- detailedStatus: {
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- __typename: 'Pipeline',
- },
- ],
- __typename: 'PipelineConnection',
- };
- }
-
- if (hasUpstream) {
- upstream = {
- id: 'gid://gitlab/Ci::Pipeline/610',
- path: '/root/trigger-downstream/-/pipelines/610',
- project: { name: 'trigger-downstream', __typename: 'Project' },
- detailedStatus: {
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- __typename: 'Pipeline',
- };
- }
-
- return {
- data: {
- project: {
- pipeline: {
- path: '/root/ci-project/-/pipelines/790',
- downstream,
- upstream,
- },
- __typename: 'Project',
- },
- },
- };
-};
-
-export const mockLintResponse = {
- valid: true,
- mergedYaml: mockCiYml,
- status: CI_CONFIG_STATUS_VALID,
- errors: [],
- warnings: [],
- jobs: [
- {
- name: 'job_1',
- stage: 'test',
- before_script: ["echo 'before script 1'"],
- script: ["echo 'script 1'"],
- after_script: ["echo 'after script 1"],
- tag_list: ['tag 1'],
- environment: 'prd',
- when: 'on_success',
- allow_failure: false,
- only: null,
- except: { refs: ['main@gitlab-org/gitlab', '/^release/.*$/@gitlab-org/gitlab'] },
- },
- {
- name: 'job_2',
- stage: 'test',
- before_script: ["echo 'before script 2'"],
- script: ["echo 'script 2'"],
- after_script: ["echo 'after script 2"],
- tag_list: ['tag 2'],
- environment: 'stg',
- when: 'on_success',
- allow_failure: true,
- only: { refs: ['web', 'chat', 'pushes'] },
- except: { refs: ['main@gitlab-org/gitlab', '/^release/.*$/@gitlab-org/gitlab'] },
- },
- ],
-};
-
-export const mockLintResponseWithoutMerged = {
- valid: false,
- status: CI_CONFIG_STATUS_INVALID,
- errors: ['error'],
- warnings: [],
- jobs: [],
-};
-
-export const mockJobs = [
- {
- name: 'job_1',
- stage: 'build',
- beforeScript: [],
- script: ["echo 'Building'"],
- afterScript: [],
- tagList: [],
- environment: null,
- when: 'on_success',
- allowFailure: true,
- only: { refs: ['web', 'chat', 'pushes'] },
- except: null,
- },
- {
- name: 'multi_project_job',
- stage: 'test',
- beforeScript: [],
- script: [],
- afterScript: [],
- tagList: [],
- environment: null,
- when: 'on_success',
- allowFailure: false,
- only: { refs: ['branches', 'tags'] },
- except: null,
- },
- {
- name: 'job_2',
- stage: 'test',
- beforeScript: ["echo 'before script'"],
- script: ["echo 'script'"],
- afterScript: ["echo 'after script"],
- tagList: [],
- environment: null,
- when: 'on_success',
- allowFailure: false,
- only: { refs: ['branches@gitlab-org/gitlab'] },
- except: { refs: ['main@gitlab-org/gitlab', '/^release/.*$/@gitlab-org/gitlab'] },
- },
-];
-
-export const mockErrors = [
- '"job_1 job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post"',
-];
-
-export const mockWarnings = [
- '"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"',
-];
-
-export const mockCommitCreateResponse = {
- data: {
- commitCreate: {
- __typename: 'CommitCreatePayload',
- errors: [],
- commit: {
- __typename: 'Commit',
- id: 'commit-1',
- sha: mockCommitNextSha,
- },
- commitPipelinePath: '',
- },
- },
-};
-
-export const mockCommitCreateResponseNewEtag = {
- data: {
- commitCreate: {
- __typename: 'CommitCreatePayload',
- errors: [],
- commit: {
- __typename: 'Commit',
- id: 'commit-2',
- sha: mockCommitNextSha,
- },
- commitPipelinePath: '/api/graphql:pipelines/sha/550ceace1acd373c84d02bd539cb9d4614f786db',
- },
- },
-};
diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js
deleted file mode 100644
index 9fe1536d3f5..00000000000
--- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js
+++ /dev/null
@@ -1,589 +0,0 @@
-import { GlAlert, GlButton, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-
-import { objectToQuery, redirectTo } from '~/lib/utils/url_utility';
-import { resolvers } from '~/pipeline_editor/graphql/resolvers';
-import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
-import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
-import PipelineEditorMessages from '~/pipeline_editor/components/ui/pipeline_editor_messages.vue';
-import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_editor_header.vue';
-import ValidationSegment, {
- i18n as validationSegmenti18n,
-} from '~/pipeline_editor/components/header/validation_segment.vue';
-import {
- COMMIT_SUCCESS,
- COMMIT_SUCCESS_WITH_REDIRECT,
- COMMIT_FAILURE,
- EDITOR_APP_STATUS_LOADING,
-} from '~/pipeline_editor/constants';
-import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
-import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.query.graphql';
-import getTemplate from '~/pipeline_editor/graphql/queries/get_starter_template.query.graphql';
-import getLatestCommitShaQuery from '~/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql';
-import getPipelineQuery from '~/pipeline_editor/graphql/queries/pipeline.query.graphql';
-import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql';
-import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-
-import PipelineEditorApp from '~/pipeline_editor/pipeline_editor_app.vue';
-import PipelineEditorHome from '~/pipeline_editor/pipeline_editor_home.vue';
-
-import {
- mockCiConfigPath,
- mockCiConfigQueryResponse,
- mockBlobContentQueryResponse,
- mockBlobContentQueryResponseNoCiFile,
- mockCiYml,
- mockCiTemplateQueryResponse,
- mockCommitSha,
- mockCommitShaResults,
- mockDefaultBranch,
- mockEmptyCommitShaResults,
- mockNewCommitShaResults,
- mockNewMergeRequestPath,
- mockProjectFullPath,
-} from './mock_data';
-
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- redirectTo: jest.fn(),
-}));
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-const defaultProvide = {
- ciConfigPath: mockCiConfigPath,
- defaultBranch: mockDefaultBranch,
- newMergeRequestPath: mockNewMergeRequestPath,
- projectFullPath: mockProjectFullPath,
- usesExternalConfig: false,
-};
-
-describe('Pipeline editor app component', () => {
- let wrapper;
-
- let mockApollo;
- let mockBlobContentData;
- let mockCiConfigData;
- let mockGetTemplate;
- let mockLatestCommitShaQuery;
- let mockPipelineQuery;
-
- const createComponent = ({
- blobLoading = false,
- options = {},
- provide = {},
- stubs = {},
- } = {}) => {
- wrapper = shallowMount(PipelineEditorApp, {
- provide: { ...defaultProvide, ...provide },
- stubs,
- mocks: {
- $apollo: {
- queries: {
- initialCiFileContent: {
- loading: blobLoading,
- },
- },
- },
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = async ({
- provide = {},
- stubs = {},
- withUndefinedBranch = false,
- } = {}) => {
- const handlers = [
- [getBlobContent, mockBlobContentData],
- [getCiConfigData, mockCiConfigData],
- [getTemplate, mockGetTemplate],
- [getLatestCommitShaQuery, mockLatestCommitShaQuery],
- [getPipelineQuery, mockPipelineQuery],
- ];
-
- mockApollo = createMockApollo(handlers, resolvers);
-
- if (!withUndefinedBranch) {
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getCurrentBranch,
- data: {
- workBranches: {
- __typename: 'BranchList',
- current: {
- __typename: 'WorkBranch',
- name: mockDefaultBranch,
- },
- },
- },
- });
- }
-
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: getAppStatus,
- data: {
- app: {
- __typename: 'AppData',
- status: EDITOR_APP_STATUS_LOADING,
- },
- },
- });
-
- const options = {
- localVue,
- mocks: {},
- apolloProvider: mockApollo,
- };
-
- createComponent({ provide, stubs, options });
-
- return waitForPromises();
- };
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findEditorHome = () => wrapper.findComponent(PipelineEditorHome);
- const findEmptyState = () => wrapper.findComponent(PipelineEditorEmptyState);
- const findEmptyStateButton = () => findEmptyState().findComponent(GlButton);
- const findValidationSegment = () => wrapper.findComponent(ValidationSegment);
-
- beforeEach(() => {
- mockBlobContentData = jest.fn();
- mockCiConfigData = jest.fn();
- mockGetTemplate = jest.fn();
- mockLatestCommitShaQuery = jest.fn();
- mockPipelineQuery = jest.fn();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('loading state', () => {
- it('displays a loading icon if the blob query is loading', () => {
- createComponent({ blobLoading: true });
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findEditorHome().exists()).toBe(false);
- });
- });
-
- describe('skipping queries', () => {
- describe('when branchName is undefined', () => {
- beforeEach(async () => {
- await createComponentWithApollo({ withUndefinedBranch: true });
- });
-
- it('does not calls getBlobContent', () => {
- expect(mockBlobContentData).not.toHaveBeenCalled();
- });
- });
-
- describe('when branchName is defined', () => {
- beforeEach(async () => {
- await createComponentWithApollo();
- });
-
- it('calls getBlobContent', () => {
- expect(mockBlobContentData).toHaveBeenCalled();
- });
- });
-
- describe('when commit sha is undefined', () => {
- beforeEach(async () => {
- mockLatestCommitShaQuery.mockResolvedValue(undefined);
- await createComponentWithApollo();
- });
-
- it('calls getBlobContent', () => {
- expect(mockBlobContentData).toHaveBeenCalled();
- });
-
- it('does not call ciConfigData', () => {
- expect(mockCiConfigData).not.toHaveBeenCalled();
- });
- });
-
- describe('when commit sha is defined', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
- await createComponentWithApollo();
- });
-
- it('calls ciConfigData', () => {
- expect(mockCiConfigData).toHaveBeenCalled();
- });
- });
- });
-
- describe('when queries are called', () => {
- beforeEach(() => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
- mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
- });
-
- describe('when project uses an external CI config file', () => {
- beforeEach(async () => {
- await createComponentWithApollo({
- provide: {
- usesExternalConfig: true,
- },
- });
- });
-
- it('shows an empty state and does not show editor home component', () => {
- expect(findEmptyState().exists()).toBe(true);
- expect(findAlert().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(false);
- });
- });
-
- describe('when file exists', () => {
- beforeEach(async () => {
- await createComponentWithApollo();
-
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
- .mockImplementation(jest.fn());
- });
-
- it('shows pipeline editor home component', () => {
- expect(findEditorHome().exists()).toBe(true);
- });
-
- it('no error is shown when data is set', () => {
- expect(findAlert().exists()).toBe(false);
- });
-
- it('ci config query is called with correct variables', async () => {
- expect(mockCiConfigData).toHaveBeenCalledWith({
- content: mockCiYml,
- projectPath: mockProjectFullPath,
- sha: mockCommitSha,
- });
- });
-
- it('does not poll for the commit sha', () => {
- expect(wrapper.vm.$apollo.queries.commitSha.startPolling).toHaveBeenCalledTimes(0);
- });
- });
-
- describe('when no CI config file exists', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
- await createComponentWithApollo({
- stubs: {
- PipelineEditorEmptyState,
- },
- });
-
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
- .mockImplementation(jest.fn());
- });
-
- it('shows an empty state and does not show editor home component', async () => {
- expect(findEmptyState().exists()).toBe(true);
- expect(findAlert().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(false);
- });
-
- it('does not poll for the commit sha', () => {
- expect(wrapper.vm.$apollo.queries.commitSha.startPolling).toHaveBeenCalledTimes(0);
- });
-
- describe('because of a fetching error', () => {
- it('shows a unkown error message', async () => {
- const loadUnknownFailureText = 'The CI configuration was not loaded, please try again.';
-
- mockBlobContentData.mockRejectedValueOnce();
- await createComponentWithApollo({
- stubs: {
- PipelineEditorMessages,
- },
- });
-
- expect(findEmptyState().exists()).toBe(false);
-
- expect(findAlert().text()).toBe(loadUnknownFailureText);
- expect(findEditorHome().exists()).toBe(true);
- });
- });
- });
-
- describe('with no CI config setup', () => {
- it('user can click on CTA button to get started', async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
- mockLatestCommitShaQuery.mockResolvedValue(mockEmptyCommitShaResults);
-
- await createComponentWithApollo({
- stubs: {
- PipelineEditorHome,
- PipelineEditorEmptyState,
- },
- });
-
- expect(findEmptyState().exists()).toBe(true);
- expect(findEditorHome().exists()).toBe(false);
-
- await findEmptyStateButton().vm.$emit('click');
-
- expect(findEmptyState().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(true);
- });
- });
-
- describe('when the lint query returns a 500 error', () => {
- beforeEach(async () => {
- mockCiConfigData.mockRejectedValueOnce(new Error(500));
- await createComponentWithApollo({
- stubs: { PipelineEditorHome, PipelineEditorHeader, ValidationSegment },
- });
- });
-
- it('shows that the lint service is down', () => {
- expect(findValidationSegment().text()).toContain(
- validationSegmenti18n.unavailableValidation,
- );
- });
-
- it('does not report an error or scroll to the top', () => {
- expect(findAlert().exists()).toBe(false);
- expect(window.scrollTo).not.toHaveBeenCalled();
- });
- });
-
- describe('when the user commits', () => {
- const updateFailureMessage = 'The GitLab CI configuration could not be updated.';
- const updateSuccessMessage = 'Your changes have been successfully committed.';
-
- describe('and the commit mutation succeeds', () => {
- beforeEach(async () => {
- window.scrollTo = jest.fn();
- await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
-
- findEditorHome().vm.$emit('commit', { type: COMMIT_SUCCESS });
- });
-
- it('shows a confirmation message', () => {
- expect(findAlert().text()).toBe(updateSuccessMessage);
- });
-
- it('scrolls to the top of the page to bring attention to the confirmation message', () => {
- expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
- });
-
- it('polls for commit sha while pipeline data is not yet available for current branch', async () => {
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
- .mockImplementation(jest.fn());
-
- // simulate a commit to the current branch
- findEditorHome().vm.$emit('updateCommitSha');
- await waitForPromises();
-
- expect(wrapper.vm.$apollo.queries.commitSha.startPolling).toHaveBeenCalledTimes(1);
- });
-
- it('stops polling for commit sha when pipeline data is available for newly committed branch', async () => {
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'stopPolling')
- .mockImplementation(jest.fn());
-
- mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
- await wrapper.vm.$apollo.queries.commitSha.refetch();
-
- expect(wrapper.vm.$apollo.queries.commitSha.stopPolling).toHaveBeenCalledTimes(1);
- });
-
- it('stops polling for commit sha when pipeline data is available for current branch', async () => {
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'stopPolling')
- .mockImplementation(jest.fn());
-
- mockLatestCommitShaQuery.mockResolvedValue(mockNewCommitShaResults);
- findEditorHome().vm.$emit('updateCommitSha');
- await waitForPromises();
-
- expect(wrapper.vm.$apollo.queries.commitSha.stopPolling).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when the commit succeeds with a redirect', () => {
- const newBranch = 'new-branch';
-
- beforeEach(async () => {
- await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
-
- findEditorHome().vm.$emit('commit', {
- type: COMMIT_SUCCESS_WITH_REDIRECT,
- params: { sourceBranch: newBranch, targetBranch: mockDefaultBranch },
- });
- });
-
- it('redirects to the merge request page with source and target branches', () => {
- const branchesQuery = objectToQuery({
- 'merge_request[source_branch]': newBranch,
- 'merge_request[target_branch]': mockDefaultBranch,
- });
-
- expect(redirectTo).toHaveBeenCalledWith(`${mockNewMergeRequestPath}?${branchesQuery}`);
- });
- });
-
- describe('and the commit mutation fails', () => {
- const commitFailedReasons = ['Commit failed'];
-
- beforeEach(async () => {
- window.scrollTo = jest.fn();
- await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
-
- findEditorHome().vm.$emit('showError', {
- type: COMMIT_FAILURE,
- reasons: commitFailedReasons,
- });
- });
-
- it('shows an error message', () => {
- expect(findAlert().text()).toMatchInterpolatedText(
- `${updateFailureMessage} ${commitFailedReasons[0]}`,
- );
- });
-
- it('scrolls to the top of the page to bring attention to the error message', () => {
- expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
- });
- });
-
- describe('when an unknown error occurs', () => {
- const unknownReasons = ['Commit failed'];
-
- beforeEach(async () => {
- window.scrollTo = jest.fn();
- await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
-
- findEditorHome().vm.$emit('showError', {
- type: COMMIT_FAILURE,
- reasons: unknownReasons,
- });
- });
-
- it('shows an error message', () => {
- expect(findAlert().text()).toMatchInterpolatedText(
- `${updateFailureMessage} ${unknownReasons[0]}`,
- );
- });
-
- it('scrolls to the top of the page to bring attention to the error message', () => {
- expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
- });
- });
- });
- });
-
- describe('when refetching content', () => {
- beforeEach(() => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
- mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
- });
-
- it('refetches blob content', async () => {
- await createComponentWithApollo();
- jest
- .spyOn(wrapper.vm.$apollo.queries.initialCiFileContent, 'refetch')
- .mockImplementation(jest.fn());
-
- expect(wrapper.vm.$apollo.queries.initialCiFileContent.refetch).toHaveBeenCalledTimes(0);
-
- await wrapper.vm.refetchContent();
-
- expect(wrapper.vm.$apollo.queries.initialCiFileContent.refetch).toHaveBeenCalledTimes(1);
- });
-
- it('hides start screen when refetch fetches CI file', async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
- await createComponentWithApollo();
-
- expect(findEmptyState().exists()).toBe(true);
- expect(findEditorHome().exists()).toBe(false);
-
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- await wrapper.vm.$apollo.queries.initialCiFileContent.refetch();
-
- expect(findEmptyState().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(true);
- });
- });
-
- describe('when a template parameter is present in the URL', () => {
- const originalLocation = window.location.href;
-
- beforeEach(() => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
- mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
- mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
- mockGetTemplate.mockResolvedValue(mockCiTemplateQueryResponse);
- setWindowLocation('?template=Android');
- });
-
- afterEach(() => {
- setWindowLocation(originalLocation);
- });
-
- it('renders the given template', async () => {
- await createComponentWithApollo({
- stubs: { PipelineEditorHome, PipelineEditorTabs },
- });
-
- expect(mockGetTemplate).toHaveBeenCalledWith({
- projectPath: mockProjectFullPath,
- templateName: 'Android',
- });
-
- expect(findEmptyState().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(true);
- });
- });
-
- describe('when add_new_config_file query param is present', () => {
- const originalLocation = window.location.href;
-
- beforeEach(() => {
- setWindowLocation('?add_new_config_file=true');
-
- mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
- });
-
- afterEach(() => {
- setWindowLocation(originalLocation);
- });
-
- describe('when CI config file does not exist', () => {
- beforeEach(async () => {
- mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
- mockLatestCommitShaQuery.mockResolvedValue(mockEmptyCommitShaResults);
- mockGetTemplate.mockResolvedValue(mockCiTemplateQueryResponse);
-
- await createComponentWithApollo();
-
- jest
- .spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
- .mockImplementation(jest.fn());
- });
-
- it('skips empty state and shows editor home component', () => {
- expect(findEmptyState().exists()).toBe(false);
- expect(findEditorHome().exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
deleted file mode 100644
index 2b06660c4b3..00000000000
--- a/spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
+++ /dev/null
@@ -1,330 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import { GlButton, GlDrawer, GlModal } from '@gitlab/ui';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import CiEditorHeader from '~/pipeline_editor/components/editor/ci_editor_header.vue';
-import CommitSection from '~/pipeline_editor/components/commit/commit_section.vue';
-import PipelineEditorDrawer from '~/pipeline_editor/components/drawer/pipeline_editor_drawer.vue';
-import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue';
-import PipelineEditorFileTree from '~/pipeline_editor/components/file_tree/container.vue';
-import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue';
-import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_editor_header.vue';
-import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
-import {
- CREATE_TAB,
- FILE_TREE_DISPLAY_KEY,
- VALIDATE_TAB,
- MERGED_TAB,
- TABS_INDEX,
- VISUALIZE_TAB,
-} from '~/pipeline_editor/constants';
-import PipelineEditorHome from '~/pipeline_editor/pipeline_editor_home.vue';
-
-import { mockLintResponse, mockCiYml } from './mock_data';
-
-jest.mock('~/lib/utils/common_utils');
-
-describe('Pipeline editor home wrapper', () => {
- let wrapper;
-
- const createComponent = ({ props = {}, glFeatures = {}, data = {}, stubs = {} } = {}) => {
- wrapper = extendedWrapper(
- shallowMount(PipelineEditorHome, {
- data: () => data,
- propsData: {
- ciConfigData: mockLintResponse,
- ciFileContent: mockCiYml,
- isCiConfigDataLoading: false,
- isNewCiConfigFile: false,
- ...props,
- },
- provide: {
- projectFullPath: '',
- totalBranches: 19,
- glFeatures: {
- ...glFeatures,
- },
- },
- stubs,
- }),
- );
- };
-
- const findBranchSwitcher = () => wrapper.findComponent(BranchSwitcher);
- const findCommitSection = () => wrapper.findComponent(CommitSection);
- const findFileNav = () => wrapper.findComponent(PipelineEditorFileNav);
- const findModal = () => wrapper.findComponent(GlModal);
- const findPipelineEditorDrawer = () => wrapper.findComponent(PipelineEditorDrawer);
- const findPipelineEditorFileTree = () => wrapper.findComponent(PipelineEditorFileTree);
- const findPipelineEditorHeader = () => wrapper.findComponent(PipelineEditorHeader);
- const findPipelineEditorTabs = () => wrapper.findComponent(PipelineEditorTabs);
- const findFileTreeBtn = () => wrapper.findByTestId('file-tree-toggle');
- const findHelpBtn = () => wrapper.findByTestId('drawer-toggle');
-
- afterEach(() => {
- localStorage.clear();
- wrapper.destroy();
- });
-
- describe('renders', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows the file nav', () => {
- expect(findFileNav().exists()).toBe(true);
- });
-
- it('shows the pipeline editor header', () => {
- expect(findPipelineEditorHeader().exists()).toBe(true);
- });
-
- it('shows the pipeline editor tabs', () => {
- expect(findPipelineEditorTabs().exists()).toBe(true);
- });
-
- it('shows the commit section by default', () => {
- expect(findCommitSection().exists()).toBe(true);
- });
- });
-
- describe('modal when switching branch', () => {
- describe('when `showSwitchBranchModal` value is false', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('is not visible', () => {
- expect(findModal().exists()).toBe(false);
- });
- });
- describe('when `showSwitchBranchModal` value is true', () => {
- beforeEach(() => {
- createComponent({
- data: { showSwitchBranchModal: true },
- stubs: { PipelineEditorFileNav },
- });
- });
-
- it('is visible', () => {
- expect(findModal().exists()).toBe(true);
- });
-
- it('pass down `shouldLoadNewBranch` to the branch switcher when primary is selected', async () => {
- expect(findBranchSwitcher().props('shouldLoadNewBranch')).toBe(false);
-
- await findModal().vm.$emit('primary');
-
- expect(findBranchSwitcher().props('shouldLoadNewBranch')).toBe(true);
- });
-
- it('closes the modal when secondary action is selected', async () => {
- expect(findModal().exists()).toBe(true);
-
- await findModal().vm.$emit('secondary');
-
- expect(findModal().exists()).toBe(false);
- });
- });
- });
-
- describe('commit form toggle', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it.each`
- tab | shouldShow
- ${MERGED_TAB} | ${false}
- ${VISUALIZE_TAB} | ${false}
- ${VALIDATE_TAB} | ${false}
- ${CREATE_TAB} | ${true}
- `(
- 'when the active tab is $tab the commit form is shown: $shouldShow',
- async ({ tab, shouldShow }) => {
- expect(findCommitSection().exists()).toBe(true);
-
- findPipelineEditorTabs().vm.$emit('set-current-tab', tab);
-
- await nextTick();
-
- expect(findCommitSection().isVisible()).toBe(shouldShow);
- },
- );
-
- it('shows the commit form again when coming back to the create tab', async () => {
- expect(findCommitSection().isVisible()).toBe(true);
-
- findPipelineEditorTabs().vm.$emit('set-current-tab', MERGED_TAB);
- await nextTick();
- expect(findCommitSection().isVisible()).toBe(false);
-
- findPipelineEditorTabs().vm.$emit('set-current-tab', CREATE_TAB);
- await nextTick();
- expect(findCommitSection().isVisible()).toBe(true);
- });
-
- describe('rendering with tab params', () => {
- it.each`
- tab | shouldShow
- ${MERGED_TAB} | ${false}
- ${VISUALIZE_TAB} | ${false}
- ${VALIDATE_TAB} | ${false}
- ${CREATE_TAB} | ${true}
- `(
- 'when the tab query param is $tab the commit form is shown: $shouldShow',
- async ({ tab, shouldShow }) => {
- setWindowLocation(`https://gitlab.test/ci/editor/?tab=${TABS_INDEX[tab]}`);
- await createComponent({ stubs: { PipelineEditorTabs } });
-
- expect(findCommitSection().isVisible()).toBe(shouldShow);
- },
- );
- });
- });
-
- describe('WalkthroughPopover events', () => {
- beforeEach(() => {
- createComponent();
- });
-
- describe('when "walkthrough-popover-cta-clicked" is emitted from pipeline editor tabs', () => {
- it('passes down `scrollToCommitForm=true` to commit section', async () => {
- expect(findCommitSection().props('scrollToCommitForm')).toBe(false);
- await findPipelineEditorTabs().vm.$emit('walkthrough-popover-cta-clicked');
- expect(findCommitSection().props('scrollToCommitForm')).toBe(true);
- });
- });
-
- describe('when "scrolled-to-commit-form" is emitted from commit section', () => {
- it('passes down `scrollToCommitForm=false` to commit section', async () => {
- await findPipelineEditorTabs().vm.$emit('walkthrough-popover-cta-clicked');
- expect(findCommitSection().props('scrollToCommitForm')).toBe(true);
- await findCommitSection().vm.$emit('scrolled-to-commit-form');
- expect(findCommitSection().props('scrollToCommitForm')).toBe(false);
- });
- });
- });
-
- describe('help drawer', () => {
- const clickHelpBtn = async () => {
- findHelpBtn().vm.$emit('click');
- await nextTick();
- };
-
- it('hides the drawer by default', () => {
- createComponent();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
- });
-
- it('toggles the drawer on button click', async () => {
- createComponent({
- stubs: {
- CiEditorHeader,
- GlButton,
- GlDrawer,
- PipelineEditorTabs,
- PipelineEditorDrawer,
- },
- });
-
- await clickHelpBtn();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(true);
-
- await clickHelpBtn();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
- });
-
- it("closes the drawer through the drawer's close button", async () => {
- createComponent({
- stubs: {
- CiEditorHeader,
- GlButton,
- GlDrawer,
- PipelineEditorTabs,
- PipelineEditorDrawer,
- },
- });
-
- await clickHelpBtn();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(true);
-
- findPipelineEditorDrawer().findComponent(GlDrawer).vm.$emit('close');
- await nextTick();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
- });
- });
-
- describe('file tree', () => {
- const toggleFileTree = async () => {
- findFileTreeBtn().vm.$emit('click');
- await nextTick();
- };
-
- describe('button toggle', () => {
- beforeEach(() => {
- createComponent({
- stubs: {
- GlButton,
- PipelineEditorFileNav,
- },
- });
- });
-
- it('shows button toggle', () => {
- expect(findFileTreeBtn().exists()).toBe(true);
- });
-
- it('toggles the drawer on button click', async () => {
- await toggleFileTree();
-
- expect(findPipelineEditorFileTree().exists()).toBe(true);
-
- await toggleFileTree();
-
- expect(findPipelineEditorFileTree().exists()).toBe(false);
- });
-
- it('sets the display state in local storage', async () => {
- await toggleFileTree();
-
- expect(localStorage.getItem(FILE_TREE_DISPLAY_KEY)).toBe('true');
-
- await toggleFileTree();
-
- expect(localStorage.getItem(FILE_TREE_DISPLAY_KEY)).toBe('false');
- });
- });
-
- describe('when file tree display state is saved in local storage', () => {
- beforeEach(() => {
- localStorage.setItem(FILE_TREE_DISPLAY_KEY, 'true');
- createComponent({
- stubs: { PipelineEditorFileNav },
- });
- });
-
- it('shows the file tree by default', () => {
- expect(findPipelineEditorFileTree().exists()).toBe(true);
- });
- });
-
- describe('when file tree display state is not saved in local storage', () => {
- beforeEach(() => {
- createComponent({
- stubs: { PipelineEditorFileNav },
- });
- });
-
- it('hides the file tree by default', () => {
- expect(findPipelineEditorFileTree().exists()).toBe(false);
- });
- });
- });
-});