diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 21:18:33 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 21:18:33 +0300 |
commit | f64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch) | |
tree | a2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /spec/frontend/vue_mr_widget | |
parent | bfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff) |
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'spec/frontend/vue_mr_widget')
13 files changed, 258 insertions, 201 deletions
diff --git a/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js index b2cc7d9be6b..e2386bc7f2b 100644 --- a/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js +++ b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js @@ -48,7 +48,7 @@ describe('Merge Requests Artifacts list app', () => { }; const findButtons = () => wrapper.findAll('button'); - const findTitle = () => wrapper.find('.js-title'); + const findTitle = () => wrapper.find('[data-testid="mr-collapsible-title"]'); const findErrorMessage = () => wrapper.find('.js-error-state'); const findTableRows = () => wrapper.findAll('tbody tr'); diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js index 94d4cccab5f..1aeb080aa04 100644 --- a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js @@ -1,4 +1,4 @@ -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue'; @@ -15,12 +15,14 @@ describe('Merge Request Collapsible Extension', () => { }, slots: { default: '<div class="js-slot">Foo</div>', + header: '<span data-testid="collapsed-header">hello there</span>', }, }); }; - const findTitle = () => wrapper.find('.js-title'); + const findTitle = () => wrapper.find('[data-testid="mr-collapsible-title"]'); const findErrorMessage = () => wrapper.find('.js-error-state'); + const findIcon = () => wrapper.find(GlIcon); afterEach(() => { wrapper.destroy(); @@ -35,8 +37,12 @@ describe('Merge Request Collapsible Extension', () => { expect(findTitle().text()).toBe(data.title); }); + it('renders the header slot', () => { + expect(wrapper.find('[data-testid="collapsed-header"]').text()).toBe('hello there'); + }); + it('renders angle-right icon', () => { - expect(wrapper.vm.arrowIconName).toBe('angle-right'); + expect(findIcon().props('name')).toBe('angle-right'); }); describe('onClick', () => { @@ -54,7 +60,7 @@ describe('Merge Request Collapsible Extension', () => { }); it('renders angle-down icon', () => { - expect(wrapper.vm.arrowIconName).toBe('angle-down'); + expect(findIcon().props('name')).toBe('angle-down'); }); }); }); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_merge_help_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_merge_help_spec.js deleted file mode 100644 index 53a74bf7456..00000000000 --- a/spec/frontend/vue_mr_widget/components/mr_widget_merge_help_spec.js +++ /dev/null @@ -1,46 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import MergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue'; - -describe('MRWidgetMergeHelp', () => { - let wrapper; - - const createComponent = ({ props = {} } = {}) => { - wrapper = shallowMount(MergeHelpComponent, { - propsData: { - missingBranch: 'this-is-not-the-branch-you-are-looking-for', - ...props, - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - describe('with missing branch', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders missing branch information', () => { - expect(wrapper.find('.mr-widget-help').text()).toContain( - 'If the this-is-not-the-branch-you-are-looking-for branch exists in your local repository', - ); - }); - }); - - describe('without missing branch', () => { - beforeEach(() => { - createComponent({ - props: { missingBranch: '' }, - }); - }); - - it('renders information about how to merge manually', () => { - expect(wrapper.find('.mr-widget-help').text()).toContain( - 'You can merge this merge request manually', - ); - }); - }); -}); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js index 3baade5161e..5ec719b17d6 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js @@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import ArtifactsApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue'; +import DeploymentList from '~/vue_merge_request_widget/components/deployment/deployment_list.vue'; import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue'; import MrWidgetPipelineContainer from '~/vue_merge_request_widget/components/mr_widget_pipeline_container.vue'; import { mockStore } from '../mock_data'; @@ -28,6 +29,8 @@ describe('MrWidgetPipelineContainer', () => { wrapper.destroy(); }); + const findDeploymentList = () => wrapper.findComponent(DeploymentList); + describe('when pre merge', () => { beforeEach(() => { factory(); @@ -55,6 +58,9 @@ describe('MrWidgetPipelineContainer', () => { const deployments = wrapper.findAll('.mr-widget-extension .js-pre-deployment'); + expect(findDeploymentList().exists()).toBe(true); + expect(findDeploymentList().props('deployments')).toBe(mockStore.deployments); + expect(deployments.wrappers.map((x) => x.props())).toEqual(expectedProps); }); }); @@ -100,6 +106,8 @@ describe('MrWidgetPipelineContainer', () => { const deployments = wrapper.findAll('.mr-widget-extension .js-post-deployment'); + expect(findDeploymentList().exists()).toBe(true); + expect(findDeploymentList().props('deployments')).toBe(mockStore.postMergeDeployments); expect(deployments.wrappers.map((x) => x.props())).toEqual(expectedProps); }); }); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js index b93236d4628..28492018600 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js @@ -1,7 +1,8 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { shallowMount, mount } from '@vue/test-utils'; import { trimText } from 'helpers/text_helper'; -import PipelineStage from '~/pipelines/components/pipelines_list/stage.vue'; +import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue'; +import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue'; import PipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue'; import { SUCCESS } from '~/vue_merge_request_widget/constants'; import mockData from '../mock_data'; @@ -25,7 +26,7 @@ describe('MRWidgetPipeline', () => { const findPipelineID = () => wrapper.find('[data-testid="pipeline-id"]'); const findPipelineInfoContainer = () => wrapper.find('[data-testid="pipeline-info-container"]'); const findCommitLink = () => wrapper.find('[data-testid="commit-link"]'); - const findPipelineGraph = () => wrapper.find('[data-testid="widget-mini-pipeline-graph"]'); + const findPipelineMiniGraph = () => wrapper.find(PipelineMiniGraph); const findAllPipelineStages = () => wrapper.findAll(PipelineStage); const findPipelineCoverage = () => wrapper.find('[data-testid="pipeline-coverage"]'); const findPipelineCoverageDelta = () => wrapper.find('[data-testid="pipeline-coverage-delta"]'); @@ -35,7 +36,7 @@ describe('MRWidgetPipeline', () => { wrapper.find('[data-testid="monitoring-pipeline-message"]'); const findLoadingIcon = () => wrapper.find(GlLoadingIcon); - const createWrapper = (props, mountFn = shallowMount) => { + const createWrapper = (props = {}, mountFn = shallowMount) => { wrapper = mountFn(PipelineComponent, { propsData: { ...defaultProps, @@ -65,10 +66,13 @@ describe('MRWidgetPipeline', () => { describe('with a pipeline', () => { beforeEach(() => { - createWrapper({ - pipelineCoverageDelta: mockData.pipelineCoverageDelta, - buildsWithCoverage: mockData.buildsWithCoverage, - }); + createWrapper( + { + pipelineCoverageDelta: mockData.pipelineCoverageDelta, + buildsWithCoverage: mockData.buildsWithCoverage, + }, + mount, + ); }); it('should render pipeline ID', () => { @@ -84,8 +88,8 @@ describe('MRWidgetPipeline', () => { }); it('should render pipeline graph', () => { - expect(findPipelineGraph().exists()).toBe(true); - expect(findAllPipelineStages().length).toBe(mockData.pipeline.details.stages.length); + expect(findPipelineMiniGraph().exists()).toBe(true); + expect(findAllPipelineStages()).toHaveLength(mockData.pipeline.details.stages.length); }); describe('should render pipeline coverage information', () => { @@ -136,7 +140,7 @@ describe('MRWidgetPipeline', () => { const mockCopy = JSON.parse(JSON.stringify(mockData)); delete mockCopy.pipeline.commit; - createWrapper({}); + createWrapper({}, mount); }); it('should render pipeline ID', () => { @@ -147,9 +151,15 @@ describe('MRWidgetPipeline', () => { expect(findPipelineInfoContainer().text()).toMatch(mockData.pipeline.details.status.label); }); - it('should render pipeline graph', () => { - expect(findPipelineGraph().exists()).toBe(true); - expect(findAllPipelineStages().length).toBe(mockData.pipeline.details.stages.length); + it('should render pipeline graph with correct styles', () => { + const stagesCount = mockData.pipeline.details.stages.length; + + expect(findPipelineMiniGraph().exists()).toBe(true); + expect(findPipelineMiniGraph().findAll('.mr-widget-pipeline-stages')).toHaveLength( + stagesCount, + ); + + expect(findAllPipelineStages()).toHaveLength(stagesCount); }); it('should render coverage information', () => { @@ -181,7 +191,7 @@ describe('MRWidgetPipeline', () => { }); it('should not render a pipeline graph', () => { - expect(findPipelineGraph().exists()).toBe(false); + expect(findPipelineMiniGraph().exists()).toBe(false); }); }); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js index a33401c5ba9..a879b06e858 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js @@ -1,85 +1,88 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue'; +import { shallowMount } from '@vue/test-utils'; +import RelatedLinks from '~/vue_merge_request_widget/components/mr_widget_related_links.vue'; describe('MRWidgetRelatedLinks', () => { - let vm; + let wrapper; - const createComponent = (data) => { - const Component = Vue.extend(relatedLinksComponent); - - return mountComponent(Component, data); + const createComponent = (propsData = {}) => { + wrapper = shallowMount(RelatedLinks, { propsData }); }; afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); describe('computed', () => { describe('closesText', () => { it('returns Closes text for open merge request', () => { - vm = createComponent({ state: 'open', relatedLinks: {} }); + createComponent({ state: 'open', relatedLinks: {} }); - expect(vm.closesText).toEqual('Closes'); + expect(wrapper.vm.closesText).toBe('Closes'); }); it('returns correct text for closed merge request', () => { - vm = createComponent({ state: 'closed', relatedLinks: {} }); + createComponent({ state: 'closed', relatedLinks: {} }); - expect(vm.closesText).toEqual('Did not close'); + expect(wrapper.vm.closesText).toBe('Did not close'); }); it('returns correct tense for merged request', () => { - vm = createComponent({ state: 'merged', relatedLinks: {} }); + createComponent({ state: 'merged', relatedLinks: {} }); - expect(vm.closesText).toEqual('Closed'); + expect(wrapper.vm.closesText).toBe('Closed'); }); }); }); it('should have only have closing issues text', () => { - vm = createComponent({ + createComponent({ relatedLinks: { closing: '<a href="#">#23</a> and <a>#42</a>', }, }); - const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); + const content = wrapper + .text() + .replace(/\n(\s)+/g, ' ') + .trim(); expect(content).toContain('Closes #23 and #42'); expect(content).not.toContain('Mentions'); }); it('should have only have mentioned issues text', () => { - vm = createComponent({ + createComponent({ relatedLinks: { mentioned: '<a href="#">#7</a>', }, }); - expect(vm.$el.innerText).toContain('Mentions #7'); - expect(vm.$el.innerText).not.toContain('Closes'); + expect(wrapper.text().trim()).toContain('Mentions #7'); + expect(wrapper.text().trim()).not.toContain('Closes'); }); it('should have closing and mentioned issues at the same time', () => { - vm = createComponent({ + createComponent({ relatedLinks: { closing: '<a href="#">#7</a>', mentioned: '<a href="#">#23</a> and <a>#42</a>', }, }); - const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); + const content = wrapper + .text() + .replace(/\n(\s)+/g, ' ') + .trim(); expect(content).toContain('Closes #7'); expect(content).toContain('Mentions #23 and #42'); }); it('should have assing issues link', () => { - vm = createComponent({ + createComponent({ relatedLinks: { assignToMe: '<a href="#">Assign yourself to these issues</a>', }, }); - expect(vm.$el.innerText).toContain('Assign yourself to these issues'); + expect(wrapper.text().trim()).toContain('Assign yourself to these issues'); }); }); diff --git a/spec/frontend/vue_mr_widget/components/review_app_link_spec.js b/spec/frontend/vue_mr_widget/components/review_app_link_spec.js index 81a52890db7..e393b56034d 100644 --- a/spec/frontend/vue_mr_widget/components/review_app_link_spec.js +++ b/spec/frontend/vue_mr_widget/components/review_app_link_spec.js @@ -1,10 +1,8 @@ -import Vue from 'vue'; +import { shallowMount } from '@vue/test-utils'; import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import component from '~/vue_merge_request_widget/components/review_app_link.vue'; +import ReviewAppLink from '~/vue_merge_request_widget/components/review_app_link.vue'; describe('review app link', () => { - const Component = Vue.extend(component); const props = { link: '/review', cssClass: 'js-link', @@ -13,37 +11,35 @@ describe('review app link', () => { tooltip: '', }, }; - let vm; - let el; + let wrapper; beforeEach(() => { - vm = mountComponent(Component, props); - el = vm.$el; + wrapper = shallowMount(ReviewAppLink, { propsData: props }); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders provided link as href attribute', () => { - expect(el.getAttribute('href')).toEqual(props.link); + expect(wrapper.attributes('href')).toBe(props.link); }); it('renders provided cssClass as class attribute', () => { - expect(el.getAttribute('class')).toContain(props.cssClass); + expect(wrapper.classes('js-link')).toBe(true); }); it('renders View app text', () => { - expect(el.textContent.trim()).toEqual('View app'); + expect(wrapper.text().trim()).toBe('View app'); }); it('renders svg icon', () => { - expect(el.querySelector('svg')).not.toBeNull(); + expect(wrapper.find('svg')).not.toBeNull(); }); it('tracks an event when clicked', () => { - const spy = mockTracking('_category_', el, jest.spyOn); - triggerEvent(el); + const spy = mockTracking('_category_', wrapper.element, jest.spyOn); + triggerEvent(wrapper.element); expect(spy).toHaveBeenCalledWith('_category_', 'open_review_app', { label: 'review_app', diff --git a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap index c425a3a86a9..e5862df5dda 100644 --- a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap +++ b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap @@ -16,6 +16,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have > <span class="gl-mr-3" + data-qa-selector="merge_request_status_content" > <span class="js-status-text-before-author" @@ -107,6 +108,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c > <span class="gl-mr-3" + data-qa-selector="merge_request_status_content" > <span class="js-status-text-before-author" diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js index d3fc1e0e05b..dc2f227b29c 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js @@ -1,36 +1,41 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import $ from 'jquery'; +import { GlPopover } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; import { removeBreakLine } from 'helpers/text_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import ConflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; describe('MRWidgetConflicts', () => { - let vm; + let wrapper; let mergeRequestWidgetGraphql = null; const path = '/conflicts'; - function createComponent(propsData = {}) { - const localVue = createLocalVue(); + const findPopover = () => wrapper.find(GlPopover); + const findResolveButton = () => wrapper.findByTestId('resolve-conflicts-button'); + const findMergeLocalButton = () => wrapper.findByTestId('merge-locally-button'); - vm = shallowMount(localVue.extend(ConflictsComponent), { - propsData, - provide: { - glFeatures: { - mergeRequestWidgetGraphql, + function createComponent(propsData = {}) { + wrapper = extendedWrapper( + shallowMount(ConflictsComponent, { + propsData, + provide: { + glFeatures: { + mergeRequestWidgetGraphql, + }, }, - }, - mocks: { - $apollo: { - queries: { - userPermissions: { loading: false }, - stateData: { loading: false }, + mocks: { + $apollo: { + queries: { + userPermissions: { loading: false }, + stateData: { loading: false }, + }, }, }, - }, - }); + }), + ); if (mergeRequestWidgetGraphql) { - vm.setData({ + wrapper.setData({ userPermissions: { canMerge: propsData.mr.canMerge, pushToSourceBranch: propsData.mr.canPushToSourceBranch, @@ -42,16 +47,12 @@ describe('MRWidgetConflicts', () => { }); } - return vm.vm.$nextTick(); + return wrapper.vm.$nextTick(); } - beforeEach(() => { - jest.spyOn($.fn, 'popover'); - }); - afterEach(() => { mergeRequestWidgetGraphql = null; - vm.destroy(); + wrapper.destroy(); }); [false, true].forEach((featureEnabled) => { @@ -82,18 +83,16 @@ describe('MRWidgetConflicts', () => { }); it('should tell you about conflicts without bothering other people', () => { - expect(vm.text()).toContain('There are merge conflicts'); - expect(vm.text()).not.toContain('ask someone with write access'); + expect(wrapper.text()).toContain('There are merge conflicts'); + expect(wrapper.text()).not.toContain('ask someone with write access'); }); it('should not allow you to resolve the conflicts', () => { - expect(vm.text()).not.toContain('Resolve conflicts'); + expect(wrapper.text()).not.toContain('Resolve conflicts'); }); it('should have merge buttons', () => { - const mergeLocallyButton = vm.find('.js-merge-locally-button'); - - expect(mergeLocallyButton.text()).toContain('Merge locally'); + expect(findMergeLocalButton().text()).toContain('Merge locally'); }); }); @@ -110,19 +109,17 @@ describe('MRWidgetConflicts', () => { }); it('should tell you about conflicts', () => { - expect(vm.text()).toContain('There are merge conflicts'); - expect(vm.text()).toContain('ask someone with write access'); + expect(wrapper.text()).toContain('There are merge conflicts'); + expect(wrapper.text()).toContain('ask someone with write access'); }); it('should allow you to resolve the conflicts', () => { - const resolveButton = vm.find('.js-resolve-conflicts-button'); - - expect(resolveButton.text()).toContain('Resolve conflicts'); - expect(resolveButton.attributes('href')).toEqual(path); + expect(findResolveButton().text()).toContain('Resolve conflicts'); + expect(findResolveButton().attributes('href')).toEqual(path); }); it('should not have merge buttons', () => { - expect(vm.text()).not.toContain('Merge locally'); + expect(wrapper.text()).not.toContain('Merge locally'); }); }); @@ -139,21 +136,17 @@ describe('MRWidgetConflicts', () => { }); it('should tell you about conflicts without bothering other people', () => { - expect(vm.text()).toContain('There are merge conflicts'); - expect(vm.text()).not.toContain('ask someone with write access'); + expect(wrapper.text()).toContain('There are merge conflicts'); + expect(wrapper.text()).not.toContain('ask someone with write access'); }); it('should allow you to resolve the conflicts', () => { - const resolveButton = vm.find('.js-resolve-conflicts-button'); - - expect(resolveButton.text()).toContain('Resolve conflicts'); - expect(resolveButton.attributes('href')).toEqual(path); + expect(findResolveButton().text()).toContain('Resolve conflicts'); + expect(findResolveButton().attributes('href')).toEqual(path); }); it('should have merge buttons', () => { - const mergeLocallyButton = vm.find('.js-merge-locally-button'); - - expect(mergeLocallyButton.text()).toContain('Merge locally'); + expect(findMergeLocalButton().text()).toContain('Merge locally'); }); }); @@ -167,7 +160,7 @@ describe('MRWidgetConflicts', () => { }, }); - expect(vm.text().trim().replace(/\s\s+/g, ' ')).toContain( + expect(wrapper.text().trim().replace(/\s\s+/g, ' ')).toContain( 'ask someone with write access', ); }); @@ -181,8 +174,8 @@ describe('MRWidgetConflicts', () => { }, }); - expect(vm.find('.js-resolve-conflicts-button').exists()).toBe(false); - expect(vm.find('.js-merge-locally-button').exists()).toBe(false); + expect(findResolveButton().exists()).toBe(false); + expect(findMergeLocalButton().exists()).toBe(false); }); it('should not have resolve button when no conflict resolution path', async () => { @@ -194,7 +187,7 @@ describe('MRWidgetConflicts', () => { }, }); - expect(vm.find('.js-resolve-conflicts-button').exists()).toBe(false); + expect(findResolveButton().exists()).toBe(false); }); }); @@ -207,7 +200,7 @@ describe('MRWidgetConflicts', () => { }, }); - expect(removeBreakLine(vm.text()).trim()).toContain( + expect(removeBreakLine(wrapper.text()).trim()).toContain( 'Fast-forward merge is not possible. To merge this request, first rebase locally.', ); }); @@ -227,11 +220,11 @@ describe('MRWidgetConflicts', () => { }); it('sets resolve button as disabled', () => { - expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe('true'); + expect(findResolveButton().attributes('disabled')).toBe('true'); }); - it('renders popover', () => { - expect($.fn.popover).toHaveBeenCalled(); + it('shows the popover', () => { + expect(findPopover().exists()).toBe(true); }); }); @@ -249,11 +242,11 @@ describe('MRWidgetConflicts', () => { }); it('sets resolve button as disabled', () => { - expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe(undefined); + expect(findResolveButton().attributes('disabled')).toBe(undefined); }); - it('renders popover', () => { - expect($.fn.popover).not.toHaveBeenCalled(); + it('does not show the popover', () => { + expect(findPopover().exists()).toBe(false); }); }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js index 222cb74cc66..b16fb5171e7 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js @@ -1,29 +1,30 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue'; +import { shallowMount } from '@vue/test-utils'; +import MrWidgetMerging from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue'; describe('MRWidgetMerging', () => { - let vm; - beforeEach(() => { - const Component = Vue.extend(mergingComponent); + let wrapper; - vm = mountComponent(Component, { - mr: { - targetBranchPath: '/branch-path', - targetBranch: 'branch', + beforeEach(() => { + wrapper = shallowMount(MrWidgetMerging, { + propsData: { + mr: { + targetBranchPath: '/branch-path', + targetBranch: 'branch', + }, }, }); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders information about merge request being merged', () => { expect( - vm.$el - .querySelector('.media-body') - .textContent.trim() + wrapper + .find('.media-body') + .text() + .trim() .replace(/\s\s+/g, ' ') .replace(/[\r\n]+/g, ' '), ).toContain('This merge request is in the process of being merged'); @@ -31,13 +32,14 @@ describe('MRWidgetMerging', () => { it('renders branch information', () => { expect( - vm.$el - .querySelector('.mr-info-list') - .textContent.trim() + wrapper + .find('.mr-info-list') + .text() + .trim() .replace(/\s\s+/g, ' ') .replace(/[\r\n]+/g, ' '), ).toEqual('The changes will be merged into branch'); - expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('/branch-path'); + expect(wrapper.find('a').attributes('href')).toBe('/branch-path'); }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js index bd0bd36ebc2..2c04905d3a9 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js @@ -14,20 +14,14 @@ describe('NothingToMerge', () => { it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(vm.$el.querySelector('a').href).toContain(newBlobPath); - expect(vm.$el.innerText).toContain( - "Currently there are no changes in this merge request's source branch", - ); - - expect(vm.$el.innerText.replace(/\s\s+/g, ' ')).toContain( - 'Please push new commits or use a different branch.', - ); + expect(vm.$el.querySelector('[data-testid="createFileButton"]').href).toContain(newBlobPath); + expect(vm.$el.innerText).toContain('Use merge requests to propose changes to your project'); }); it('should not show new blob link if there is no link available', () => { vm.mr.newBlobPath = null; Vue.nextTick(() => { - expect(vm.$el.querySelector('a')).toEqual(null); + expect(vm.$el.querySelector('[data-testid="createFileButton"]')).toEqual(null); }); }); }); diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_list_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_list_spec.js new file mode 100644 index 00000000000..dd0c483b28a --- /dev/null +++ b/spec/frontend/vue_mr_widget/deployment/deployment_list_spec.js @@ -0,0 +1,101 @@ +import { mount } from '@vue/test-utils'; +import { zip } from 'lodash'; +import { trimText } from 'helpers/text_helper'; +import Deployment from '~/vue_merge_request_widget/components/deployment/deployment.vue'; +import DeploymentList from '~/vue_merge_request_widget/components/deployment/deployment_list.vue'; +import MrCollapsibleExtension from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue'; +import { mockStore } from '../mock_data'; + +const DEFAULT_PROPS = { + showVisualReviewAppLink: false, + hasDeploymentMetrics: false, + deploymentClass: 'js-pre-deployment', +}; + +describe('~/vue_merge_request_widget/components/deployment/deployment_list.vue', () => { + let wrapper; + let propsData; + + const factory = (props = {}) => { + propsData = { + ...DEFAULT_PROPS, + deployments: mockStore.deployments, + ...props, + }; + wrapper = mount(DeploymentList, { + propsData, + }); + }; + + afterEach(() => { + wrapper?.destroy?.(); + wrapper = null; + }); + + describe('with few deployments', () => { + beforeEach(() => { + factory(); + }); + + it('shows all deployments', () => { + const deploymentWrappers = wrapper.findAllComponents(Deployment); + expect(wrapper.findComponent(MrCollapsibleExtension).exists()).toBe(false); + expect(deploymentWrappers).toHaveLength(propsData.deployments.length); + + zip(deploymentWrappers.wrappers, propsData.deployments).forEach( + ([deploymentWrapper, deployment]) => { + expect(deploymentWrapper.props('deployment')).toEqual(deployment); + expect(deploymentWrapper.props()).toMatchObject({ + showVisualReviewApp: DEFAULT_PROPS.showVisualReviewAppLink, + showMetrics: DEFAULT_PROPS.hasDeploymentMetrics, + }); + expect(deploymentWrapper.classes(DEFAULT_PROPS.deploymentClass)).toBe(true); + expect(deploymentWrapper.text()).toEqual(expect.any(String)); + expect(deploymentWrapper.text()).not.toBe(''); + }, + ); + }); + }); + describe('with many deployments', () => { + let deployments; + let collapsibleExtension; + + beforeEach(() => { + deployments = [ + ...mockStore.deployments, + ...mockStore.deployments.map((deployment) => ({ + ...deployment, + id: deployment.id + mockStore.deployments.length, + })), + ]; + factory({ deployments }); + + collapsibleExtension = wrapper.findComponent(MrCollapsibleExtension); + }); + + it('shows collapsed deployments', () => { + expect(collapsibleExtension.exists()).toBe(true); + expect(trimText(collapsibleExtension.text())).toBe( + `${deployments.length} environments impacted. View all environments.`, + ); + }); + it('shows all deployments on click', async () => { + await collapsibleExtension.find('button').trigger('click'); + const deploymentWrappers = wrapper.findAllComponents(Deployment); + expect(deploymentWrappers).toHaveLength(deployments.length); + + zip(deploymentWrappers.wrappers, propsData.deployments).forEach( + ([deploymentWrapper, deployment]) => { + expect(deploymentWrapper.props('deployment')).toEqual(deployment); + expect(deploymentWrapper.props()).toMatchObject({ + showVisualReviewApp: DEFAULT_PROPS.showVisualReviewAppLink, + showMetrics: DEFAULT_PROPS.hasDeploymentMetrics, + }); + expect(deploymentWrapper.classes(DEFAULT_PROPS.deploymentClass)).toBe(true); + expect(deploymentWrapper.text()).toEqual(expect.any(String)); + expect(deploymentWrapper.text()).not.toBe(''); + }, + ); + }); + }); +}); diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js index 7b020813bd5..c4962b608e1 100644 --- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js @@ -91,18 +91,6 @@ describe('MrWidgetOptions', () => { }); }); - describe('shouldRenderMergeHelp', () => { - it('should return false for the initial merged state', () => { - expect(wrapper.vm.shouldRenderMergeHelp).toBeFalsy(); - }); - - it('should return true for a state which requires help widget', () => { - wrapper.vm.mr.state = 'conflicts'; - - expect(wrapper.vm.shouldRenderMergeHelp).toBeTruthy(); - }); - }); - describe('shouldRenderPipelines', () => { it('should return true when hasCI is true', () => { wrapper.vm.mr.hasCI = true; |