From 9dc93a4519d9d5d7be48ff274127136236a3adb3 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 20 Apr 2021 23:50:22 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-11-stable-ee --- .../components/mr_widget_author_time_spec.js | 43 +++--- .../components/mr_widget_header_spec.js | 156 +++++++++---------- .../components/mr_widget_pipeline_spec.js | 91 ++++++----- .../states/mr_widget_auto_merge_enabled_spec.js | 29 +++- .../components/states/mr_widget_conflicts_spec.js | 19 +-- .../states/mr_widget_failed_to_merge_spec.js | 166 ++++++++++----------- 6 files changed, 263 insertions(+), 241 deletions(-) (limited to 'spec/frontend/vue_mr_widget') diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js index 78efcb6e695..8fd93809e01 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js @@ -1,42 +1,43 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; +import { shallowMount } from '@vue/test-utils'; +import MrWidgetAuthor from '~/vue_merge_request_widget/components/mr_widget_author.vue'; import MrWidgetAuthorTime from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; describe('MrWidgetAuthorTime', () => { - let vm; + let wrapper; + + const defaultProps = { + actionText: 'Merged by', + author: { + name: 'Administrator', + username: 'root', + webUrl: 'http://localhost:3000/root', + avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + }, + dateTitle: '2017-03-23T23:02:00.807Z', + dateReadable: '12 hours ago', + }; beforeEach(() => { - const Component = Vue.extend(MrWidgetAuthorTime); - - vm = mountComponent(Component, { - actionText: 'Merged by', - author: { - name: 'Administrator', - username: 'root', - webUrl: 'http://localhost:3000/root', - avatarUrl: - 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - }, - dateTitle: '2017-03-23T23:02:00.807Z', - dateReadable: '12 hours ago', + wrapper = shallowMount(MrWidgetAuthorTime, { + propsData: defaultProps, }); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders provided action text', () => { - expect(vm.$el.textContent).toContain('Merged by'); + expect(wrapper.text()).toContain('Merged by'); }); it('renders author', () => { - expect(vm.$el.textContent).toContain('Administrator'); + expect(wrapper.find(MrWidgetAuthor).props('author')).toStrictEqual(defaultProps.author); }); it('renders provided time', () => { - expect(vm.$el.querySelector('time').getAttribute('title')).toEqual('2017-03-23T23:02:00.807Z'); + expect(wrapper.find('time').attributes('title')).toBe('2017-03-23T23:02:00.807Z'); - expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago'); + expect(wrapper.find('time').text().trim()).toBe('12 hours ago'); }); }); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js index db884dfe015..eadf07e54fb 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js @@ -1,38 +1,35 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import Header from '~/vue_merge_request_widget/components/mr_widget_header.vue'; describe('MRWidgetHeader', () => { - let vm; - let Component; + let wrapper; - beforeEach(() => { - Component = Vue.extend(headerComponent); - }); + const createComponent = (propsData = {}) => { + wrapper = shallowMount(Header, { + propsData, + }); + }; afterEach(() => { - vm.$destroy(); + wrapper.destroy(); gon.relative_url_root = ''; }); const expectDownloadDropdownItems = () => { - const downloadEmailPatchesEl = vm.$el.querySelector('.js-download-email-patches'); - const downloadPlainDiffEl = vm.$el.querySelector('.js-download-plain-diff'); - - expect(downloadEmailPatchesEl.innerText.trim()).toEqual('Email patches'); - expect(downloadEmailPatchesEl.querySelector('a').getAttribute('href')).toEqual( - '/mr/email-patches', - ); - expect(downloadPlainDiffEl.innerText.trim()).toEqual('Plain diff'); - expect(downloadPlainDiffEl.querySelector('a').getAttribute('href')).toEqual( - '/mr/plainDiffPath', - ); + const downloadEmailPatchesEl = wrapper.find('.js-download-email-patches'); + const downloadPlainDiffEl = wrapper.find('.js-download-plain-diff'); + + expect(downloadEmailPatchesEl.text().trim()).toBe('Email patches'); + expect(downloadEmailPatchesEl.attributes('href')).toBe('/mr/email-patches'); + expect(downloadPlainDiffEl.text().trim()).toBe('Plain diff'); + expect(downloadPlainDiffEl.attributes('href')).toBe('/mr/plainDiffPath'); }; describe('computed', () => { describe('shouldShowCommitsBehindText', () => { it('return true when there are divergedCommitsCount', () => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', @@ -42,11 +39,11 @@ describe('MRWidgetHeader', () => { }, }); - expect(vm.shouldShowCommitsBehindText).toEqual(true); + expect(wrapper.vm.shouldShowCommitsBehindText).toBe(true); }); it('returns false where there are no divergedComits count', () => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 0, sourceBranch: 'mr-widget-refactor', @@ -56,13 +53,13 @@ describe('MRWidgetHeader', () => { }, }); - expect(vm.shouldShowCommitsBehindText).toEqual(false); + expect(wrapper.vm.shouldShowCommitsBehindText).toBe(false); }); }); describe('commitsBehindText', () => { it('returns singular when there is one commit', () => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 1, sourceBranch: 'mr-widget-refactor', @@ -73,13 +70,13 @@ describe('MRWidgetHeader', () => { }, }); - expect(vm.commitsBehindText).toEqual( + expect(wrapper.vm.commitsBehindText).toBe( 'The source branch is 1 commit behind the target branch', ); }); it('returns plural when there is more than one commit', () => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 2, sourceBranch: 'mr-widget-refactor', @@ -90,7 +87,7 @@ describe('MRWidgetHeader', () => { }, }); - expect(vm.commitsBehindText).toEqual( + expect(wrapper.vm.commitsBehindText).toBe( 'The source branch is 2 commits behind the target branch', ); }); @@ -100,7 +97,7 @@ describe('MRWidgetHeader', () => { describe('template', () => { describe('common elements', () => { beforeEach(() => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', @@ -118,17 +115,17 @@ describe('MRWidgetHeader', () => { }); it('renders source branch link', () => { - expect(vm.$el.querySelector('.js-source-branch').innerHTML).toEqual( + expect(wrapper.find('.js-source-branch').html()).toContain( 'mr-widget-refactor', ); }); it('renders clipboard button', () => { - expect(vm.$el.querySelector('[data-testid="mr-widget-copy-clipboard"]')).not.toEqual(null); + expect(wrapper.find('[data-testid="mr-widget-copy-clipboard"]')).not.toBe(null); }); it('renders target branch', () => { - expect(vm.$el.querySelector('.js-target-branch').textContent.trim()).toEqual('master'); + expect(wrapper.find('.js-target-branch').text().trim()).toBe('master'); }); }); @@ -151,71 +148,68 @@ describe('MRWidgetHeader', () => { targetProjectFullPath: 'gitlab-org/gitlab-ce', }; - afterEach(() => { - vm.$destroy(); - }); - beforeEach(() => { - vm = mountComponent(Component, { + createComponent({ mr: { ...mrDefaultOptions }, }); }); it('renders checkout branch button with modal trigger', () => { - const button = vm.$el.querySelector('.js-check-out-branch'); + const button = wrapper.find('.js-check-out-branch'); - expect(button.textContent.trim()).toBe('Check out branch'); + expect(button.text().trim()).toBe('Check out branch'); }); - it('renders web ide button', () => { - const button = vm.$el.querySelector('.js-web-ide'); + it('renders web ide button', async () => { + const button = wrapper.find('.js-web-ide'); - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.classList.contains('disabled')).toBe(false); - expect(button.getAttribute('href')).toEqual( + await nextTick(); + + expect(button.text().trim()).toBe('Open in Web IDE'); + expect(button.classes('disabled')).toBe(false); + expect(button.attributes('href')).toBe( '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org%2Fgitlab-ce', ); }); - it('renders web ide button in disabled state with no href', () => { + it('renders web ide button in disabled state with no href', async () => { const mr = { ...mrDefaultOptions, canPushToSourceBranch: false }; - vm = mountComponent(Component, { mr }); + createComponent({ mr }); + + await nextTick(); - const link = vm.$el.querySelector('.js-web-ide'); + const link = wrapper.find('.js-web-ide'); - expect(link.classList.contains('disabled')).toBe(true); - expect(link.getAttribute('href')).toBeNull(); + expect(link.attributes('disabled')).toBe('true'); + expect(link.attributes('href')).toBeUndefined(); }); - it('renders web ide button with blank query string if target & source project branch', (done) => { - vm.mr.targetProjectFullPath = 'root/gitlab-ce'; + it('renders web ide button with blank query string if target & source project branch', async () => { + createComponent({ mr: { ...mrDefaultOptions, targetProjectFullPath: 'root/gitlab-ce' } }); - vm.$nextTick(() => { - const button = vm.$el.querySelector('.js-web-ide'); + await nextTick(); - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual( - '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=', - ); + const button = wrapper.find('.js-web-ide'); - done(); - }); + expect(button.text().trim()).toBe('Open in Web IDE'); + expect(button.attributes('href')).toBe( + '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=', + ); }); - it('renders web ide button with relative URL', (done) => { + it('renders web ide button with relative URL', async () => { gon.relative_url_root = '/gitlab'; - vm.mr.iid = 2; - vm.$nextTick(() => { - const button = vm.$el.querySelector('.js-web-ide'); + createComponent({ mr: { ...mrDefaultOptions, iid: 2 } }); - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual( - '/gitlab/-/ide/project/root/gitlab-ce/merge_requests/2?target_project=gitlab-org%2Fgitlab-ce', - ); + await nextTick(); - done(); - }); + const button = wrapper.find('.js-web-ide'); + + expect(button.text().trim()).toBe('Open in Web IDE'); + expect(button.attributes('href')).toBe( + '/gitlab/-/ide/project/root/gitlab-ce/merge_requests/2?target_project=gitlab-org%2Fgitlab-ce', + ); }); it('renders download dropdown with links', () => { @@ -225,7 +219,7 @@ describe('MRWidgetHeader', () => { describe('with a closed merge request', () => { beforeEach(() => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', @@ -243,9 +237,9 @@ describe('MRWidgetHeader', () => { }); it('does not render checkout branch button with modal trigger', () => { - const button = vm.$el.querySelector('.js-check-out-branch'); + const button = wrapper.find('.js-check-out-branch'); - expect(button).toEqual(null); + expect(button.exists()).toBe(false); }); it('renders download dropdown with links', () => { @@ -255,7 +249,7 @@ describe('MRWidgetHeader', () => { describe('without diverged commits', () => { beforeEach(() => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 0, sourceBranch: 'mr-widget-refactor', @@ -273,13 +267,13 @@ describe('MRWidgetHeader', () => { }); it('does not render diverged commits info', () => { - expect(vm.$el.querySelector('.diverged-commits-count')).toEqual(null); + expect(wrapper.find('.diverged-commits-count').exists()).toBe(false); }); }); describe('with diverged commits', () => { beforeEach(() => { - vm = mountComponent(Component, { + createComponent({ mr: { divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', @@ -297,17 +291,13 @@ describe('MRWidgetHeader', () => { }); it('renders diverged commits info', () => { - expect(vm.$el.querySelector('.diverged-commits-count').textContent).toEqual( + expect(wrapper.find('.diverged-commits-count').text().trim()).toBe( 'The source branch is 12 commits behind the target branch', ); - expect(vm.$el.querySelector('.diverged-commits-count a').textContent).toEqual( - '12 commits behind', - ); - - expect(vm.$el.querySelector('.diverged-commits-count a')).toHaveAttr( - 'href', - vm.mr.targetBranchPath, + expect(wrapper.find('.diverged-commits-count a').text().trim()).toBe('12 commits behind'); + expect(wrapper.find('.diverged-commits-count a').attributes('href')).toBe( + wrapper.vm.mr.targetBranchPath, ); }); }); 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 28492018600..924dc37aab9 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,6 +1,7 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { shallowMount, mount } from '@vue/test-utils'; import { trimText } from 'helpers/text_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; 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'; @@ -22,27 +23,31 @@ describe('MRWidgetPipeline', () => { 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.'; const monitoringMessage = 'Checking pipeline status.'; - const findCIErrorMessage = () => wrapper.find('[data-testid="ci-error-message"]'); - 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 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"]'); + const findCIErrorMessage = () => wrapper.findByTestId('ci-error-message'); + const findPipelineID = () => wrapper.findByTestId('pipeline-id'); + const findPipelineInfoContainer = () => wrapper.findByTestId('pipeline-info-container'); + const findCommitLink = () => wrapper.findByTestId('commit-link'); + const findPipelineFinishedAt = () => wrapper.findByTestId('finished-at'); + const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph); + const findAllPipelineStages = () => wrapper.findAllComponents(PipelineStage); + const findPipelineCoverage = () => wrapper.findByTestId('pipeline-coverage'); + const findPipelineCoverageDelta = () => wrapper.findByTestId('pipeline-coverage-delta'); const findPipelineCoverageTooltipText = () => - wrapper.find('[data-testid="pipeline-coverage-tooltip"]').text(); - const findMonitoringPipelineMessage = () => - wrapper.find('[data-testid="monitoring-pipeline-message"]'); - const findLoadingIcon = () => wrapper.find(GlLoadingIcon); + wrapper.findByTestId('pipeline-coverage-tooltip').text(); + const findPipelineCoverageDeltaTooltipText = () => + wrapper.findByTestId('pipeline-coverage-delta-tooltip').text(); + const findMonitoringPipelineMessage = () => wrapper.findByTestId('monitoring-pipeline-message'); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const createWrapper = (props = {}, mountFn = shallowMount) => { - wrapper = mountFn(PipelineComponent, { - propsData: { - ...defaultProps, - ...props, - }, - }); + wrapper = extendedWrapper( + mountFn(PipelineComponent, { + propsData: { + ...defaultProps, + ...props, + }, + }), + ); }; afterEach(() => { @@ -87,6 +92,13 @@ describe('MRWidgetPipeline', () => { expect(findCommitLink().attributes('href')).toBe(mockData.pipeline.commit.commit_path); }); + it('should render pipeline finished timestamp', () => { + expect(findPipelineFinishedAt().attributes()).toMatchObject({ + title: 'Apr 7, 2017 2:00pm GMT+0000', + datetime: mockData.pipeline.details.finished_at, + }); + }); + it('should render pipeline graph', () => { expect(findPipelineMiniGraph().exists()).toBe(true); expect(findAllPipelineStages()).toHaveLength(mockData.pipeline.details.stages.length); @@ -94,7 +106,9 @@ describe('MRWidgetPipeline', () => { describe('should render pipeline coverage information', () => { it('should render coverage percentage', () => { - expect(findPipelineCoverage().text()).toMatch(`Coverage ${mockData.pipeline.coverage}%`); + expect(findPipelineCoverage().text()).toMatch( + `Test coverage ${mockData.pipeline.coverage}%`, + ); }); it('should render coverage delta', () => { @@ -102,24 +116,9 @@ describe('MRWidgetPipeline', () => { expect(findPipelineCoverageDelta().text()).toBe(`(${mockData.pipelineCoverageDelta}%)`); }); - it('coverage delta should have no special style if there is no coverage change', () => { - createWrapper({ pipelineCoverageDelta: '0' }); - expect(findPipelineCoverageDelta().classes()).toEqual([]); - }); - - it('coverage delta should have text-success style if coverage increased', () => { - createWrapper({ pipelineCoverageDelta: '10' }); - expect(findPipelineCoverageDelta().classes()).toEqual(['text-success']); - }); - - it('coverage delta should have text-danger style if coverage increased', () => { - createWrapper({ pipelineCoverageDelta: '-10' }); - expect(findPipelineCoverageDelta().classes()).toEqual(['text-danger']); - }); - it('should render tooltip for jobs contributing to code coverage', () => { const tooltipText = findPipelineCoverageTooltipText(); - const expectedDescription = `Coverage value for this pipeline was calculated by averaging the resulting coverage values of ${mockData.buildsWithCoverage.length} jobs.`; + const expectedDescription = `Test coverage value for this pipeline was calculated by averaging the resulting coverage values of ${mockData.buildsWithCoverage.length} jobs.`; expect(tooltipText).toContain(expectedDescription); }); @@ -132,6 +131,26 @@ describe('MRWidgetPipeline', () => { expect(tooltipText).toContain(`${build.name} (${build.coverage}%)`); }, ); + + describe.each` + style | coverageState | coverageChangeText | styleClass | pipelineCoverageDelta + ${'no special'} | ${'the same'} | ${'not change'} | ${''} | ${'0'} + ${'success'} | ${'increased'} | ${'increase'} | ${'text-success'} | ${'10'} + ${'danger'} | ${'decreased'} | ${'decrease'} | ${'text-danger'} | ${'-10'} + `( + 'if test coverage is $coverageState', + ({ style, styleClass, coverageChangeText, pipelineCoverageDelta }) => { + it(`coverage delta should have ${style}`, () => { + createWrapper({ pipelineCoverageDelta }); + expect(findPipelineCoverageDelta().classes()).toEqual(styleClass ? [styleClass] : []); + }); + + it(`coverage delta tooltip should say that the coverage will ${coverageChangeText}`, () => { + createWrapper({ pipelineCoverageDelta }); + expect(findPipelineCoverageDeltaTooltipText()).toContain(coverageChangeText); + }); + }, + ); }); }); @@ -163,7 +182,7 @@ describe('MRWidgetPipeline', () => { }); it('should render coverage information', () => { - expect(findPipelineCoverage().text()).toMatch(`Coverage ${mockData.pipeline.coverage}%`); + expect(findPipelineCoverage().text()).toMatch(`Test coverage ${mockData.pipeline.coverage}%`); }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js index 4dd1bd2aa9c..1af96717b56 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js @@ -28,11 +28,11 @@ function convertPropsToGraphqlState(props) { }; } -function factory(propsData) { +function factory(propsData, stateOverride = {}) { let state = {}; if (mergeRequestWidgetGraphqlEnabled) { - state = convertPropsToGraphqlState(propsData); + state = { ...convertPropsToGraphqlState(propsData), ...stateOverride }; } wrapper = extendedWrapper( @@ -125,7 +125,7 @@ describe('MRWidgetAutoMergeEnabled', () => { }, ); - it('should return false when shouldRemoveSourceBranch set to false', () => { + it('should not find "Delete" button when shouldRemoveSourceBranch set to true', () => { factory({ ...defaultMrProps(), shouldRemoveSourceBranch: true, @@ -134,6 +134,29 @@ describe('MRWidgetAutoMergeEnabled', () => { expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(false); }); + it('should find "Delete" button when shouldRemoveSourceBranch overrides state.forceRemoveSourceBranch', () => { + factory( + { + ...defaultMrProps(), + shouldRemoveSourceBranch: false, + }, + { + forceRemoveSourceBranch: true, + }, + ); + + expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(true); + }); + + it('should find "Delete" button when shouldRemoveSourceBranch set to false', () => { + factory({ + ...defaultMrProps(), + shouldRemoveSourceBranch: false, + }); + + expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(true); + }); + it('should return false if user is not able to remove the source branch', () => { factory({ ...defaultMrProps(), 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 dc2f227b29c..fee78d3af94 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,4 +1,3 @@ -import { GlPopover } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; import { removeBreakLine } from 'helpers/text_helper'; @@ -10,7 +9,6 @@ describe('MRWidgetConflicts', () => { let mergeRequestWidgetGraphql = null; const path = '/conflicts'; - const findPopover = () => wrapper.find(GlPopover); const findResolveButton = () => wrapper.findByTestId('resolve-conflicts-button'); const findMergeLocalButton = () => wrapper.findByTestId('merge-locally-button'); @@ -219,12 +217,8 @@ describe('MRWidgetConflicts', () => { }); }); - it('sets resolve button as disabled', () => { - expect(findResolveButton().attributes('disabled')).toBe('true'); - }); - - it('shows the popover', () => { - expect(findPopover().exists()).toBe(true); + it('should not allow you to resolve the conflicts', () => { + expect(findResolveButton().exists()).toBe(false); }); }); @@ -241,12 +235,9 @@ describe('MRWidgetConflicts', () => { }); }); - it('sets resolve button as disabled', () => { - expect(findResolveButton().attributes('disabled')).toBe(undefined); - }); - - it('does not show the popover', () => { - expect(findPopover().exists()).toBe(false); + it('should allow you to resolve the conflicts', () => { + expect(findResolveButton().text()).toContain('Resolve conflicts'); + expect(findResolveButton().attributes('href')).toEqual(TEST_HOST); }); }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js index c1471314c4a..6d8e7056366 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js @@ -1,69 +1,67 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue'; +import MrWidgetFailedToMerge from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue'; import eventHub from '~/vue_merge_request_widget/event_hub'; describe('MRWidgetFailedToMerge', () => { const dummyIntervalId = 1337; - let Component; - let mr; - let vm; + let wrapper; + + const createComponent = (props = {}, data = {}) => { + wrapper = shallowMount(MrWidgetFailedToMerge, { + propsData: { + mr: { + mergeError: 'Merge error happened', + }, + ...props, + }, + data() { + return data; + }, + }); + }; beforeEach(() => { - Component = Vue.extend(failedToMergeComponent); jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); jest.spyOn(window, 'setInterval').mockReturnValue(dummyIntervalId); jest.spyOn(window, 'clearInterval').mockImplementation(); - mr = { - mergeError: 'Merge error happened', - }; - vm = mountComponent(Component, { - mr, - }); }); afterEach(() => { - vm.$destroy(); - }); - - it('sets interval to refresh', () => { - expect(window.setInterval).toHaveBeenCalledWith(vm.updateTimer, 1000); - expect(vm.intervalId).toBe(dummyIntervalId); + wrapper.destroy(); }); - it('clears interval when destroying ', () => { - vm.$destroy(); + describe('interval', () => { + it('sets interval to refresh', () => { + createComponent(); - expect(window.clearInterval).toHaveBeenCalledWith(dummyIntervalId); - }); - - describe('computed', () => { - describe('timerText', () => { - it('should return correct timer text', () => { - expect(vm.timerText).toEqual('Refreshing in 10 seconds to show the updated status...'); + expect(window.setInterval).toHaveBeenCalledWith(wrapper.vm.updateTimer, 1000); + expect(wrapper.vm.intervalId).toBe(dummyIntervalId); + }); - vm.timer = 1; + it('clears interval when destroying ', () => { + createComponent(); + wrapper.destroy(); - expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...'); - }); + expect(window.clearInterval).toHaveBeenCalledWith(dummyIntervalId); }); + }); - describe('mergeError', () => { - it('removes forced line breaks', (done) => { - mr.mergeError = 'contains
line breaks
'; + describe('mergeError', () => { + it('removes forced line breaks', async () => { + createComponent({ mr: { mergeError: 'contains
line breaks
' } }); - Vue.nextTick() - .then(() => { - expect(vm.mergeError).toBe('contains line breaks.'); - }) - .then(done) - .catch(done.fail); - }); + await nextTick(); + + expect(wrapper.vm.mergeError).toBe('contains line breaks.'); }); }); describe('created', () => { it('should disable polling', () => { + createComponent(); + expect(eventHub.$emit).toHaveBeenCalledWith('DisablePolling'); }); }); @@ -71,11 +69,13 @@ describe('MRWidgetFailedToMerge', () => { describe('methods', () => { describe('refresh', () => { it('should emit event to request component refresh', () => { - expect(vm.isRefreshing).toEqual(false); + createComponent(); + + expect(wrapper.vm.isRefreshing).toBe(false); - vm.refresh(); + wrapper.vm.refresh(); - expect(vm.isRefreshing).toEqual(true); + expect(wrapper.vm.isRefreshing).toBe(true); expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); expect(eventHub.$emit).toHaveBeenCalledWith('EnablePolling'); }); @@ -83,78 +83,76 @@ describe('MRWidgetFailedToMerge', () => { describe('updateTimer', () => { it('should update timer and emit event when timer end', () => { - jest.spyOn(vm, 'refresh').mockImplementation(() => {}); + createComponent(); + + jest.spyOn(wrapper.vm, 'refresh').mockImplementation(() => {}); - expect(vm.timer).toEqual(10); + expect(wrapper.vm.timer).toEqual(10); for (let i = 0; i < 10; i += 1) { - expect(vm.timer).toEqual(10 - i); - vm.updateTimer(); + expect(wrapper.vm.timer).toEqual(10 - i); + wrapper.vm.updateTimer(); } - expect(vm.refresh).toHaveBeenCalled(); + expect(wrapper.vm.refresh).toHaveBeenCalled(); }); }); }); describe('while it is refreshing', () => { - it('renders Refresing now', (done) => { - vm.isRefreshing = true; - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.js-refresh-label').textContent.trim()).toEqual( - 'Refreshing now', - ); - done(); - }); + it('renders Refresing now', async () => { + createComponent({}, { isRefreshing: true }); + + await nextTick(); + + expect(wrapper.find('.js-refresh-label').text().trim()).toBe('Refreshing now'); }); }); describe('while it is not regresing', () => { + beforeEach(() => { + createComponent(); + }); + it('renders warning icon and disabled merge button', () => { - expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull(); - expect( - vm.$el.querySelector('[data-testid="disabled-merge-button"]').getAttribute('disabled'), - ).toEqual('disabled'); + expect(wrapper.find('.js-ci-status-icon-warning')).not.toBeNull(); + expect(wrapper.find(StatusIcon).props('showDisabledButton')).toBe(true); }); it('renders given error', () => { - expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual( - 'Merge error happened.', - ); + expect(wrapper.find('.has-error-message').text().trim()).toBe('Merge error happened.'); }); it('renders refresh button', () => { expect( - vm.$el - .querySelector('[data-testid="merge-request-failed-refresh-button"]') - .textContent.trim(), - ).toEqual('Refresh now'); + wrapper.find('[data-testid="merge-request-failed-refresh-button"]').text().trim(), + ).toBe('Refresh now'); }); it('renders remaining time', () => { - expect(vm.$el.querySelector('.has-custom-error').textContent.trim()).toEqual( + expect(wrapper.find('.has-custom-error').text().trim()).toBe( 'Refreshing in 10 seconds to show the updated status...', ); }); }); - it('should just generic merge failed message if merge_error is not available', (done) => { - vm.mr.mergeError = null; + it('should just generic merge failed message if merge_error is not available', async () => { + createComponent({ mr: { mergeError: null } }); - Vue.nextTick(() => { - expect(vm.$el.innerText).toContain('Merge failed.'); - expect(vm.$el.innerText).not.toContain('Merge error happened.'); - done(); - }); + await nextTick(); + + expect(wrapper.text().trim()).toContain('Merge failed.'); + expect(wrapper.text().trim()).not.toContain('Merge error happened.'); }); - it('should show refresh label when refresh requested', (done) => { - vm.refresh(); - Vue.nextTick(() => { - expect(vm.$el.innerText).not.toContain('Merge failed. Refreshing'); - expect(vm.$el.innerText).toContain('Refreshing now'); - done(); - }); + it('should show refresh label when refresh requested', async () => { + createComponent(); + + wrapper.vm.refresh(); + + await nextTick(); + + expect(wrapper.text().trim()).not.toContain('Merge failed. Refreshing'); + expect(wrapper.text().trim()).toContain('Refreshing now'); }); }); -- cgit v1.2.3