diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-18 10:34:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-18 10:34:06 +0000 |
commit | 859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch) | |
tree | d7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /spec/frontend/projects | |
parent | 446d496a6d000c73a304be52587cd9bbc7493136 (diff) | |
download | gitlab-ce-859a6fb938bb9ee2a317c46dfa4fcc1af49608f0.tar.gz |
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'spec/frontend/projects')
23 files changed, 677 insertions, 474 deletions
diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js index 9fa7d658405..7686c28c7fc 100644 --- a/spec/frontend/projects/commit/components/branches_dropdown_spec.js +++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js @@ -1,8 +1,8 @@ +import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; -import { shallowMount } from '@vue/test-utils'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue'; Vue.use(Vuex); diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js index 1c37b82fed3..1569f5b4bbe 100644 --- a/spec/frontend/projects/commit/components/form_modal_spec.js +++ b/spec/frontend/projects/commit/components/form_modal_spec.js @@ -1,12 +1,13 @@ -import MockAdapter from 'axios-mock-adapter'; -import { shallowMount, mount, createWrapper } from '@vue/test-utils'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { GlModal, GlForm, GlFormCheckbox, GlSprintf } from '@gitlab/ui'; import { within } from '@testing-library/dom'; +import { shallowMount, mount, createWrapper } from '@vue/test-utils'; +import MockAdapter from 'axios-mock-adapter'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import axios from '~/lib/utils/axios_utils'; -import eventHub from '~/projects/commit/event_hub'; -import CommitFormModal from '~/projects/commit/components/form_modal.vue'; +import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue'; +import CommitFormModal from '~/projects/commit/components/form_modal.vue'; +import eventHub from '~/projects/commit/event_hub'; import createStore from '~/projects/commit/store'; import mockData from '../mock_data'; @@ -64,7 +65,7 @@ describe('CommitFormModal', () => { wrapper.vm.show(); - expect(rootEmit).toHaveBeenCalledWith('bv::show::modal', mockData.modalPropsData.modalId); + expect(rootEmit).toHaveBeenCalledWith(BV_SHOW_MODAL, mockData.modalPropsData.modalId); }); it('Clears the modal state once modal is hidden', () => { diff --git a/spec/frontend/projects/commit/components/form_trigger_spec.js b/spec/frontend/projects/commit/components/form_trigger_spec.js index ca51419d6a5..4503493c0a6 100644 --- a/spec/frontend/projects/commit/components/form_trigger_spec.js +++ b/spec/frontend/projects/commit/components/form_trigger_spec.js @@ -1,5 +1,5 @@ -import { shallowMount } from '@vue/test-utils'; import { GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import FormTrigger from '~/projects/commit/components/form_trigger.vue'; import eventHub from '~/projects/commit/event_hub'; diff --git a/spec/frontend/projects/commit/store/actions_spec.js b/spec/frontend/projects/commit/store/actions_spec.js index ec528d4ee88..458372229cf 100644 --- a/spec/frontend/projects/commit/store/actions_spec.js +++ b/spec/frontend/projects/commit/store/actions_spec.js @@ -1,12 +1,12 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import axios from '~/lib/utils/axios_utils'; import createFlash from '~/flash'; -import getInitialState from '~/projects/commit/store/state'; +import axios from '~/lib/utils/axios_utils'; +import { PROJECT_BRANCHES_ERROR } from '~/projects/commit/constants'; import * as actions from '~/projects/commit/store/actions'; import * as types from '~/projects/commit/store/mutation_types'; +import getInitialState from '~/projects/commit/store/state'; import mockData from '../mock_data'; -import { PROJECT_BRANCHES_ERROR } from '~/projects/commit/constants'; jest.mock('~/flash.js'); diff --git a/spec/frontend/projects/commit/store/mutations_spec.js b/spec/frontend/projects/commit/store/mutations_spec.js index 59ab3d9a74a..2ea50e71772 100644 --- a/spec/frontend/projects/commit/store/mutations_spec.js +++ b/spec/frontend/projects/commit/store/mutations_spec.js @@ -1,5 +1,5 @@ -import mutations from '~/projects/commit/store/mutations'; import * as types from '~/projects/commit/store/mutation_types'; +import mutations from '~/projects/commit/store/mutations'; describe('Commit form modal mutations', () => { let stateCopy; diff --git a/spec/frontend/projects/commit_box/info/load_branches_spec.js b/spec/frontend/projects/commit_box/info/load_branches_spec.js index ebd4ee45dab..8100200cbdd 100644 --- a/spec/frontend/projects/commit_box/info/load_branches_spec.js +++ b/spec/frontend/projects/commit_box/info/load_branches_spec.js @@ -1,6 +1,6 @@ import axios from 'axios'; -import waitForPromises from 'helpers/wait_for_promises'; import MockAdapter from 'axios-mock-adapter'; +import waitForPromises from 'helpers/wait_for_promises'; import { loadBranches } from '~/projects/commit_box/info/load_branches'; const mockCommitPath = '/commit/abcd/branches'; diff --git a/spec/frontend/projects/commits/components/author_select_spec.js b/spec/frontend/projects/commits/components/author_select_spec.js index 63920ddfd72..9a8f7ff7582 100644 --- a/spec/frontend/projects/commits/components/author_select_spec.js +++ b/spec/frontend/projects/commits/components/author_select_spec.js @@ -1,6 +1,6 @@ +import { GlDropdown, GlDropdownSectionHeader, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; -import { GlDropdown, GlDropdownSectionHeader, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui'; import * as urlUtility from '~/lib/utils/url_utility'; import AuthorSelect from '~/projects/commits/components/author_select.vue'; import { createStore } from '~/projects/commits/store'; diff --git a/spec/frontend/projects/commits/store/actions_spec.js b/spec/frontend/projects/commits/store/actions_spec.js index a842aaa2a76..e2c993b8395 100644 --- a/spec/frontend/projects/commits/store/actions_spec.js +++ b/spec/frontend/projects/commits/store/actions_spec.js @@ -1,10 +1,10 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import * as types from '~/projects/commits/store/mutation_types'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; import actions from '~/projects/commits/store/actions'; +import * as types from '~/projects/commits/store/mutation_types'; import createState from '~/projects/commits/store/state'; -import { deprecatedCreateFlash as createFlash } from '~/flash'; jest.mock('~/flash'); diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js new file mode 100644 index 00000000000..d28a30e93b1 --- /dev/null +++ b/spec/frontend/projects/compare/components/app_spec.js @@ -0,0 +1,116 @@ +import { GlButton } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import CompareApp from '~/projects/compare/components/app.vue'; +import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue'; + +jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); + +const projectCompareIndexPath = 'some/path'; +const refsProjectPath = 'some/refs/path'; +const paramsFrom = 'master'; +const paramsTo = 'master'; + +describe('CompareApp component', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(CompareApp, { + propsData: { + projectCompareIndexPath, + refsProjectPath, + paramsFrom, + paramsTo, + projectMergeRequestPath: '', + createMrPath: '', + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + beforeEach(() => { + createComponent(); + }); + + it('renders component with prop', () => { + expect(wrapper.props()).toEqual( + expect.objectContaining({ + projectCompareIndexPath, + refsProjectPath, + paramsFrom, + paramsTo, + }), + ); + }); + + it('contains the correct form attributes', () => { + expect(wrapper.attributes('action')).toBe(projectCompareIndexPath); + expect(wrapper.attributes('method')).toBe('POST'); + }); + + it('has input with csrf token', () => { + expect(wrapper.find('input[name="authenticity_token"]').attributes('value')).toBe( + 'mock-csrf-token', + ); + }); + + it('has ellipsis', () => { + expect(wrapper.find('[data-testid="ellipsis"]').exists()).toBe(true); + }); + + it('render Source and Target BranchDropdown components', () => { + const branchDropdowns = wrapper.findAll(RevisionDropdown); + + expect(branchDropdowns.length).toBe(2); + expect(branchDropdowns.at(0).props('revisionText')).toBe('Source'); + expect(branchDropdowns.at(1).props('revisionText')).toBe('Target'); + }); + + describe('compare button', () => { + const findCompareButton = () => wrapper.find(GlButton); + + it('renders button', () => { + expect(findCompareButton().exists()).toBe(true); + }); + + it('submits form', () => { + findCompareButton().vm.$emit('click'); + expect(wrapper.find('form').element.submit).toHaveBeenCalled(); + }); + + it('has compare text', () => { + expect(findCompareButton().text()).toBe('Compare'); + }); + }); + + describe('merge request buttons', () => { + const findProjectMrButton = () => wrapper.find('[data-testid="projectMrButton"]'); + const findCreateMrButton = () => wrapper.find('[data-testid="createMrButton"]'); + + it('does not have merge request buttons', () => { + createComponent(); + expect(findProjectMrButton().exists()).toBe(false); + expect(findCreateMrButton().exists()).toBe(false); + }); + + it('has "View open merge request" button', () => { + createComponent({ + projectMergeRequestPath: 'some/project/merge/request/path', + }); + expect(findProjectMrButton().exists()).toBe(true); + expect(findCreateMrButton().exists()).toBe(false); + }); + + it('has "Create merge request" button', () => { + createComponent({ + createMrPath: 'some/create/create/mr/path', + }); + expect(findProjectMrButton().exists()).toBe(false); + expect(findCreateMrButton().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js new file mode 100644 index 00000000000..f3ff5e26d2b --- /dev/null +++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js @@ -0,0 +1,92 @@ +import { GlDropdown } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import AxiosMockAdapter from 'axios-mock-adapter'; +import createFlash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue'; + +const defaultProps = { + refsProjectPath: 'some/refs/path', + revisionText: 'Target', + paramsName: 'from', + paramsBranch: 'master', +}; + +jest.mock('~/flash'); + +describe('RevisionDropdown component', () => { + let wrapper; + let axiosMock; + + const createComponent = (props = {}) => { + wrapper = shallowMount(RevisionDropdown, { + propsData: { + ...defaultProps, + ...props, + }, + }); + }; + + beforeEach(() => { + axiosMock = new AxiosMockAdapter(axios); + }); + + afterEach(() => { + wrapper.destroy(); + axiosMock.restore(); + }); + + const findGlDropdown = () => wrapper.find(GlDropdown); + + it('sets hidden input', () => { + createComponent(); + expect(wrapper.find('input[type="hidden"]').attributes('value')).toBe( + defaultProps.paramsBranch, + ); + }); + + it('update the branches on success', async () => { + const Branches = ['branch-1', 'branch-2']; + const Tags = ['tag-1', 'tag-2', 'tag-3']; + + axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(200, { + Branches, + Tags, + }); + + createComponent(); + + await axios.waitForAll(); + + expect(wrapper.vm.branches).toEqual(Branches); + expect(wrapper.vm.tags).toEqual(Tags); + }); + + it('shows flash message on error', async () => { + axiosMock.onGet('some/invalid/path').replyOnce(404); + + createComponent(); + + await wrapper.vm.fetchBranchesAndTags(); + expect(createFlash).toHaveBeenCalled(); + }); + + describe('GlDropdown component', () => { + it('renders props', () => { + createComponent(); + expect(wrapper.props()).toEqual(expect.objectContaining(defaultProps)); + }); + + it('display default text', () => { + createComponent({ + paramsBranch: null, + }); + expect(findGlDropdown().props('text')).toBe('Select branch/tag'); + }); + + it('display params branch text', () => { + createComponent(); + expect(findGlDropdown().props('text')).toBe(defaultProps.paramsBranch); + }); + }); +}); diff --git a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap index 0b9f095a700..f0d72124379 100644 --- a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap +++ b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap @@ -53,12 +53,12 @@ exports[`Project remove modal initialized matches the snapshot 1`] = ` variant="danger" > <gl-sprintf-stub - message="Once a project is permanently deleted it %{strongStart}cannot be recovered%{strongEnd}. Permanently deleting this project will %{strongStart}immediately delete%{strongEnd} its repositories and %{strongStart}all related resources%{strongEnd} including issues, merge requests etc." + message="Once a project is permanently deleted, it %{strongStart}cannot be recovered%{strongEnd}. Permanently deleting this project will %{strongStart}immediately delete%{strongEnd} its repositories and %{strongStart}all related resources%{strongEnd}, including issues, merge requests etc." /> </gl-alert-stub> <p> - This action cannot be undone. You will lose this project's repository and all content: issues, merge requests, etc. + This action cannot be undone. You will lose this project's repository and all related resources, including issues, merge requests, etc. </p> <p diff --git a/spec/frontend/projects/components/shared/delete_button_spec.js b/spec/frontend/projects/components/shared/delete_button_spec.js index cf7e41a2df2..3e491584670 100644 --- a/spec/frontend/projects/components/shared/delete_button_spec.js +++ b/spec/frontend/projects/components/shared/delete_button_spec.js @@ -1,5 +1,5 @@ -import { shallowMount } from '@vue/test-utils'; import { GlModal } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import { stubComponent } from 'helpers/stub_component'; import SharedDeleteButton from '~/projects/components/shared/delete_button.vue'; diff --git a/spec/frontend/projects/experiment_new_project_creation/components/app_spec.js b/spec/frontend/projects/experiment_new_project_creation/components/app_spec.js index 9a5f200f5a9..b4ae50341d4 100644 --- a/spec/frontend/projects/experiment_new_project_creation/components/app_spec.js +++ b/spec/frontend/projects/experiment_new_project_creation/components/app_spec.js @@ -1,8 +1,8 @@ -import { shallowMount } from '@vue/test-utils'; import { GlBreadcrumb } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import App from '~/projects/experiment_new_project_creation/components/app.vue'; -import WelcomePage from '~/projects/experiment_new_project_creation/components/welcome.vue'; import LegacyContainer from '~/projects/experiment_new_project_creation/components/legacy_container.vue'; +import WelcomePage from '~/projects/experiment_new_project_creation/components/welcome.vue'; describe('Experimental new project creation app', () => { let wrapper; diff --git a/spec/frontend/projects/members/utils_spec.js b/spec/frontend/projects/members/utils_spec.js new file mode 100644 index 00000000000..813e8455e85 --- /dev/null +++ b/spec/frontend/projects/members/utils_spec.js @@ -0,0 +1,14 @@ +import { projectMemberRequestFormatter } from '~/projects/members/utils'; + +describe('project member utils', () => { + describe('projectMemberRequestFormatter', () => { + it('returns expected format', () => { + expect( + projectMemberRequestFormatter({ + accessLevel: 50, + expires_at: '2020-10-16', + }), + ).toEqual({ project_member: { access_level: 50, expires_at: '2020-10-16' } }); + }); + }); +}); diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js index 44329944097..e8aace14db4 100644 --- a/spec/frontend/projects/pipelines/charts/components/app_spec.js +++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js @@ -1,32 +1,19 @@ -import { merge } from 'lodash'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import VueApollo from 'vue-apollo'; import { GlTabs, GlTab } from '@gitlab/ui'; -import createMockApollo from 'helpers/mock_apollo_helper'; +import { shallowMount } from '@vue/test-utils'; +import { merge } from 'lodash'; +import setWindowLocation from 'helpers/set_window_location_helper'; +import { TEST_HOST } from 'helpers/test_constants'; +import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/url_utility'; import Component from '~/projects/pipelines/charts/components/app.vue'; import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue'; -import getPipelineCountByStatus from '~/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql'; -import getProjectPipelineStatistics from '~/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql'; -import { mockPipelineCount, mockPipelineStatistics } from '../mock_data'; -const projectPath = 'gitlab-org/gitlab'; -const localVue = createLocalVue(); -localVue.use(VueApollo); +jest.mock('~/lib/utils/url_utility'); const DeploymentFrequencyChartsStub = { name: 'DeploymentFrequencyCharts', render: () => {} }; describe('ProjectsPipelinesChartsApp', () => { let wrapper; - function createMockApolloProvider() { - const requestHandlers = [ - [getPipelineCountByStatus, jest.fn().mockResolvedValue(mockPipelineCount)], - [getProjectPipelineStatistics, jest.fn().mockResolvedValue(mockPipelineStatistics)], - ]; - - return createMockApollo(requestHandlers); - } - function createComponent(mountOptions = {}) { wrapper = shallowMount( Component, @@ -34,11 +21,8 @@ describe('ProjectsPipelinesChartsApp', () => { {}, { provide: { - projectPath, shouldRenderDeploymentFrequencyCharts: false, }, - localVue, - apolloProvider: createMockApolloProvider(), stubs: { DeploymentFrequencyCharts: DeploymentFrequencyChartsStub, }, @@ -57,52 +41,15 @@ describe('ProjectsPipelinesChartsApp', () => { wrapper = null; }); - describe('pipelines charts', () => { - it('displays the pipeline charts', () => { - const chart = wrapper.find(PipelineCharts); - const analytics = mockPipelineStatistics.data.project.pipelineAnalytics; - - const { - totalPipelines: total, - successfulPipelines: success, - failedPipelines: failed, - } = mockPipelineCount.data.project; - - expect(chart.exists()).toBe(true); - expect(chart.props()).toMatchObject({ - counts: { - failed: failed.count, - success: success.count, - total: total.count, - successRatio: (success.count / (success.count + failed.count)) * 100, - }, - lastWeek: { - labels: analytics.weekPipelinesLabels, - totals: analytics.weekPipelinesTotals, - success: analytics.weekPipelinesSuccessful, - }, - lastMonth: { - labels: analytics.monthPipelinesLabels, - totals: analytics.monthPipelinesTotals, - success: analytics.monthPipelinesSuccessful, - }, - lastYear: { - labels: analytics.yearPipelinesLabels, - totals: analytics.yearPipelinesTotals, - success: analytics.yearPipelinesSuccessful, - }, - timesChart: { - labels: analytics.pipelineTimesLabels, - values: analytics.pipelineTimesValues, - }, - }); - }); - }); - - const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub); const findGlTabs = () => wrapper.find(GlTabs); const findAllGlTab = () => wrapper.findAll(GlTab); const findGlTabAt = (i) => findAllGlTab().at(i); + const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub); + const findPipelineCharts = () => wrapper.find(PipelineCharts); + + it('renders the pipeline charts', () => { + expect(findPipelineCharts().exists()).toBe(true); + }); describe('when shouldRenderDeploymentFrequencyCharts is true', () => { beforeEach(() => { @@ -115,6 +62,97 @@ describe('ProjectsPipelinesChartsApp', () => { expect(findGlTabAt(1).attributes('title')).toBe('Deployments'); expect(findDeploymentFrequencyCharts().exists()).toBe(true); }); + + it('sets the tab and url when a tab is clicked', async () => { + let chartsPath; + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts`); + + mergeUrlParams.mockImplementation(({ chart }, path) => { + expect(chart).toBe('deployments'); + expect(path).toBe(window.location.pathname); + chartsPath = `${path}?chart=${chart}`; + return chartsPath; + }); + + updateHistory.mockImplementation(({ url }) => { + expect(url).toBe(chartsPath); + }); + const tabs = findGlTabs(); + + expect(tabs.attributes('value')).toBe('0'); + + tabs.vm.$emit('input', 1); + + await wrapper.vm.$nextTick(); + + expect(tabs.attributes('value')).toBe('1'); + }); + + it('should not try to push history if the tab does not change', async () => { + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts`); + + mergeUrlParams.mockImplementation(({ chart }, path) => `${path}?chart=${chart}`); + + const tabs = findGlTabs(); + + expect(tabs.attributes('value')).toBe('0'); + + tabs.vm.$emit('input', 0); + + await wrapper.vm.$nextTick(); + + expect(updateHistory).not.toHaveBeenCalled(); + }); + }); + + describe('when provided with a query param', () => { + it.each` + chart | tab + ${'deployments'} | ${'1'} + ${'pipelines'} | ${'0'} + ${'fake'} | ${'0'} + ${''} | ${'0'} + `('shows the correct tab for URL parameter "$chart"', ({ chart, tab }) => { + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts?chart=${chart}`); + getParameterValues.mockImplementation((name) => { + expect(name).toBe('chart'); + return chart ? [chart] : []; + }); + createComponent({ provide: { shouldRenderDeploymentFrequencyCharts: true } }); + expect(findGlTabs().attributes('value')).toBe(tab); + }); + + it('should set the tab when the back button is clicked', async () => { + let popstateHandler; + + window.addEventListener = jest.fn(); + + window.addEventListener.mockImplementation((event, handler) => { + if (event === 'popstate') { + popstateHandler = handler; + } + }); + + getParameterValues.mockImplementation((name) => { + expect(name).toBe('chart'); + return []; + }); + + createComponent({ provide: { shouldRenderDeploymentFrequencyCharts: true } }); + + expect(findGlTabs().attributes('value')).toBe('0'); + + getParameterValues.mockImplementationOnce((name) => { + expect(name).toBe('chart'); + return ['deployments']; + }); + + popstateHandler(); + + await wrapper.vm.$nextTick(); + + expect(findGlTabs().attributes('value')).toBe('1'); + }); }); describe('when shouldRenderDeploymentFrequencyCharts is false', () => { diff --git a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js new file mode 100644 index 00000000000..037530ddd48 --- /dev/null +++ b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js @@ -0,0 +1,94 @@ +import { GlSegmentedControl } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import CiCdAnalyticsAreaChart from '~/projects/pipelines/charts/components/ci_cd_analytics_area_chart.vue'; +import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue'; +import { transformedAreaChartData, chartOptions } from '../mock_data'; + +const DEFAULT_PROPS = { + chartOptions, + charts: [ + { + range: 'test range 1', + title: 'title 1', + data: transformedAreaChartData, + }, + { + range: 'test range 2', + title: 'title 2', + data: transformedAreaChartData, + }, + { + range: 'test range 3', + title: 'title 3', + data: transformedAreaChartData, + }, + ], +}; + +describe('~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue', () => { + let wrapper; + + const createWrapper = (props = {}) => + shallowMount(CiCdAnalyticsCharts, { + propsData: { + ...DEFAULT_PROPS, + ...props, + }, + }); + + afterEach(() => { + if (wrapper) { + wrapper.destroy(); + wrapper = null; + } + }); + + describe('segmented control', () => { + let segmentedControl; + + beforeEach(() => { + wrapper = createWrapper(); + segmentedControl = wrapper.find(GlSegmentedControl); + }); + + it('should default to the first chart', () => { + expect(segmentedControl.props('checked')).toBe(0); + }); + + it('should use the title and index as values', () => { + const options = segmentedControl.props('options'); + expect(options).toHaveLength(3); + expect(options).toEqual([ + { + text: 'title 1', + value: 0, + }, + { + text: 'title 2', + value: 1, + }, + { + text: 'title 3', + value: 2, + }, + ]); + }); + + it('should select a different chart on change', async () => { + segmentedControl.vm.$emit('input', 1); + + const chart = wrapper.find(CiCdAnalyticsAreaChart); + + await nextTick(); + + expect(chart.props('chartData')).toEqual(transformedAreaChartData); + expect(chart.text()).toBe('Date range: test range 2'); + }); + }); + + it('should not display charts if there are no charts', () => { + wrapper = createWrapper({ charts: [] }); + expect(wrapper.find(CiCdAnalyticsAreaChart).exists()).toBe(false); + }); +}); diff --git a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js index 598055d5828..c5cfe783569 100644 --- a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js +++ b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js @@ -1,35 +1,37 @@ -import { shallowMount } from '@vue/test-utils'; import { GlColumnChart } from '@gitlab/ui/dist/charts'; -import StatisticsList from '~/projects/pipelines/charts/components/statistics_list.vue'; -import CiCdAnalyticsAreaChart from '~/projects/pipelines/charts/components/ci_cd_analytics_area_chart.vue'; +import { createLocalVue, shallowMount } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue'; import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue'; -import { - counts, - timesChartData as timesChart, - areaChartData as lastWeek, - areaChartData as lastMonth, - lastYearChartData as lastYear, -} from '../mock_data'; +import StatisticsList from '~/projects/pipelines/charts/components/statistics_list.vue'; +import getPipelineCountByStatus from '~/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql'; +import getProjectPipelineStatistics from '~/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql'; +import { mockPipelineCount, mockPipelineStatistics } from '../mock_data'; + +const projectPath = 'gitlab-org/gitlab'; +const localVue = createLocalVue(); +localVue.use(VueApollo); -describe('ProjectsPipelinesChartsApp', () => { +describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => { let wrapper; + function createMockApolloProvider() { + const requestHandlers = [ + [getPipelineCountByStatus, jest.fn().mockResolvedValue(mockPipelineCount)], + [getProjectPipelineStatistics, jest.fn().mockResolvedValue(mockPipelineStatistics)], + ]; + + return createMockApollo(requestHandlers); + } + beforeEach(() => { wrapper = shallowMount(PipelineCharts, { - propsData: { - counts, - timesChart, - lastWeek, - lastMonth, - lastYear, - }, provide: { - projectPath: 'test/project', - shouldRenderDeploymentFrequencyCharts: true, - }, - stubs: { - DeploymentFrequencyCharts: true, + projectPath, }, + localVue, + apolloProvider: createMockApolloProvider(), }); }); @@ -43,7 +45,12 @@ describe('ProjectsPipelinesChartsApp', () => { const list = wrapper.find(StatisticsList); expect(list.exists()).toBe(true); - expect(list.props('counts')).toBe(counts); + expect(list.props('counts')).toEqual({ + total: 34, + success: 23, + failed: 1, + successRatio: (23 / (23 + 1)) * 100, + }); }); it('displays the commit duration chart', () => { @@ -58,20 +65,17 @@ describe('ProjectsPipelinesChartsApp', () => { }); describe('pipelines charts', () => { - it('displays 3 area charts', () => { - expect(wrapper.findAll(CiCdAnalyticsAreaChart)).toHaveLength(3); + it('displays the charts components', () => { + expect(wrapper.find(CiCdAnalyticsCharts).exists()).toBe(true); }); describe('displays individual correctly', () => { it('renders with the correct data', () => { - const charts = wrapper.findAll(CiCdAnalyticsAreaChart); - for (let i = 0; i < charts.length; i += 1) { - const chart = charts.at(i); - - expect(chart.exists()).toBeTruthy(); - expect(chart.props('chartData')).toBe(wrapper.vm.areaCharts[i].data); - expect(chart.text()).toBe(wrapper.vm.areaCharts[i].title); - } + const charts = wrapper.find(CiCdAnalyticsCharts); + expect(charts.props()).toEqual({ + charts: wrapper.vm.areaCharts, + chartOptions: wrapper.vm.$options.areaChartOptions, + }); }); }); }); diff --git a/spec/frontend/projects/pipelines/charts/mock_data.js b/spec/frontend/projects/pipelines/charts/mock_data.js index 3bc09f0b0a0..2e2c594102c 100644 --- a/spec/frontend/projects/pipelines/charts/mock_data.js +++ b/spec/frontend/projects/pipelines/charts/mock_data.js @@ -57,6 +57,16 @@ export const mockPipelineCount = { }, }; +export const chartOptions = { + xAxis: { + name: 'X axis title', + type: 'category', + }, + yAxis: { + name: 'Y axis title', + }, +}; + export const mockPipelineStatistics = { data: { project: { diff --git a/spec/frontend/projects/settings/access_dropdown_spec.js b/spec/frontend/projects/settings/access_dropdown_spec.js index 8a57930ac83..236968a3736 100644 --- a/spec/frontend/projects/settings/access_dropdown_spec.js +++ b/spec/frontend/projects/settings/access_dropdown_spec.js @@ -14,7 +14,6 @@ describe('AccessDropdown', () => { `); const $dropdown = $('#dummy-dropdown'); $dropdown.data('defaultLabel', defaultLabel); - gon.features = { deployKeysOnProtectedBranches: true }; const options = { $dropdown, accessLevelsData: { diff --git a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js index 1fac3d07b16..2d6efe7ae83 100644 --- a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js +++ b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js @@ -2,8 +2,8 @@ import { GlAlert, GlToggle, GlTooltip } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import MockAxiosAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; -import SharedRunnersToggleComponent from '~/projects/settings/components/shared_runners_toggle.vue'; import axios from '~/lib/utils/axios_utils'; +import SharedRunnersToggleComponent from '~/projects/settings/components/shared_runners_toggle.vue'; const TEST_UPDATE_PATH = '/test/update_shared_runners'; diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js index c83b1852147..f9fbb1b3016 100644 --- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js +++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js @@ -1,20 +1,36 @@ -import { mount } from '@vue/test-utils'; +import { GlAlert } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; -import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue'; -import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue'; import axios from '~/lib/utils/axios_utils'; import httpStatusCodes from '~/lib/utils/http_status'; +import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue'; +import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue'; describe('ServiceDeskRoot', () => { - const endpoint = '/gitlab-org/gitlab-test/service_desk'; - const initialIncomingEmail = 'servicedeskaddress@example.com'; let axiosMock; let wrapper; let spy; + const provideData = { + customEmail: 'custom.email@example.com', + customEmailEnabled: true, + endpoint: '/gitlab-org/gitlab-test/service_desk', + initialIncomingEmail: 'servicedeskaddress@example.com', + initialIsEnabled: true, + outgoingName: 'GitLab Support Bot', + projectKey: 'key', + selectedTemplate: 'Bug', + templates: ['Bug', 'Documentation'], + }; + + const getAlertText = () => wrapper.find(GlAlert).text(); + + const createComponent = () => shallowMount(ServiceDeskRoot, { provide: provideData }); + beforeEach(() => { axiosMock = new AxiosMockAdapter(axios); + spy = jest.spyOn(axios, 'put'); }); afterEach(() => { @@ -25,156 +41,122 @@ describe('ServiceDeskRoot', () => { } }); - it('sends a request to toggle service desk off when the toggle is clicked from the on state', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK); + describe('ServiceDeskSetting component', () => { + it('is rendered', () => { + wrapper = createComponent(); + + expect(wrapper.find(ServiceDeskSetting).props()).toEqual({ + customEmail: provideData.customEmail, + customEmailEnabled: provideData.customEmailEnabled, + incomingEmail: provideData.initialIncomingEmail, + initialOutgoingName: provideData.outgoingName, + initialProjectKey: provideData.projectKey, + initialSelectedTemplate: provideData.selectedTemplate, + isEnabled: provideData.initialIsEnabled, + isTemplateSaving: false, + templates: provideData.templates, + }); + }); + + describe('toggle event', () => { + describe('when toggling service desk on', () => { + beforeEach(async () => { + wrapper = createComponent(); - spy = jest.spyOn(axios, 'put'); + wrapper.find(ServiceDeskSetting).vm.$emit('toggle', true); - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: true, - initialIncomingEmail, - endpoint, - }, - }); + await waitForPromises(); + }); + + it('sends a request to turn service desk on', () => { + axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK); - wrapper.find('button.gl-toggle').trigger('click'); + expect(spy).toHaveBeenCalledWith(provideData.endpoint, { service_desk_enabled: true }); + }); - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(spy).toHaveBeenCalledWith(endpoint, { service_desk_enabled: false }); + it('shows a message when there is an error', () => { + axiosMock.onPut(provideData.endpoint).networkError(); + + expect(getAlertText()).toContain('An error occurred while enabling Service Desk.'); + }); }); - }); - it('sends a request to toggle service desk on when the toggle is clicked from the off state', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK); + describe('when toggling service desk off', () => { + beforeEach(async () => { + wrapper = createComponent(); - spy = jest.spyOn(axios, 'put'); + wrapper.find(ServiceDeskSetting).vm.$emit('toggle', false); - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: false, - initialIncomingEmail: '', - endpoint, - }, - }); + await waitForPromises(); + }); - wrapper.find('button.gl-toggle').trigger('click'); + it('sends a request to turn service desk off', () => { + axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK); - return wrapper.vm.$nextTick(() => { - expect(spy).toHaveBeenCalledWith(endpoint, { service_desk_enabled: true }); - }); - }); + expect(spy).toHaveBeenCalledWith(provideData.endpoint, { service_desk_enabled: false }); + }); - it('shows an error message when there is an issue toggling service desk on', () => { - axiosMock.onPut(endpoint).networkError(); + it('shows a message when there is an error', () => { + axiosMock.onPut(provideData.endpoint).networkError(); - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: false, - initialIncomingEmail: '', - endpoint, - }, + expect(getAlertText()).toContain('An error occurred while disabling Service Desk.'); + }); + }); }); - wrapper.find('button.gl-toggle').trigger('click'); + describe('save event', () => { + describe('successful request', () => { + beforeEach(async () => { + axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK); - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(wrapper.html()).toContain('An error occurred while enabling Service Desk.'); - }); - }); + wrapper = createComponent(); - it('sends a request to update template when the "Save template" button is clicked', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK); + const payload = { + selectedTemplate: 'Bug', + outgoingName: 'GitLab Support Bot', + projectKey: 'key', + }; - spy = jest.spyOn(axios, 'put'); + wrapper.find(ServiceDeskSetting).vm.$emit('save', payload); - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: true, - endpoint, - initialIncomingEmail, - selectedTemplate: 'Bug', - outgoingName: 'GitLab Support Bot', - templates: ['Bug', 'Documentation'], - projectKey: 'key', - }, - }); + await waitForPromises(); + }); - wrapper.find('button.btn-success').trigger('click'); + it('sends a request to update template', async () => { + expect(spy).toHaveBeenCalledWith(provideData.endpoint, { + issue_template_key: 'Bug', + outgoing_name: 'GitLab Support Bot', + project_key: 'key', + service_desk_enabled: true, + }); + }); - return wrapper.vm.$nextTick(() => { - expect(spy).toHaveBeenCalledWith(endpoint, { - issue_template_key: 'Bug', - outgoing_name: 'GitLab Support Bot', - project_key: 'key', - service_desk_enabled: true, + it('shows success message', () => { + expect(getAlertText()).toContain('Changes saved.'); + }); }); - }); - }); - it('saves the template when the "Save template" button is clicked', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK); - - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: true, - endpoint, - initialIncomingEmail, - selectedTemplate: 'Bug', - templates: ['Bug', 'Documentation'], - }, - }); + describe('unsuccessful request', () => { + beforeEach(async () => { + axiosMock.onPut(provideData.endpoint).networkError(); - wrapper.find('button.btn-success').trigger('click'); + wrapper = createComponent(); - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(wrapper.html()).toContain('Changes saved.'); - }); - }); + const payload = { + selectedTemplate: 'Bug', + outgoingName: 'GitLab Support Bot', + projectKey: 'key', + }; - it('shows an error message when there is an issue saving the template', () => { - axiosMock.onPut(endpoint).networkError(); - - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: true, - endpoint, - initialIncomingEmail, - selectedTemplate: 'Bug', - templates: ['Bug', 'Documentation'], - }, - }); + wrapper.find(ServiceDeskSetting).vm.$emit('save', payload); - wrapper.find('button.btn-success').trigger('click'); + await waitForPromises(); + }); - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(wrapper.html()).toContain('An error occured while saving changes:'); + it('shows an error message', () => { + expect(getAlertText()).toContain('An error occured while saving changes:'); + }); }); - }); - - it('passes customEmail through updatedCustomEmail correctly', () => { - const customEmail = 'foo'; - - wrapper = mount(ServiceDeskRoot, { - propsData: { - initialIsEnabled: true, - endpoint, - customEmail, - }, }); - - expect(wrapper.find(ServiceDeskSetting).props('customEmail')).toEqual(customEmail); }); }); diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js index ddd9a7b2fad..f6744f4971e 100644 --- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js +++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js @@ -1,63 +1,68 @@ +import { GlButton, GlFormSelect, GlLoadingIcon, GlToggle } from '@gitlab/ui'; import { shallowMount, mount } from '@vue/test-utils'; -import { GlLoadingIcon } from '@gitlab/ui'; -import eventHub from '~/projects/settings_service_desk/event_hub'; +import { nextTick } from 'vue'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; describe('ServiceDeskSetting', () => { let wrapper; + const findButton = () => wrapper.find(GlButton); + const findClipboardButton = () => wrapper.find(ClipboardButton); + const findIncomingEmail = () => wrapper.findByTestId('incoming-email'); + const findIncomingEmailLabel = () => wrapper.findByTestId('incoming-email-describer'); + const findLoadingIcon = () => wrapper.find(GlLoadingIcon); + const findTemplateDropdown = () => wrapper.find(GlFormSelect); + const findToggle = () => wrapper.find(GlToggle); + + const createComponent = ({ props = {}, mountFunction = shallowMount } = {}) => + extendedWrapper( + mountFunction(ServiceDeskSetting, { + propsData: { + isEnabled: true, + ...props, + }, + }), + ); + afterEach(() => { if (wrapper) { wrapper.destroy(); } }); - const findTemplateDropdown = () => wrapper.find('#service-desk-template-select'); - const findIncomingEmail = () => wrapper.find('[data-testid="incoming-email"]'); - describe('when isEnabled=true', () => { describe('only isEnabled', () => { describe('as project admin', () => { beforeEach(() => { - wrapper = shallowMount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - }, - }); + wrapper = createComponent(); }); it('should see activation checkbox', () => { - expect(wrapper.find('#service-desk-checkbox').exists()).toBe(true); + expect(findToggle().exists()).toBe(true); }); it('should see main panel with the email info', () => { - expect(wrapper.find('#incoming-email-describer').exists()).toBe(true); + expect(findIncomingEmailLabel().exists()).toBe(true); }); it('should see loading spinner and not the incoming email', () => { - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(findLoadingIcon().exists()).toBe(true); expect(findIncomingEmail().exists()).toBe(false); }); }); }); describe('service desk toggle', () => { - it('emits an event to turn on Service Desk when clicked', () => { - const eventSpy = jest.fn(); - eventHub.$on('serviceDeskEnabledCheckboxToggled', eventSpy); - - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: false, - }, - }); + it('emits an event to turn on Service Desk when clicked', async () => { + wrapper = createComponent(); - wrapper.find('#service-desk-checkbox').trigger('click'); + findToggle().vm.$emit('change', true); - expect(eventSpy).toHaveBeenCalledWith(true); + await nextTick(); - eventHub.$off('serviceDeskEnabledCheckboxToggled', eventSpy); - eventSpy.mockRestore(); + expect(wrapper.emitted('toggle')[0]).toEqual([true]); }); }); @@ -65,23 +70,23 @@ describe('ServiceDeskSetting', () => { const incomingEmail = 'foo@bar.com'; beforeEach(() => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - incomingEmail, - }, + wrapper = createComponent({ + props: { incomingEmail }, }); }); it('should see email and not the loading spinner', () => { expect(findIncomingEmail().element.value).toEqual(incomingEmail); - expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); + expect(findLoadingIcon().exists()).toBe(false); }); it('renders a copy to clipboard button', () => { - expect(wrapper.find('.qa-clipboard-button').exists()).toBe(true); - expect(wrapper.find('.qa-clipboard-button').element.dataset.clipboardText).toBe( - incomingEmail, + expect(findClipboardButton().exists()).toBe(true); + expect(findClipboardButton().props()).toEqual( + expect.objectContaining({ + title: 'Copy', + text: incomingEmail, + }), ); }); }); @@ -92,12 +97,8 @@ describe('ServiceDeskSetting', () => { const customEmail = 'custom@bar.com'; beforeEach(() => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - incomingEmail, - customEmail, - }, + wrapper = createComponent({ + props: { incomingEmail, customEmail }, }); }); @@ -110,12 +111,8 @@ describe('ServiceDeskSetting', () => { const email = 'foo@bar.com'; beforeEach(() => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - incomingEmail: email, - customEmail: email, - }, + wrapper = createComponent({ + props: { incomingEmail: email, customEmail: email }, }); }); @@ -127,21 +124,13 @@ describe('ServiceDeskSetting', () => { describe('templates dropdown', () => { it('renders a dropdown to choose a template', () => { - wrapper = shallowMount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - }, - }); + wrapper = createComponent(); - expect(wrapper.find('#service-desk-template-select').exists()).toBe(true); + expect(findTemplateDropdown().exists()).toBe(true); }); it('renders a dropdown with a default value of ""', () => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - }, - }); + wrapper = createComponent({ mountFunction: mount }); expect(findTemplateDropdown().element.value).toEqual(''); }); @@ -149,23 +138,18 @@ describe('ServiceDeskSetting', () => { it('renders a dropdown with a value of "Bug" when it is the initial value', () => { const templates = ['Bug', 'Documentation', 'Security release']; - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - initialSelectedTemplate: 'Bug', - templates, - }, + wrapper = createComponent({ + props: { initialSelectedTemplate: 'Bug', templates }, + mountFunction: mount, }); expect(findTemplateDropdown().element.value).toEqual('Bug'); }); it('renders a dropdown with no options when the project has no templates', () => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - templates: [], - }, + wrapper = createComponent({ + props: { templates: [] }, + mountFunction: mount, }); // The dropdown by default has one empty option @@ -174,11 +158,10 @@ describe('ServiceDeskSetting', () => { it('renders a dropdown with options when the project has templates', () => { const templates = ['Bug', 'Documentation', 'Security release']; - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - templates, - }, + + wrapper = createComponent({ + props: { templates }, + mountFunction: mount, }); // An empty-named template is prepended so the user can select no template @@ -199,78 +182,59 @@ describe('ServiceDeskSetting', () => { describe('save button', () => { it('renders a save button to save a template', () => { - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - }, - }); + wrapper = createComponent(); - expect(wrapper.find('button.btn-success').text()).toContain('Save changes'); + expect(findButton().text()).toContain('Save changes'); }); - it('emits a save event with the chosen template when the save button is clicked', () => { - const eventSpy = jest.fn(); - eventHub.$on('serviceDeskTemplateSave', eventSpy); - - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, + it('emits a save event with the chosen template when the save button is clicked', async () => { + wrapper = createComponent({ + props: { initialSelectedTemplate: 'Bug', initialOutgoingName: 'GitLab Support Bot', initialProjectKey: 'key', }, }); - wrapper.find('button.btn-success').trigger('click'); + findButton().vm.$emit('click'); + + await nextTick(); - expect(eventSpy).toHaveBeenCalledWith({ + const payload = { selectedTemplate: 'Bug', outgoingName: 'GitLab Support Bot', projectKey: 'key', - }); + }; - eventHub.$off('serviceDeskTemplateSave', eventSpy); - eventSpy.mockRestore(); + expect(wrapper.emitted('save')[0]).toEqual([payload]); }); }); describe('when isEnabled=false', () => { beforeEach(() => { - wrapper = shallowMount(ServiceDeskSetting, { - propsData: { - isEnabled: false, - }, + wrapper = createComponent({ + props: { isEnabled: false }, }); }); it('does not render email panel', () => { - expect(wrapper.find('#incoming-email-describer').exists()).toBe(false); + expect(findIncomingEmailLabel().exists()).toBe(false); }); it('does not render template dropdown', () => { - expect(wrapper.find('#service-desk-template-select').exists()).toBe(false); + expect(findTemplateDropdown().exists()).toBe(false); }); it('does not render template save button', () => { - expect(wrapper.find('button.btn-success').exists()).toBe(false); + expect(findButton().exists()).toBe(false); }); - it('emits an event to turn on Service Desk when the toggle is clicked', () => { - const eventSpy = jest.fn(); - eventHub.$on('serviceDeskEnabledCheckboxToggled', eventSpy); - - wrapper = mount(ServiceDeskSetting, { - propsData: { - isEnabled: true, - }, - }); - - wrapper.find('#service-desk-checkbox').trigger('click'); + it('emits an event to turn on Service Desk when the toggle is clicked', async () => { + findToggle().vm.$emit('change', false); - expect(eventSpy).toHaveBeenCalledWith(false); + await nextTick(); - eventHub.$off('serviceDeskEnabledCheckboxToggled', eventSpy); - eventSpy.mockRestore(); + expect(wrapper.emitted('toggle')[0]).toEqual([false]); }); }); }); diff --git a/spec/frontend/projects/settings_service_desk/services/service_desk_service_spec.js b/spec/frontend/projects/settings_service_desk/services/service_desk_service_spec.js deleted file mode 100644 index d5340df03fe..00000000000 --- a/spec/frontend/projects/settings_service_desk/services/service_desk_service_spec.js +++ /dev/null @@ -1,111 +0,0 @@ -import AxiosMockAdapter from 'axios-mock-adapter'; -import ServiceDeskService from '~/projects/settings_service_desk/services/service_desk_service'; -import axios from '~/lib/utils/axios_utils'; -import httpStatusCodes from '~/lib/utils/http_status'; - -describe('ServiceDeskService', () => { - const endpoint = `/gitlab-org/gitlab-test/service_desk`; - const dummyResponse = { message: 'Dummy response' }; - const errorMessage = 'Network Error'; - let axiosMock; - let service; - - beforeEach(() => { - axiosMock = new AxiosMockAdapter(axios); - service = new ServiceDeskService(endpoint); - }); - - afterEach(() => { - axiosMock.restore(); - }); - - describe('toggleServiceDesk', () => { - it('makes a request to set service desk', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse); - - return service.toggleServiceDesk(true).then((response) => { - expect(response.data).toEqual(dummyResponse); - }); - }); - - it('fails on error response', () => { - axiosMock.onPut(endpoint).networkError(); - - return service.toggleServiceDesk(true).catch((error) => { - expect(error.message).toBe(errorMessage); - }); - }); - - it('makes a request with the expected body', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse); - - const spy = jest.spyOn(axios, 'put'); - - service.toggleServiceDesk(true); - - expect(spy).toHaveBeenCalledWith(endpoint, { - service_desk_enabled: true, - }); - - spy.mockRestore(); - }); - }); - - describe('updateTemplate', () => { - it('makes a request to update template', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse); - - return service - .updateTemplate( - { - selectedTemplate: 'Bug', - outgoingName: 'GitLab Support Bot', - }, - true, - ) - .then((response) => { - expect(response.data).toEqual(dummyResponse); - }); - }); - - it('fails on error response', () => { - axiosMock.onPut(endpoint).networkError(); - - return service - .updateTemplate( - { - selectedTemplate: 'Bug', - outgoingName: 'GitLab Support Bot', - }, - true, - ) - .catch((error) => { - expect(error.message).toBe(errorMessage); - }); - }); - - it('makes a request with the expected body', () => { - axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse); - - const spy = jest.spyOn(axios, 'put'); - - service.updateTemplate( - { - selectedTemplate: 'Bug', - outgoingName: 'GitLab Support Bot', - projectKey: 'key', - }, - true, - ); - - expect(spy).toHaveBeenCalledWith(endpoint, { - issue_template_key: 'Bug', - outgoing_name: 'GitLab Support Bot', - project_key: 'key', - service_desk_enabled: true, - }); - - spy.mockRestore(); - }); - }); -}); |