diff options
Diffstat (limited to 'spec/frontend/jira_import')
-rw-r--r-- | spec/frontend/jira_import/components/jira_import_app_spec.js | 200 | ||||
-rw-r--r-- | spec/frontend/jira_import/components/jira_import_form_spec.js | 201 | ||||
-rw-r--r-- | spec/frontend/jira_import/mock_data.js | 16 |
3 files changed, 247 insertions, 170 deletions
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 64b4461d7b2..27314a0eb6e 100644 --- a/spec/frontend/jira_import/components/jira_import_app_spec.js +++ b/spec/frontend/jira_import/components/jira_import_app_spec.js @@ -1,21 +1,26 @@ import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; -import { mount, shallowMount } from '@vue/test-utils'; -import AxiosMockAdapter from 'axios-mock-adapter'; +import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; -import axios from '~/lib/utils/axios_utils'; 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 getJiraUserMappingMutation from '~/jira_import/queries/get_jira_user_mapping.mutation.graphql'; -import { imports, issuesPath, jiraIntegrationPath, jiraProjects, userMappings } from '../mock_data'; +import { + imports, + issuesPath, + jiraIntegrationPath, + jiraProjects, + projectId, + projectPath, +} from '../mock_data'; describe('JiraImportApp', () => { - let axiosMock; - let mutateSpy; let wrapper; + const inProgressIllustration = 'in-progress-illustration.svg'; + + const setupIllustration = 'setup-illustration.svg'; + const getFormComponent = () => wrapper.find(JiraImportForm); const getProgressComponent = () => wrapper.find(JiraImportProgress); @@ -29,28 +34,22 @@ describe('JiraImportApp', () => { const mountComponent = ({ isJiraConfigured = true, errorMessage = '', - selectedProject = 'MTG', showAlert = false, isInProgress = false, loading = false, - mutate = mutateSpy, - mountFunction = shallowMount, } = {}) => - mountFunction(JiraImportApp, { + shallowMount(JiraImportApp, { propsData: { - inProgressIllustration: 'in-progress-illustration.svg', + inProgressIllustration, isJiraConfigured, issuesPath, jiraIntegrationPath, - projectId: '5', - projectPath: 'gitlab-org/gitlab-test', - setupIllustration: 'setup-illustration.svg', + projectId, + projectPath, + setupIllustration, }, data() { return { - isSubmitting: false, - selectedProject, - userMappings, errorMessage, showAlert, jiraImportDetails: { @@ -64,26 +63,11 @@ describe('JiraImportApp', () => { mocks: { $apollo: { loading, - mutate, }, }, }); - beforeEach(() => { - axiosMock = new AxiosMockAdapter(axios); - mutateSpy = jest.fn(() => - Promise.resolve({ - data: { - jiraImportStart: { errors: [] }, - jiraImportUsers: { jiraUsers: [], errors: [] }, - }, - }), - ); - }); - afterEach(() => { - axiosMock.restore(); - mutateSpy.mockRestore(); wrapper.destroy(); wrapper = null; }); @@ -176,111 +160,84 @@ describe('JiraImportApp', () => { }); }); - describe('import in progress screen', () => { + describe('import setup component', () => { + beforeEach(() => { + wrapper = mountComponent({ isJiraConfigured: false }); + }); + + it('receives the illustration', () => { + expect(getSetupComponent().props('illustration')).toBe(setupIllustration); + }); + + it('receives the path to the Jira integration page', () => { + expect(getSetupComponent().props('jiraIntegrationPath')).toBe(jiraIntegrationPath); + }); + }); + + describe('import in progress component', () => { beforeEach(() => { wrapper = mountComponent({ isInProgress: true }); }); - it('shows the illustration', () => { - expect(getProgressComponent().props('illustration')).toBe('in-progress-illustration.svg'); + it('receives the illustration', () => { + expect(getProgressComponent().props('illustration')).toBe(inProgressIllustration); }); - it('shows the name of the most recent import initiator', () => { + it('receives the name of the most recent import initiator', () => { expect(getProgressComponent().props('importInitiator')).toBe('Jane Doe'); }); - it('shows the name of the most recent imported project', () => { + it('receives the name of the most recent imported project', () => { expect(getProgressComponent().props('importProject')).toBe('MTG'); }); - it('shows the time of the most recent import', () => { + it('receives the time of the most recent import', () => { expect(getProgressComponent().props('importTime')).toBe('2020-04-09T16:17:18+00:00'); }); - it('has the path to the issues page', () => { + it('receives the path to the issues page', () => { expect(getProgressComponent().props('issuesPath')).toBe('gitlab-org/gitlab-test/-/issues'); }); }); - describe('jira import form screen', () => { - describe('when selected project has been imported before', () => { - it('shows jira-import::MTG-3 label since project MTG has been imported 2 time before', () => { - wrapper = mountComponent(); - - expect(getFormComponent().props('importLabel')).toBe('jira-import::MTG-3'); - }); - - it('shows warning alert to explain project MTG has been imported 2 times before', () => { - wrapper = mountComponent({ mountFunction: mount }); - - expect(getAlert().text()).toBe( - 'You have imported from this project 2 times before. Each new import will create duplicate issues.', - ); - }); + describe('import form component', () => { + beforeEach(() => { + wrapper = mountComponent(); }); - describe('when selected project has not been imported before', () => { - beforeEach(() => { - wrapper = mountComponent({ selectedProject: 'MJP' }); - }); - - it('shows jira-import::MJP-1 label since project MJP has not been imported before', () => { - expect(getFormComponent().props('importLabel')).toBe('jira-import::MJP-1'); - }); - - it('does not show warning alert since project MJP has not been imported before', () => { - expect(getAlert().exists()).toBe(false); - }); + it('receives the illustration', () => { + expect(getFormComponent().props('issuesPath')).toBe(issuesPath); }); - }); - describe('initiating a Jira import', () => { - it('calls the mutation with the expected arguments', () => { - wrapper = mountComponent(); + it('receives the name of the most recent import initiator', () => { + expect(getFormComponent().props('jiraImports')).toEqual(imports); + }); - const mutationArguments = { - mutation: initiateJiraImportMutation, - variables: { - input: { - jiraProjectKey: 'MTG', - projectPath: 'gitlab-org/gitlab-test', - usersMapping: [ - { - jiraAccountId: 'aei23f98f-q23fj98qfj', - gitlabId: 15, - }, - { - jiraAccountId: 'fu39y8t34w-rq3u289t3h4i', - gitlabId: undefined, - }, - ], - }, - }, - }; + it('receives the name of the most recent imported project', () => { + expect(getFormComponent().props('jiraProjects')).toEqual(jiraProjects); + }); - getFormComponent().vm.$emit('initiateJiraImport', 'MTG'); + it('receives the project ID', () => { + expect(getFormComponent().props('projectId')).toBe(projectId); + }); - expect(mutateSpy).toHaveBeenCalledWith(expect.objectContaining(mutationArguments)); + it('receives the project path', () => { + expect(getFormComponent().props('projectPath')).toBe(projectPath); }); - it('shows alert message with error message on error', () => { - const mutate = jest.fn(() => Promise.reject()); + it('shows an alert when it emits an error', async () => { + expect(getAlert().exists()).toBe(false); - wrapper = mountComponent({ mutate }); + getFormComponent().vm.$emit('error', 'There was an error'); - getFormComponent().vm.$emit('initiateJiraImport', 'MTG'); + await Vue.nextTick(); - // 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.'); - }); + expect(getAlert().exists()).toBe(true); }); }); describe('alert', () => { - it('can be dismissed', () => { + it('can be dismissed', async () => { wrapper = mountComponent({ errorMessage: 'There was an error importing the Jira project.', showAlert: true, @@ -291,40 +248,9 @@ describe('JiraImportApp', () => { getAlert().vm.$emit('dismiss'); - return Vue.nextTick().then(() => { - expect(getAlert().exists()).toBe(false); - }); - }); - }); - - describe('on mount', () => { - it('makes a GraphQL mutation call to get user mappings', () => { - wrapper = mountComponent(); + await Vue.nextTick(); - const mutationArguments = { - mutation: getJiraUserMappingMutation, - variables: { - input: { - projectPath: 'gitlab-org/gitlab-test', - }, - }, - }; - - expect(mutateSpy).toHaveBeenCalledWith(expect.objectContaining(mutationArguments)); - }); - - it('does not make a GraphQL mutation call to get user mappings when Jira is not configured', () => { - wrapper = mountComponent({ isJiraConfigured: false }); - - expect(mutateSpy).not.toHaveBeenCalled(); - }); - - it('shows error message when there is an error with the GraphQL mutation call', () => { - const mutate = jest.fn(() => Promise.reject()); - - wrapper = mountComponent({ mutate }); - - expect(getAlert().exists()).toBe(true); + 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 685b0288e92..7cc7b40f4c8 100644 --- a/spec/frontend/jira_import/components/jira_import_form_spec.js +++ b/spec/frontend/jira_import/components/jira_import_form_spec.js @@ -1,56 +1,97 @@ -import { GlButton, GlFormSelect, GlLabel, GlTable } from '@gitlab/ui'; +import { GlAlert, GlButton, GlNewDropdown, GlFormSelect, GlLabel, GlTable } from '@gitlab/ui'; import { getByRole } from '@testing-library/dom'; import { mount, shallowMount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import JiraImportForm from '~/jira_import/components/jira_import_form.vue'; -import { issuesPath, jiraProjects, userMappings } from '../mock_data'; +import getJiraUserMappingMutation from '~/jira_import/queries/get_jira_user_mapping.mutation.graphql'; +import initiateJiraImportMutation from '~/jira_import/queries/initiate_jira_import.mutation.graphql'; +import { + imports, + issuesPath, + jiraProjects, + projectId, + projectPath, + userMappings as defaultUserMappings, +} from '../mock_data'; describe('JiraImportForm', () => { let axiosMock; + let mutateSpy; let wrapper; const currentUsername = 'mrgitlab'; - const importLabel = 'jira-import::MTG-1'; - const value = 'MTG'; + + const getAlert = () => wrapper.find(GlAlert); const getSelectDropdown = () => wrapper.find(GlFormSelect); + const getContinueButton = () => wrapper.find(GlButton); + const getCancelButton = () => wrapper.findAll(GlButton).at(1); + const getLabel = () => wrapper.find(GlLabel); + + const getTable = () => wrapper.find(GlTable); + + const getUserDropdown = () => getTable().find(GlNewDropdown); + const getHeader = name => getByRole(wrapper.element, 'columnheader', { name }); - const mountComponent = ({ isSubmitting = false, mountFunction = shallowMount } = {}) => + const mountComponent = ({ + isSubmitting = false, + loading = false, + mutate = mutateSpy, + selectedProject = 'MTG', + userMappings = defaultUserMappings, + mountFunction = shallowMount, + } = {}) => mountFunction(JiraImportForm, { propsData: { - importLabel, - isSubmitting, issuesPath, + jiraImports: imports, jiraProjects, - projectId: '5', - userMappings, - value, + projectId, + projectPath, }, data: () => ({ isFetching: false, + isSubmitting, searchTerm: '', + selectedProject, selectState: null, users: [], + userMappings, }), + mocks: { + $apollo: { + loading, + mutate, + }, + }, currentUsername, }); beforeEach(() => { axiosMock = new AxiosMockAdapter(axios); + mutateSpy = jest.fn(() => + Promise.resolve({ + data: { + jiraImportStart: { errors: [] }, + jiraImportUsers: { jiraUsers: [], errors: [] }, + }, + }), + ); }); afterEach(() => { axiosMock.restore(); + mutateSpy.mockRestore(); wrapper.destroy(); wrapper = null; }); - describe('select dropdown', () => { + describe('select dropdown project selection', () => { it('is shown', () => { wrapper = mountComponent(); @@ -67,12 +108,34 @@ describe('JiraImportForm', () => { }); }); - it('emits an "input" event when the input select value changes', () => { - wrapper = mountComponent(); + describe('when selected project has been imported before', () => { + it('shows jira-import::MTG-3 label since project MTG has been imported 2 time before', () => { + wrapper = mountComponent(); + + expect(getLabel().props('title')).toBe('jira-import::MTG-3'); + }); + + it('shows warning alert to explain project MTG has been imported 2 times before', () => { + wrapper = mountComponent({ mountFunction: mount }); + + expect(getAlert().text()).toBe( + 'You have imported from this project 2 times before. Each new import will create duplicate issues.', + ); + }); + }); + + describe('when selected project has not been imported before', () => { + beforeEach(() => { + wrapper = mountComponent({ selectedProject: 'MJP' }); + }); - getSelectDropdown().vm.$emit('change', value); + it('shows jira-import::MJP-1 label since project MJP has not been imported before', () => { + expect(getLabel().props('title')).toBe('jira-import::MJP-1'); + }); - expect(wrapper.emitted('input')[0]).toEqual([value]); + it('does not show warning alert since project MJP has not been imported before', () => { + expect(getAlert().exists()).toBe(false); + }); }); }); @@ -81,10 +144,6 @@ describe('JiraImportForm', () => { wrapper = mountComponent(); }); - it('shows a label which will be applied to imported Jira projects', () => { - expect(wrapper.find(GlLabel).props('title')).toBe(importLabel); - }); - it('shows a heading for the user mapping section', () => { expect( getByRole(wrapper.element, 'heading', { name: 'Jira-GitLab user mapping template' }), @@ -93,7 +152,7 @@ describe('JiraImportForm', () => { it('shows information to the user', () => { expect(wrapper.find('p').text()).toBe( - 'Jira users have been matched with similar GitLab users. This can be overwritten by selecting a GitLab user from the dropdown in the "GitLab username" column. If it wasn\'t possible to match a Jira user with a GitLab user, the dropdown defaults to the user conducting the import.', + 'Jira users have been imported from the configured Jira instance. They can be mapped by selecting a GitLab user from the dropdown in the "GitLab username" column. When the form appears, the dropdown defaults to the user conducting the import.', ); }); }); @@ -121,13 +180,53 @@ describe('JiraImportForm', () => { it('shows all user mappings', () => { wrapper = mountComponent({ mountFunction: mount }); - expect(wrapper.find(GlTable).findAll('tbody tr').length).toBe(userMappings.length); + expect(getTable().findAll('tbody tr')).toHaveLength(2); }); it('shows correct information in each cell', () => { wrapper = mountComponent({ mountFunction: mount }); - expect(wrapper.find(GlTable).element).toMatchSnapshot(); + expect(getTable().element).toMatchSnapshot(); + }); + + describe('when there is no Jira->GitLab user mapping', () => { + it('shows the logged in user in the dropdown', () => { + wrapper = mountComponent({ + mountFunction: mount, + userMappings: [ + { + jiraAccountId: 'aei23f98f-q23fj98qfj', + jiraDisplayName: 'Jane Doe', + jiraEmail: 'janedoe@example.com', + gitlabId: undefined, + gitlabUsername: undefined, + }, + ], + }); + + expect(getUserDropdown().text()).toContain(currentUsername); + }); + }); + + describe('when there is a Jira->GitLab user mapping', () => { + it('shows the mapped user in the dropdown', () => { + const gitlabUsername = 'mai'; + + wrapper = mountComponent({ + mountFunction: mount, + userMappings: [ + { + jiraAccountId: 'aei23f98f-q23fj98qfj', + jiraDisplayName: 'Jane Doe', + jiraEmail: 'janedoe@example.com', + gitlabId: 14, + gitlabUsername, + }, + ], + }); + + expect(getUserDropdown().text()).toContain(gitlabUsername); + }); }); }); }); @@ -137,13 +236,13 @@ describe('JiraImportForm', () => { it('is shown', () => { wrapper = mountComponent(); - expect(wrapper.find(GlButton).text()).toBe('Continue'); + expect(getContinueButton().text()).toBe('Continue'); }); it('is in loading state when the form is submitting', async () => { wrapper = mountComponent({ isSubmitting: true }); - expect(wrapper.find(GlButton).props('loading')).toBe(true); + expect(getContinueButton().props('loading')).toBe(true); }); }); @@ -162,13 +261,61 @@ describe('JiraImportForm', () => { }); }); - describe('form', () => { - it('emits an "initiateJiraImport" event with the selected dropdown value when submitted', () => { + describe('submitting the form', () => { + it('initiates the Jira import mutation with the expected arguments', () => { wrapper = mountComponent(); + const mutationArguments = { + mutation: initiateJiraImportMutation, + variables: { + input: { + jiraProjectKey: 'MTG', + projectPath, + usersMapping: [ + { + jiraAccountId: 'aei23f98f-q23fj98qfj', + gitlabId: 15, + }, + { + jiraAccountId: 'fu39y8t34w-rq3u289t3h4i', + gitlabId: undefined, + }, + ], + }, + }, + }; + wrapper.find('form').trigger('submit'); - expect(wrapper.emitted('initiateJiraImport')[0]).toEqual([value]); + expect(mutateSpy).toHaveBeenCalledWith(expect.objectContaining(mutationArguments)); + }); + }); + + describe('on mount GraphQL user mapping mutation', () => { + it('is called with the expected arguments', () => { + wrapper = mountComponent(); + + const mutationArguments = { + mutation: getJiraUserMappingMutation, + variables: { + input: { + projectPath, + }, + }, + }; + + expect(mutateSpy).toHaveBeenCalledWith(expect.objectContaining(mutationArguments)); + }); + + describe('when there is an error when called', () => { + beforeEach(() => { + const mutate = jest.fn(() => Promise.reject()); + wrapper = mountComponent({ mutate }); + }); + + it('shows error message', () => { + expect(getAlert().exists()).toBe(true); + }); }); }); }); diff --git a/spec/frontend/jira_import/mock_data.js b/spec/frontend/jira_import/mock_data.js index a7447221b15..8ea40080f32 100644 --- a/spec/frontend/jira_import/mock_data.js +++ b/spec/frontend/jira_import/mock_data.js @@ -3,6 +3,16 @@ import { IMPORT_STATE } from '~/jira_import/utils/jira_import_utils'; export const fullPath = 'gitlab-org/gitlab-test'; +export const issuesPath = 'gitlab-org/gitlab-test/-/issues'; + +export const illustration = 'illustration.svg'; + +export const jiraIntegrationPath = 'gitlab-org/gitlab-test/-/services/jira/edit'; + +export const projectId = '5'; + +export const projectPath = 'gitlab-org/gitlab-test'; + export const queryDetails = { query: getJiraImportDetailsQuery, variables: { @@ -71,12 +81,6 @@ export const jiraImportMutationResponse = { }, }; -export const issuesPath = 'gitlab-org/gitlab-test/-/issues'; - -export const jiraIntegrationPath = 'gitlab-org/gitlab-test/-/services/jira/edit'; - -export const illustration = 'illustration.svg'; - export const jiraProjects = [ { text: 'My Jira Project (MJP)', value: 'MJP' }, { text: 'My Second Jira Project (MSJP)', value: 'MSJP' }, |