From 983a0bba5d2a042c4a3bbb22432ec192c7501d82 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 20 Apr 2020 18:38:24 +0000 Subject: Add latest changes from gitlab-org/gitlab@12-10-stable-ee --- .../jira_import/components/jira_import_app_spec.js | 207 +++++++++++++++++++-- .../components/jira_import_form_spec.js | 136 ++++++++++---- .../components/jira_import_progress_spec.js | 70 +++++++ .../components/jira_import_setup_spec.js | 17 +- spec/frontend/jira_import/utils_spec.js | 27 +++ 5 files changed, 400 insertions(+), 57 deletions(-) create mode 100644 spec/frontend/jira_import/components/jira_import_progress_spec.js create mode 100644 spec/frontend/jira_import/utils_spec.js (limited to 'spec/frontend/jira_import') diff --git a/spec/frontend/jira_import/components/jira_import_app_spec.js b/spec/frontend/jira_import/components/jira_import_app_spec.js index fb3ffe1ede3..ce32559d5c9 100644 --- a/spec/frontend/jira_import/components/jira_import_app_spec.js +++ b/spec/frontend/jira_import/components/jira_import_app_spec.js @@ -1,38 +1,213 @@ +import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; import JiraImportApp from '~/jira_import/components/jira_import_app.vue'; +import JiraImportForm from '~/jira_import/components/jira_import_form.vue'; +import JiraImportProgress from '~/jira_import/components/jira_import_progress.vue'; import JiraImportSetup from '~/jira_import/components/jira_import_setup.vue'; +import initiateJiraImportMutation from '~/jira_import/queries/initiate_jira_import.mutation.graphql'; +import { IMPORT_STATE } from '~/jira_import/utils'; + +const mountComponent = ({ + isJiraConfigured = true, + errorMessage = '', + showAlert = true, + status = IMPORT_STATE.NONE, + loading = false, + mutate = jest.fn(() => Promise.resolve()), +} = {}) => + shallowMount(JiraImportApp, { + propsData: { + isJiraConfigured, + inProgressIllustration: 'in-progress-illustration.svg', + issuesPath: 'gitlab-org/gitlab-test/-/issues', + jiraProjects: [ + ['My Jira Project', 'MJP'], + ['My Second Jira Project', 'MSJP'], + ['Migrate to GitLab', 'MTG'], + ], + projectPath: 'gitlab-org/gitlab-test', + setupIllustration: 'setup-illustration.svg', + }, + data() { + return { + errorMessage, + showAlert, + jiraImportDetails: { + status, + import: { + jiraProjectKey: 'MTG', + scheduledAt: '2020-04-08T12:17:25+00:00', + scheduledBy: { + name: 'Jane Doe', + }, + }, + }, + }; + }, + mocks: { + $apollo: { + loading, + mutate, + }, + }, + }); describe('JiraImportApp', () => { let wrapper; + const getFormComponent = () => wrapper.find(JiraImportForm); + + const getProgressComponent = () => wrapper.find(JiraImportProgress); + + const getSetupComponent = () => wrapper.find(JiraImportSetup); + + const getAlert = () => wrapper.find(GlAlert); + + const getLoadingIcon = () => wrapper.find(GlLoadingIcon); + afterEach(() => { wrapper.destroy(); wrapper = null; }); - describe('set up Jira integration page', () => { + describe('when Jira integration is not configured', () => { + beforeEach(() => { + wrapper = mountComponent({ isJiraConfigured: false }); + }); + + it('shows the "Set up Jira integration" screen', () => { + expect(getSetupComponent().exists()).toBe(true); + }); + + it('does not show loading icon', () => { + expect(getLoadingIcon().exists()).toBe(false); + }); + + it('does not show the "Import in progress" screen', () => { + expect(getProgressComponent().exists()).toBe(false); + }); + + it('does not show the "Import Jira project" form', () => { + expect(getFormComponent().exists()).toBe(false); + }); + }); + + describe('when Jira integration is configured but data is being fetched', () => { + beforeEach(() => { + wrapper = mountComponent({ loading: true }); + }); + + it('does not show the "Set up Jira integration" screen', () => { + expect(getSetupComponent().exists()).toBe(false); + }); + + it('shows loading icon', () => { + expect(getLoadingIcon().exists()).toBe(true); + }); + + it('does not show the "Import in progress" screen', () => { + expect(getProgressComponent().exists()).toBe(false); + }); + + it('does not show the "Import Jira project" form', () => { + expect(getFormComponent().exists()).toBe(false); + }); + }); + + describe('when Jira integration is configured but import is in progress', () => { + beforeEach(() => { + wrapper = mountComponent({ status: IMPORT_STATE.SCHEDULED }); + }); + + it('does not show the "Set up Jira integration" screen', () => { + expect(getSetupComponent().exists()).toBe(false); + }); + + it('does not show loading icon', () => { + expect(getLoadingIcon().exists()).toBe(false); + }); + + it('shows the "Import in progress" screen', () => { + expect(getProgressComponent().exists()).toBe(true); + }); + + it('does not show the "Import Jira project" form', () => { + expect(getFormComponent().exists()).toBe(false); + }); + }); + + describe('when Jira integration is configured and there is no import in progress', () => { beforeEach(() => { - wrapper = shallowMount(JiraImportApp, { - propsData: { - isJiraConfigured: true, - projectPath: 'gitlab-org/gitlab-test', - setupIllustration: 'illustration.svg', + wrapper = mountComponent(); + }); + + it('does not show the "Set up Jira integration" screen', () => { + expect(getSetupComponent().exists()).toBe(false); + }); + + it('does not show loading icon', () => { + expect(getLoadingIcon().exists()).toBe(false); + }); + + it('does not show the Import in progress" screen', () => { + expect(getProgressComponent().exists()).toBe(false); + }); + + it('shows the "Import Jira project" form', () => { + expect(getFormComponent().exists()).toBe(true); + }); + }); + + describe('initiating a Jira import', () => { + it('calls the mutation with the expected arguments', () => { + const mutate = jest.fn(() => Promise.resolve()); + + wrapper = mountComponent({ mutate }); + + const mutationArguments = { + mutation: initiateJiraImportMutation, + variables: { + input: { + jiraProjectKey: 'MTG', + projectPath: 'gitlab-org/gitlab-test', + }, }, - }); + }; + + getFormComponent().vm.$emit('initiateJiraImport', 'MTG'); + + expect(mutate).toHaveBeenCalledWith(expect.objectContaining(mutationArguments)); }); - it('is shown when Jira integration is not configured', () => { - wrapper.setProps({ - isJiraConfigured: false, - }); + it('shows alert message with error message on error', () => { + const mutate = jest.fn(() => Promise.reject()); + + wrapper = mountComponent({ mutate }); + + getFormComponent().vm.$emit('initiateJiraImport', 'MTG'); + + // One tick doesn't update the dom to the desired state so we have two ticks here + return Vue.nextTick() + .then(Vue.nextTick) + .then(() => { + expect(getAlert().text()).toBe('There was an error importing the Jira project.'); + }); + }); + }); - return wrapper.vm.$nextTick(() => { - expect(wrapper.find(JiraImportSetup).exists()).toBe(true); - }); + it('can dismiss alert message', () => { + wrapper = mountComponent({ + errorMessage: 'There was an error importing the Jira project.', + showAlert: true, }); - it('is not shown when Jira integration is configured', () => { - expect(wrapper.find(JiraImportSetup).exists()).toBe(false); + expect(getAlert().exists()).toBe(true); + + getAlert().vm.$emit('dismiss'); + + return Vue.nextTick().then(() => { + expect(getAlert().exists()).toBe(false); }); }); }); diff --git a/spec/frontend/jira_import/components/jira_import_form_spec.js b/spec/frontend/jira_import/components/jira_import_form_spec.js index 315ccccd991..0987eb11693 100644 --- a/spec/frontend/jira_import/components/jira_import_form_spec.js +++ b/spec/frontend/jira_import/components/jira_import_form_spec.js @@ -1,62 +1,126 @@ -import { GlAvatar, GlNewButton, GlFormSelect, GlLabel } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; +import { GlAvatar, GlButton, GlFormSelect, GlLabel } from '@gitlab/ui'; +import { mount, shallowMount } from '@vue/test-utils'; import JiraImportForm from '~/jira_import/components/jira_import_form.vue'; +const mountComponent = ({ mountType } = {}) => { + const mountFunction = mountType === 'mount' ? mount : shallowMount; + + return mountFunction(JiraImportForm, { + propsData: { + issuesPath: 'gitlab-org/gitlab-test/-/issues', + jiraProjects: [ + { + text: 'My Jira Project', + value: 'MJP', + }, + { + text: 'My Second Jira Project', + value: 'MSJP', + }, + { + text: 'Migrate to GitLab', + value: 'MTG', + }, + ], + }, + }); +}; + describe('JiraImportForm', () => { let wrapper; - beforeEach(() => { - wrapper = shallowMount(JiraImportForm); - }); + const getCancelButton = () => wrapper.findAll(GlButton).at(1); afterEach(() => { wrapper.destroy(); wrapper = null; }); - it('shows a dropdown to choose the Jira project to import from', () => { - expect(wrapper.find(GlFormSelect).exists()).toBe(true); - }); + describe('select dropdown', () => { + it('is shown', () => { + wrapper = mountComponent(); - it('shows a label which will be applied to imported Jira projects', () => { - expect(wrapper.find(GlLabel).attributes('title')).toBe('jira-import::KEY-1'); - }); + expect(wrapper.find(GlFormSelect).exists()).toBe(true); + }); - it('shows information to the user', () => { - expect(wrapper.find('p').text()).toBe( - "For each Jira issue successfully imported, we'll create a new GitLab issue with the following data:", - ); - }); + it('contains a list of Jira projects to select from', () => { + wrapper = mountComponent({ mountType: 'mount' }); - it('shows jira.issue.summary for the Title', () => { - expect(wrapper.find('[id="jira-project-title"]').text()).toBe('jira.issue.summary'); + const optionItems = ['My Jira Project', 'My Second Jira Project', 'Migrate to GitLab']; + + wrapper + .find(GlFormSelect) + .findAll('option') + .wrappers.forEach((optionEl, index) => { + expect(optionEl.text()).toBe(optionItems[index]); + }); + }); }); - it('shows an avatar for the Reporter', () => { - expect(wrapper.find(GlAvatar).exists()).toBe(true); + describe('form information', () => { + beforeEach(() => { + wrapper = mountComponent(); + }); + + it('shows a label which will be applied to imported Jira projects', () => { + expect(wrapper.find(GlLabel).attributes('title')).toBe('jira-import::KEY-1'); + }); + + it('shows information to the user', () => { + expect(wrapper.find('p').text()).toBe( + "For each Jira issue successfully imported, we'll create a new GitLab issue with the following data:", + ); + }); + + it('shows jira.issue.summary for the Title', () => { + expect(wrapper.find('[id="jira-project-title"]').text()).toBe('jira.issue.summary'); + }); + + it('shows an avatar for the Reporter', () => { + expect(wrapper.find(GlAvatar).exists()).toBe(true); + }); + + it('shows jira.issue.description.content for the Description', () => { + expect(wrapper.find('[id="jira-project-description"]').text()).toBe( + 'jira.issue.description.content', + ); + }); }); - it('shows jira.issue.description.content for the Description', () => { - expect(wrapper.find('[id="jira-project-description"]').text()).toBe( - 'jira.issue.description.content', - ); + describe('Next button', () => { + beforeEach(() => { + wrapper = mountComponent(); + }); + + it('is shown', () => { + expect(wrapper.find(GlButton).text()).toBe('Next'); + }); }); - it('shows a Next button', () => { - const nextButton = wrapper - .findAll(GlNewButton) - .at(0) - .text(); + describe('Cancel button', () => { + beforeEach(() => { + wrapper = mountComponent(); + }); + + it('is shown', () => { + expect(getCancelButton().text()).toBe('Cancel'); + }); - expect(nextButton).toBe('Next'); + it('links to the Issues page', () => { + expect(getCancelButton().attributes('href')).toBe('gitlab-org/gitlab-test/-/issues'); + }); }); - it('shows a Cancel button', () => { - const cancelButton = wrapper - .findAll(GlNewButton) - .at(1) - .text(); + it('emits an "initiateJiraImport" event with the selected dropdown value when submitted', () => { + const selectedOption = 'MTG'; + + wrapper = mountComponent(); + wrapper.setData({ + selectedOption, + }); + + wrapper.find('form').trigger('submit'); - expect(cancelButton).toBe('Cancel'); + expect(wrapper.emitted('initiateJiraImport')[0]).toEqual([selectedOption]); }); }); diff --git a/spec/frontend/jira_import/components/jira_import_progress_spec.js b/spec/frontend/jira_import/components/jira_import_progress_spec.js new file mode 100644 index 00000000000..9a6fc3b5925 --- /dev/null +++ b/spec/frontend/jira_import/components/jira_import_progress_spec.js @@ -0,0 +1,70 @@ +import { GlEmptyState } from '@gitlab/ui'; +import { mount, shallowMount } from '@vue/test-utils'; +import JiraImportProgress from '~/jira_import/components/jira_import_progress.vue'; + +describe('JiraImportProgress', () => { + let wrapper; + + const getGlEmptyStateAttribute = attribute => wrapper.find(GlEmptyState).attributes(attribute); + + const getParagraphText = () => wrapper.find('p').text(); + + const mountComponent = ({ mountType = 'shallowMount' } = {}) => { + const mountFunction = mountType === 'shallowMount' ? shallowMount : mount; + return mountFunction(JiraImportProgress, { + propsData: { + illustration: 'illustration.svg', + importInitiator: 'Jane Doe', + importProject: 'JIRAPROJECT', + importTime: '2020-04-08T12:17:25+00:00', + issuesPath: 'gitlab-org/gitlab-test/-/issues', + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('empty state', () => { + beforeEach(() => { + wrapper = mountComponent(); + }); + + it('contains illustration', () => { + expect(getGlEmptyStateAttribute('svgpath')).toBe('illustration.svg'); + }); + + it('contains a title', () => { + const title = 'Import in progress'; + expect(getGlEmptyStateAttribute('title')).toBe(title); + }); + + it('contains button text', () => { + expect(getGlEmptyStateAttribute('primarybuttontext')).toBe('View issues'); + }); + + it('contains button url', () => { + expect(getGlEmptyStateAttribute('primarybuttonlink')).toBe('gitlab-org/gitlab-test/-/issues'); + }); + }); + + describe('description', () => { + beforeEach(() => { + wrapper = mountComponent({ mountType: 'mount' }); + }); + + it('shows who initiated the import', () => { + expect(getParagraphText()).toContain('Import started by: Jane Doe'); + }); + + it('shows the time of import', () => { + expect(getParagraphText()).toContain('Time of import: Apr 8, 2020 12:17pm GMT+0000'); + }); + + it('shows the project key of the import', () => { + expect(getParagraphText()).toContain('Jira project: JIRAPROJECT'); + }); + }); +}); diff --git a/spec/frontend/jira_import/components/jira_import_setup_spec.js b/spec/frontend/jira_import/components/jira_import_setup_spec.js index 27366bd7e8a..834c14b512e 100644 --- a/spec/frontend/jira_import/components/jira_import_setup_spec.js +++ b/spec/frontend/jira_import/components/jira_import_setup_spec.js @@ -1,9 +1,12 @@ +import { GlEmptyState } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import JiraImportSetup from '~/jira_import/components/jira_import_setup.vue'; describe('JiraImportSetup', () => { let wrapper; + const getGlEmptyStateAttribute = attribute => wrapper.find(GlEmptyState).attributes(attribute); + beforeEach(() => { wrapper = shallowMount(JiraImportSetup, { propsData: { @@ -17,12 +20,16 @@ describe('JiraImportSetup', () => { wrapper = null; }); - it('displays a message to the user', () => { - const message = 'You will first need to set up Jira Integration to use this feature.'; - expect(wrapper.find('p').text()).toBe(message); + it('contains illustration', () => { + expect(getGlEmptyStateAttribute('svgpath')).toBe('illustration.svg'); + }); + + it('contains a description', () => { + const description = 'You will first need to set up Jira Integration to use this feature.'; + expect(getGlEmptyStateAttribute('description')).toBe(description); }); - it('contains button to set up Jira integration', () => { - expect(wrapper.find('a').text()).toBe('Set up Jira Integration'); + it('contains button text', () => { + expect(getGlEmptyStateAttribute('primarybuttontext')).toBe('Set up Jira Integration'); }); }); diff --git a/spec/frontend/jira_import/utils_spec.js b/spec/frontend/jira_import/utils_spec.js new file mode 100644 index 00000000000..a14db104229 --- /dev/null +++ b/spec/frontend/jira_import/utils_spec.js @@ -0,0 +1,27 @@ +import { IMPORT_STATE, isInProgress } from '~/jira_import/utils'; + +describe('isInProgress', () => { + it('returns true when state is IMPORT_STATE.SCHEDULED', () => { + expect(isInProgress(IMPORT_STATE.SCHEDULED)).toBe(true); + }); + + it('returns true when state is IMPORT_STATE.STARTED', () => { + expect(isInProgress(IMPORT_STATE.STARTED)).toBe(true); + }); + + it('returns false when state is IMPORT_STATE.FAILED', () => { + expect(isInProgress(IMPORT_STATE.FAILED)).toBe(false); + }); + + it('returns false when state is IMPORT_STATE.FINISHED', () => { + expect(isInProgress(IMPORT_STATE.FINISHED)).toBe(false); + }); + + it('returns false when state is IMPORT_STATE.NONE', () => { + expect(isInProgress(IMPORT_STATE.NONE)).toBe(false); + }); + + it('returns false when state is undefined', () => { + expect(isInProgress()).toBe(false); + }); +}); -- cgit v1.2.3