diff options
Diffstat (limited to 'spec/javascripts/vue_mr_widget/components')
29 files changed, 0 insertions, 3817 deletions
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js deleted file mode 100644 index f78fcfb52b4..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js +++ /dev/null @@ -1,76 +0,0 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlLink } from '@gitlab/ui'; -import MrWidgetAlertMessage from '~/vue_merge_request_widget/components/mr_widget_alert_message.vue'; - -describe('MrWidgetAlertMessage', () => { - let wrapper; - - beforeEach(() => { - const localVue = createLocalVue(); - - wrapper = shallowMount(localVue.extend(MrWidgetAlertMessage), { - propsData: {}, - localVue, - }); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when type is not provided', () => { - it('should render a red message', done => { - wrapper.vm.$nextTick(() => { - expect(wrapper.classes()).toContain('danger_message'); - expect(wrapper.classes()).not.toContain('warning_message'); - done(); - }); - }); - }); - - describe('when type === "danger"', () => { - it('should render a red message', done => { - wrapper.setProps({ type: 'danger' }); - wrapper.vm.$nextTick(() => { - expect(wrapper.classes()).toContain('danger_message'); - expect(wrapper.classes()).not.toContain('warning_message'); - done(); - }); - }); - }); - - describe('when type === "warning"', () => { - it('should render a red message', done => { - wrapper.setProps({ type: 'warning' }); - wrapper.vm.$nextTick(() => { - expect(wrapper.classes()).toContain('warning_message'); - expect(wrapper.classes()).not.toContain('danger_message'); - done(); - }); - }); - }); - - describe('when helpPath is not provided', () => { - it('should not render a help icon/link', done => { - wrapper.vm.$nextTick(() => { - const link = wrapper.find(GlLink); - - expect(link.exists()).toBe(false); - done(); - }); - }); - }); - - describe('when helpPath is provided', () => { - it('should render a help icon/link', done => { - wrapper.setProps({ helpPath: '/path/to/help/docs' }); - wrapper.vm.$nextTick(() => { - const link = wrapper.find(GlLink); - - expect(link.exists()).toBe(true); - expect(link.attributes().href).toBe('/path/to/help/docs'); - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js deleted file mode 100644 index a942a9dec87..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import MrWidgetAuthor from '~/vue_merge_request_widget/components/mr_widget_author.vue'; - -describe('MrWidgetAuthor', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(MrWidgetAuthor); - - vm = mountComponent(Component, { - author: { - name: 'Administrator', - username: 'root', - webUrl: 'http://localhost:3000/root', - avatarUrl: - 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders link with the author web url', () => { - expect(vm.$el.getAttribute('href')).toEqual('http://localhost:3000/root'); - }); - - it('renders image with avatar url', () => { - expect(vm.$el.querySelector('img').getAttribute('src')).toEqual( - 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - ); - }); - - it('renders author name', () => { - expect(vm.$el.textContent.trim()).toEqual('Administrator'); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js deleted file mode 100644 index 55af2baa924..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js +++ /dev/null @@ -1,44 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import MrWidgetAuthorTime from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; - -describe('MrWidgetAuthorTime', () => { - let vm; - - 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', - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders provided action text', () => { - expect(vm.$el.textContent).toContain('Merged by'); - }); - - it('renders author', () => { - expect(vm.$el.textContent).toContain('Administrator'); - }); - - it('renders provided time', () => { - expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toEqual( - '2017-03-23T23:02:00.807Z', - ); - - expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago'); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js deleted file mode 100644 index 3cbaa47c832..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js +++ /dev/null @@ -1,313 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue'; - -describe('MRWidgetHeader', () => { - let vm; - let Component; - - beforeEach(() => { - Component = Vue.extend(headerComponent); - }); - - afterEach(() => { - vm.$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.textContent.trim()).toEqual('Email patches'); - expect(downloadEmailPatchesEl.getAttribute('href')).toEqual('/mr/email-patches'); - expect(downloadPlainDiffEl.textContent.trim()).toEqual('Plain diff'); - expect(downloadPlainDiffEl.getAttribute('href')).toEqual('/mr/plainDiffPath'); - }; - - describe('computed', () => { - describe('shouldShowCommitsBehindText', () => { - it('return true when there are divergedCommitsCount', () => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 12, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>', - targetBranch: 'master', - statusPath: 'abc', - }, - }); - - expect(vm.shouldShowCommitsBehindText).toEqual(true); - }); - - it('returns false where there are no divergedComits count', () => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 0, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>', - targetBranch: 'master', - statusPath: 'abc', - }, - }); - - expect(vm.shouldShowCommitsBehindText).toEqual(false); - }); - }); - - describe('commitsBehindText', () => { - it('returns singular when there is one commit', () => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 1, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>', - targetBranch: 'master', - targetBranchPath: '/foo/bar/master', - statusPath: 'abc', - }, - }); - - expect(vm.commitsBehindText).toEqual( - 'The source branch is <a href="/foo/bar/master">1 commit behind</a> the target branch', - ); - }); - - it('returns plural when there is more than one commit', () => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 2, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>', - targetBranch: 'master', - targetBranchPath: '/foo/bar/master', - statusPath: 'abc', - }, - }); - - expect(vm.commitsBehindText).toEqual( - 'The source branch is <a href="/foo/bar/master">2 commits behind</a> the target branch', - ); - }); - }); - }); - - describe('template', () => { - describe('common elements', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 12, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - sourceBranchRemoved: false, - targetBranchPath: 'foo/bar/commits-path', - targetBranchTreePath: 'foo/bar/tree/path', - targetBranch: 'master', - isOpen: true, - emailPatchesPath: '/mr/email-patches', - plainDiffPath: '/mr/plainDiffPath', - statusPath: 'abc', - }, - }); - }); - - it('renders source branch link', () => { - expect(vm.$el.querySelector('.js-source-branch').innerHTML).toEqual( - '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - ); - }); - - it('renders clipboard button', () => { - expect(vm.$el.querySelector('.btn-clipboard')).not.toEqual(null); - }); - - it('renders target branch', () => { - expect(vm.$el.querySelector('.js-target-branch').textContent.trim()).toEqual('master'); - }); - }); - - describe('with an open merge request', () => { - const mrDefaultOptions = { - iid: 1, - divergedCommitsCount: 12, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - sourceBranchRemoved: false, - targetBranchPath: 'foo/bar/commits-path', - targetBranchTreePath: 'foo/bar/tree/path', - targetBranch: 'master', - isOpen: true, - canPushToSourceBranch: true, - emailPatchesPath: '/mr/email-patches', - plainDiffPath: '/mr/plainDiffPath', - statusPath: 'abc', - sourceProjectFullPath: 'root/gitlab-ce', - targetProjectFullPath: 'gitlab-org/gitlab-ce', - }; - - afterEach(() => { - vm.$destroy(); - }); - - beforeEach(() => { - vm = mountComponent(Component, { - mr: { ...mrDefaultOptions }, - }); - }); - - it('renders checkout branch button with modal trigger', () => { - const button = vm.$el.querySelector('.js-check-out-branch'); - - expect(button.textContent.trim()).toEqual('Check out branch'); - expect(button.getAttribute('data-target')).toEqual('#modal_merge_info'); - expect(button.getAttribute('data-toggle')).toEqual('modal'); - }); - - it('renders web ide button', () => { - const button = vm.$el.querySelector('.js-web-ide'); - - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.classList.contains('disabled')).toBe(false); - expect(button.getAttribute('href')).toEqual( - '/-/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', () => { - const mr = { ...mrDefaultOptions, canPushToSourceBranch: false }; - vm = mountComponent(Component, { mr }); - - const link = vm.$el.querySelector('.js-web-ide'); - - expect(link.classList.contains('disabled')).toBe(true); - expect(link.getAttribute('href')).toBeNull(); - }); - - it('renders web ide button with blank query string if target & source project branch', done => { - vm.mr.targetProjectFullPath = 'root/gitlab-ce'; - - vm.$nextTick(() => { - const button = vm.$el.querySelector('.js-web-ide'); - - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual( - '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=', - ); - - done(); - }); - }); - - it('renders web ide button with relative URL', done => { - gon.relative_url_root = '/gitlab'; - vm.mr.iid = 2; - - vm.$nextTick(() => { - const button = vm.$el.querySelector('.js-web-ide'); - - 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', - ); - - done(); - }); - }); - - it('renders download dropdown with links', () => { - expectDownloadDropdownItems(); - }); - }); - - describe('with a closed merge request', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 12, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - sourceBranchRemoved: false, - targetBranchPath: 'foo/bar/commits-path', - targetBranchTreePath: 'foo/bar/tree/path', - targetBranch: 'master', - isOpen: false, - emailPatchesPath: '/mr/email-patches', - plainDiffPath: '/mr/plainDiffPath', - statusPath: 'abc', - }, - }); - }); - - it('does not render checkout branch button with modal trigger', () => { - const button = vm.$el.querySelector('.js-check-out-branch'); - - expect(button).toEqual(null); - }); - - it('renders download dropdown with links', () => { - expectDownloadDropdownItems(); - }); - }); - - describe('without diverged commits', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 0, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - sourceBranchRemoved: false, - targetBranchPath: 'foo/bar/commits-path', - targetBranchTreePath: 'foo/bar/tree/path', - targetBranch: 'master', - isOpen: true, - emailPatchesPath: '/mr/email-patches', - plainDiffPath: '/mr/plainDiffPath', - statusPath: 'abc', - }, - }); - }); - - it('does not render diverged commits info', () => { - expect(vm.$el.querySelector('.diverged-commits-count')).toEqual(null); - }); - }); - - describe('with diverged commits', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - divergedCommitsCount: 12, - sourceBranch: 'mr-widget-refactor', - sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', - sourceBranchRemoved: false, - targetBranchPath: 'foo/bar/commits-path', - targetBranchTreePath: 'foo/bar/tree/path', - targetBranch: 'master', - isOpen: true, - emailPatchesPath: '/mr/email-patches', - plainDiffPath: '/mr/plainDiffPath', - statusPath: 'abc', - }, - }); - }); - - it('renders diverged commits info', () => { - expect(vm.$el.querySelector('.diverged-commits-count').textContent).toEqual( - '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, - ); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js deleted file mode 100644 index d15c3552b4a..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ /dev/null @@ -1,223 +0,0 @@ -import Vue from 'vue'; -import MemoryUsage from '~/vue_merge_request_widget/components/deployment/memory_usage.vue'; -import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; - -const url = '/root/acets-review-apps/environments/15/deployments/1/metrics'; -const monitoringUrl = '/root/acets-review-apps/environments/15/metrics'; - -const metricsMockData = { - success: true, - metrics: { - memory_before: [ - { - metric: {}, - value: [1495785220.607, '9572875.906976745'], - }, - ], - memory_after: [ - { - metric: {}, - value: [1495787020.607, '4485853.130206379'], - }, - ], - memory_values: [ - { - metric: {}, - values: [[1493716685, '4.30859375']], - }, - ], - }, - last_update: '2017-05-02T12:34:49.628Z', - deployment_time: 1493718485, -}; - -const createComponent = () => { - const Component = Vue.extend(MemoryUsage); - - return new Component({ - el: document.createElement('div'), - propsData: { - metricsUrl: url, - metricsMonitoringUrl: monitoringUrl, - memoryMetrics: [], - deploymentTime: 0, - hasMetrics: false, - loadFailed: false, - loadingMetrics: true, - backOffRequestCounter: 0, - }, - }); -}; - -const messages = { - loadingMetrics: 'Loading deployment statistics', - hasMetrics: 'Memory usage is unchanged at 0MB', - loadFailed: 'Failed to load deployment statistics', - metricsUnavailable: 'Deployment statistics are not available currently', -}; - -describe('MemoryUsage', () => { - let vm; - let el; - - beforeEach(() => { - vm = createComponent(); - el = vm.$el; - }); - - describe('data', () => { - it('should have default data', () => { - const data = MemoryUsage.data(); - - expect(Array.isArray(data.memoryMetrics)).toBeTruthy(); - expect(data.memoryMetrics.length).toBe(0); - - expect(typeof data.deploymentTime).toBe('number'); - expect(data.deploymentTime).toBe(0); - - expect(typeof data.hasMetrics).toBe('boolean'); - expect(data.hasMetrics).toBeFalsy(); - - expect(typeof data.loadFailed).toBe('boolean'); - expect(data.loadFailed).toBeFalsy(); - - expect(typeof data.loadingMetrics).toBe('boolean'); - expect(data.loadingMetrics).toBeTruthy(); - - expect(typeof data.backOffRequestCounter).toBe('number'); - expect(data.backOffRequestCounter).toBe(0); - }); - }); - - describe('computed', () => { - describe('memoryChangeMessage', () => { - it('should contain "increased" if memoryFrom value is less than memoryTo value', () => { - vm.memoryFrom = 4.28; - vm.memoryTo = 9.13; - - expect(vm.memoryChangeMessage.indexOf('increased')).not.toEqual('-1'); - }); - - it('should contain "decreased" if memoryFrom value is less than memoryTo value', () => { - vm.memoryFrom = 9.13; - vm.memoryTo = 4.28; - - expect(vm.memoryChangeMessage.indexOf('decreased')).not.toEqual('-1'); - }); - - it('should contain "unchanged" if memoryFrom value equal to memoryTo value', () => { - vm.memoryFrom = 1; - vm.memoryTo = 1; - - expect(vm.memoryChangeMessage.indexOf('unchanged')).not.toEqual('-1'); - }); - }); - }); - - describe('methods', () => { - const { metrics, deployment_time } = metricsMockData; - - describe('getMegabytes', () => { - it('should return Megabytes from provided Bytes value', () => { - const memoryInBytes = '9572875.906976745'; - - expect(vm.getMegabytes(memoryInBytes)).toEqual('9.13'); - }); - }); - - describe('computeGraphData', () => { - it('should populate sparkline graph', () => { - vm.computeGraphData(metrics, deployment_time); - const { hasMetrics, memoryMetrics, deploymentTime, memoryFrom, memoryTo } = vm; - - expect(hasMetrics).toBeTruthy(); - expect(memoryMetrics.length).toBeGreaterThan(0); - expect(deploymentTime).toEqual(deployment_time); - expect(memoryFrom).toEqual('9.13'); - expect(memoryTo).toEqual('4.28'); - }); - }); - - describe('loadMetrics', () => { - const returnServicePromise = () => - new Promise(resolve => { - resolve({ - data: metricsMockData, - }); - }); - - it('should load metrics data using MRWidgetService', done => { - spyOn(MRWidgetService, 'fetchMetrics').and.returnValue(returnServicePromise(true)); - spyOn(vm, 'computeGraphData'); - - vm.loadMetrics(); - setTimeout(() => { - expect(MRWidgetService.fetchMetrics).toHaveBeenCalledWith(url); - expect(vm.computeGraphData).toHaveBeenCalledWith(metrics, deployment_time); - done(); - }, 333); - }); - }); - }); - - describe('template', () => { - it('should render template elements correctly', () => { - expect(el.classList.contains('mr-memory-usage')).toBeTruthy(); - expect(el.querySelector('.js-usage-info')).toBeDefined(); - }); - - it('should show loading metrics message while metrics are being loaded', done => { - vm.loadingMetrics = true; - vm.hasMetrics = false; - vm.loadFailed = false; - - Vue.nextTick(() => { - expect(el.querySelector('.js-usage-info.usage-info-loading')).toBeDefined(); - - expect(el.querySelector('.js-usage-info .usage-info-load-spinner')).toBeDefined(); - - expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadingMetrics); - done(); - }); - }); - - it('should show deployment memory usage when metrics are loaded', done => { - vm.loadingMetrics = false; - vm.hasMetrics = true; - vm.loadFailed = false; - vm.memoryMetrics = metricsMockData.metrics.memory_values[0].values; - - Vue.nextTick(() => { - expect(el.querySelector('.memory-graph-container')).toBeDefined(); - expect(el.querySelector('.js-usage-info').innerText).toContain(messages.hasMetrics); - done(); - }); - }); - - it('should show failure message when metrics loading failed', done => { - vm.loadingMetrics = false; - vm.hasMetrics = false; - vm.loadFailed = true; - - Vue.nextTick(() => { - expect(el.querySelector('.js-usage-info.usage-info-failed')).toBeDefined(); - - expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadFailed); - done(); - }); - }); - - it('should show metrics unavailable message when metrics loading failed', done => { - vm.loadingMetrics = false; - vm.hasMetrics = false; - vm.loadFailed = false; - - Vue.nextTick(() => { - expect(el.querySelector('.js-usage-info.usage-info-unavailable')).toBeDefined(); - - expect(el.querySelector('.js-usage-info').innerText).toContain(messages.metricsUnavailable); - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js deleted file mode 100644 index b566876fe1d..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js +++ /dev/null @@ -1,70 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue'; - -describe('MRWidgetMergeHelp', () => { - let vm; - let Component; - - beforeEach(() => { - Component = Vue.extend(mergeHelpComponent); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('with missing branch', () => { - beforeEach(() => { - vm = mountComponent(Component, { - missingBranch: 'this-is-not-the-branch-you-are-looking-for', - }); - }); - - it('renders missing branch information', () => { - expect( - vm.$el.textContent - .trim() - .replace(/[\r\n]+/g, ' ') - .replace(/\s\s+/g, ' '), - ).toEqual( - 'If the this-is-not-the-branch-you-are-looking-for branch exists in your local repository, you can merge this merge request manually using the command line', - ); - }); - - it('renders button to open help modal', () => { - expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-target')).toEqual( - '#modal_merge_info', - ); - - expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-toggle')).toEqual( - 'modal', - ); - }); - }); - - describe('without missing branch', () => { - beforeEach(() => { - vm = mountComponent(Component); - }); - - it('renders information about how to merge manually', () => { - expect( - vm.$el.textContent - .trim() - .replace(/[\r\n]+/g, ' ') - .replace(/\s\s+/g, ' '), - ).toEqual('You can merge this merge request manually using the command line'); - }); - - it('renders element to open a modal', () => { - expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-target')).toEqual( - '#modal_merge_info', - ); - - expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-toggle')).toEqual( - 'modal', - ); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js deleted file mode 100644 index 883c41085fa..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js +++ /dev/null @@ -1,326 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { trimText } from 'spec/helpers/text_helper'; -import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue'; -import mockData from '../mock_data'; - -describe('MRWidgetPipeline', () => { - let vm; - let Component; - - beforeEach(() => { - Component = Vue.extend(pipelineComponent); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('hasPipeline', () => { - it('should return true when there is a pipeline', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - ciStatus: 'success', - hasCi: true, - troubleshootingDocsPath: 'help', - }); - - expect(vm.hasPipeline).toEqual(true); - }); - - it('should return false when there is no pipeline', () => { - vm = mountComponent(Component, { - pipeline: {}, - troubleshootingDocsPath: 'help', - }); - - expect(vm.hasPipeline).toEqual(false); - }); - }); - - describe('hasCIError', () => { - it('should return false when there is no CI error', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - }); - - expect(vm.hasCIError).toEqual(false); - }); - - it('should return true when there is a CI error', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - hasCi: true, - ciStatus: null, - troubleshootingDocsPath: 'help', - }); - - expect(vm.hasCIError).toEqual(true); - }); - }); - - describe('coverageDeltaClass', () => { - it('should return no class if there is no coverage change', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - pipelineCoverageDelta: '0', - troubleshootingDocsPath: 'help', - }); - - expect(vm.coverageDeltaClass).toEqual(''); - }); - - it('should return text-success if the coverage increased', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - pipelineCoverageDelta: '10', - troubleshootingDocsPath: 'help', - }); - - expect(vm.coverageDeltaClass).toEqual('text-success'); - }); - - it('should return text-danger if the coverage decreased', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - pipelineCoverageDelta: '-12', - troubleshootingDocsPath: 'help', - }); - - expect(vm.coverageDeltaClass).toEqual('text-danger'); - }); - }); - }); - - describe('rendered output', () => { - it('should render CI error', () => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - hasCi: true, - troubleshootingDocsPath: 'help', - }); - - expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( - 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.', - ); - }); - - it('should render CI error when no pipeline is provided', () => { - vm = mountComponent(Component, { - pipeline: {}, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - }); - - expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( - 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.', - ); - }); - - it('should render CI error when no CI is provided and pipeline must succeed is turned on', () => { - vm = mountComponent(Component, { - pipeline: {}, - hasCi: false, - pipelineMustSucceed: true, - troubleshootingDocsPath: 'help', - }); - - expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( - 'No pipeline has been run for this commit.', - ); - }); - - describe('with a pipeline', () => { - beforeEach(() => { - vm = mountComponent(Component, { - pipeline: mockData.pipeline, - hasCi: true, - ciStatus: 'success', - pipelineCoverageDelta: mockData.pipelineCoverageDelta, - troubleshootingDocsPath: 'help', - }); - }); - - it('should render pipeline ID', () => { - expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual( - `#${mockData.pipeline.id}`, - ); - }); - - it('should render pipeline status and commit id', () => { - expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( - mockData.pipeline.details.status.label, - ); - - expect(vm.$el.querySelector('.js-commit-link').textContent.trim()).toEqual( - mockData.pipeline.commit.short_id, - ); - - expect(vm.$el.querySelector('.js-commit-link').getAttribute('href')).toEqual( - mockData.pipeline.commit.commit_path, - ); - }); - - it('should render pipeline graph', () => { - expect(vm.$el.querySelector('.mr-widget-pipeline-graph')).toBeDefined(); - expect(vm.$el.querySelectorAll('.stage-container').length).toEqual( - mockData.pipeline.details.stages.length, - ); - }); - - it('should render coverage information', () => { - expect(vm.$el.querySelector('.media-body').textContent).toContain( - `Coverage ${mockData.pipeline.coverage}`, - ); - }); - - it('should render pipeline coverage delta information', () => { - expect(vm.$el.querySelector('.js-pipeline-coverage-delta.text-danger')).toBeDefined(); - expect(vm.$el.querySelector('.js-pipeline-coverage-delta').textContent).toContain( - `(${mockData.pipelineCoverageDelta}%)`, - ); - }); - }); - - describe('without commit path', () => { - beforeEach(() => { - const mockCopy = JSON.parse(JSON.stringify(mockData)); - delete mockCopy.pipeline.commit; - - vm = mountComponent(Component, { - pipeline: mockCopy.pipeline, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - }); - }); - - it('should render pipeline ID', () => { - expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual( - `#${mockData.pipeline.id}`, - ); - }); - - it('should render pipeline status', () => { - expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( - mockData.pipeline.details.status.label, - ); - - expect(vm.$el.querySelector('.js-commit-link')).toBeNull(); - }); - - it('should render pipeline graph', () => { - expect(vm.$el.querySelector('.mr-widget-pipeline-graph')).toBeDefined(); - expect(vm.$el.querySelectorAll('.stage-container').length).toEqual( - mockData.pipeline.details.stages.length, - ); - }); - - it('should render coverage information', () => { - expect(vm.$el.querySelector('.media-body').textContent).toContain( - `Coverage ${mockData.pipeline.coverage}`, - ); - }); - }); - - describe('without coverage', () => { - it('should not render a coverage', () => { - const mockCopy = JSON.parse(JSON.stringify(mockData)); - delete mockCopy.pipeline.coverage; - - vm = mountComponent(Component, { - pipeline: mockCopy.pipeline, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - }); - - expect(vm.$el.querySelector('.media-body').textContent).not.toContain('Coverage'); - }); - }); - - describe('without a pipeline graph', () => { - it('should not render a pipeline graph', () => { - const mockCopy = JSON.parse(JSON.stringify(mockData)); - delete mockCopy.pipeline.details.stages; - - vm = mountComponent(Component, { - pipeline: mockCopy.pipeline, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - }); - - expect(vm.$el.querySelector('.js-mini-pipeline-graph')).toEqual(null); - }); - }); - - describe('for each type of pipeline', () => { - let pipeline; - - beforeEach(() => { - ({ pipeline } = JSON.parse(JSON.stringify(mockData))); - - pipeline.details.name = 'Pipeline'; - pipeline.merge_request_event_type = undefined; - pipeline.ref.tag = false; - pipeline.ref.branch = false; - }); - - const factory = () => { - vm = mountComponent(Component, { - pipeline, - hasCi: true, - ciStatus: 'success', - troubleshootingDocsPath: 'help', - sourceBranchLink: mockData.source_branch_link, - }); - }; - - describe('for a branch pipeline', () => { - it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => { - pipeline.ref.branch = true; - - factory(); - - const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockData.source_branch_link}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); - - expect(actual).toBe(expected); - }); - }); - - describe('for a tag pipeline', () => { - it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => { - pipeline.ref.tag = true; - - factory(); - - const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); - - expect(actual).toBe(expected); - }); - }); - - describe('for a detached merge request pipeline', () => { - it('renders a pipeline widget that reads "Detached merge request pipeline <ID> <status> for <SHA>"', () => { - pipeline.details.name = 'Detached merge request pipeline'; - pipeline.merge_request_event_type = 'detached'; - - factory(); - - const expected = `Detached merge request pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText); - - expect(actual).toBe(expected); - }); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js deleted file mode 100644 index 5b293862b16..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js +++ /dev/null @@ -1,141 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import eventHub from '~/vue_merge_request_widget/event_hub'; -import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue'; - -describe('Merge request widget rebase component', () => { - let Component; - let vm; - beforeEach(() => { - Component = Vue.extend(component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('While rebasing', () => { - it('should show progress message', () => { - vm = mountComponent(Component, { - mr: { rebaseInProgress: true }, - service: {}, - }); - - expect( - vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(), - ).toContain('Rebase in progress'); - }); - }); - - describe('With permissions', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - rebaseInProgress: false, - canPushToSourceBranch: true, - }, - service: {}, - }); - }); - - it('it should render rebase button and warning message', () => { - const text = vm.$el - .querySelector('.rebase-state-find-class-convention span') - .textContent.trim(); - - expect(text).toContain('Fast-forward merge is not possible.'); - expect(text.replace(/\s\s+/g, ' ')).toContain( - 'Rebase the source branch onto the target branch or merge target', - ); - - expect(text).toContain('branch into source branch to allow this merge request to be merged.'); - }); - - it('it should render error message when it fails', done => { - vm.rebasingError = 'Something went wrong!'; - - Vue.nextTick(() => { - expect( - vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(), - ).toContain('Something went wrong!'); - done(); - }); - }); - }); - - describe('Without permissions', () => { - it('should render a message explaining user does not have permissions', () => { - vm = mountComponent(Component, { - mr: { - rebaseInProgress: false, - canPushToSourceBranch: false, - targetBranch: 'foo', - }, - service: {}, - }); - - const text = vm.$el - .querySelector('.rebase-state-find-class-convention span') - .textContent.trim(); - - expect(text).toContain('Fast-forward merge is not possible.'); - expect(text).toContain('Rebase the source branch onto'); - expect(text).toContain('foo'); - expect(text.replace(/\s\s+/g, ' ')).toContain('to allow this merge request to be merged.'); - }); - - it('should render the correct target branch name', () => { - const targetBranch = 'fake-branch-to-test-with'; - vm = mountComponent(Component, { - mr: { - rebaseInProgress: false, - canPushToSourceBranch: false, - targetBranch, - }, - service: {}, - }); - - const elem = vm.$el.querySelector('.rebase-state-find-class-convention span'); - - expect(elem.innerHTML).toContain( - `Fast-forward merge is not possible. Rebase the source branch onto <span class="label-branch">${targetBranch}</span> to allow this merge request to be merged.`, - ); - }); - }); - - describe('methods', () => { - it('checkRebaseStatus', done => { - spyOn(eventHub, '$emit'); - vm = mountComponent(Component, { - mr: {}, - service: { - rebase() { - return Promise.resolve(); - }, - poll() { - return Promise.resolve({ - data: { - rebase_in_progress: false, - merge_error: null, - }, - }); - }, - }, - }); - - vm.rebase(); - - // Wait for the rebase request - vm.$nextTick() - // Wait for the polling request - .then(vm.$nextTick()) - // Wait for the eventHub to be called - .then(vm.$nextTick()) - .then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess'); - }) - .then(done) - .catch(done.fail); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js deleted file mode 100644 index a152bd01916..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js +++ /dev/null @@ -1,85 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue'; - -describe('MRWidgetRelatedLinks', () => { - let vm; - - const createComponent = data => { - const Component = Vue.extend(relatedLinksComponent); - - return mountComponent(Component, data); - }; - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('closesText', () => { - it('returns Closes text for open merge request', () => { - vm = createComponent({ state: 'open', relatedLinks: {} }); - - expect(vm.closesText).toEqual('Closes'); - }); - - it('returns correct text for closed merge request', () => { - vm = createComponent({ state: 'closed', relatedLinks: {} }); - - expect(vm.closesText).toEqual('Did not close'); - }); - - it('returns correct tense for merged request', () => { - vm = createComponent({ state: 'merged', relatedLinks: {} }); - - expect(vm.closesText).toEqual('Closed'); - }); - }); - }); - - it('should have only have closing issues text', () => { - vm = createComponent({ - relatedLinks: { - closing: '<a href="#">#23</a> and <a>#42</a>', - }, - }); - const content = vm.$el.textContent.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({ - relatedLinks: { - mentioned: '<a href="#">#7</a>', - }, - }); - - expect(vm.$el.innerText).toContain('Mentions #7'); - expect(vm.$el.innerText).not.toContain('Closes'); - }); - - it('should have closing and mentioned issues at the same time', () => { - vm = 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(); - - expect(content).toContain('Closes #7'); - expect(content).toContain('Mentions #23 and #42'); - }); - - it('should have assing issues link', () => { - vm = createComponent({ - relatedLinks: { - assignToMe: '<a href="#">Assign yourself to these issues</a>', - }, - }); - - expect(vm.$el.innerText).toContain('Assign yourself to these issues'); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js deleted file mode 100644 index 20bda024d89..00000000000 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js +++ /dev/null @@ -1,48 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import mrStatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue'; - -describe('MR widget status icon component', () => { - let vm; - let Component; - - beforeEach(() => { - Component = Vue.extend(mrStatusIcon); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('while loading', () => { - it('renders loading icon', () => { - vm = mountComponent(Component, { status: 'loading' }); - - expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('gl-spinner'); - }); - }); - - describe('with status icon', () => { - it('renders ci status icon', () => { - vm = mountComponent(Component, { status: 'failed' }); - - expect(vm.$el.querySelector('.js-ci-status-icon-failed')).not.toBeNull(); - }); - }); - - describe('with disabled button', () => { - it('renders a disabled button', () => { - vm = mountComponent(Component, { status: 'failed', showDisabledButton: true }); - - expect(vm.$el.querySelector('.js-disabled-merge-button').textContent.trim()).toEqual('Merge'); - }); - }); - - describe('without disabled button', () => { - it('does not render a disabled button', () => { - vm = mountComponent(Component, { status: 'failed' }); - - expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeNull(); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js b/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js deleted file mode 100644 index 242193c7b3d..00000000000 --- a/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js +++ /dev/null @@ -1,52 +0,0 @@ -import Vue from 'vue'; -import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper'; -import component from '~/vue_merge_request_widget/components/review_app_link.vue'; -import mountComponent from '../../helpers/vue_mount_component_helper'; - -describe('review app link', () => { - const Component = Vue.extend(component); - const props = { - link: '/review', - cssClass: 'js-link', - display: { - text: 'View app', - tooltip: '', - }, - }; - let vm; - let el; - - beforeEach(() => { - vm = mountComponent(Component, props); - el = vm.$el; - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders provided link as href attribute', () => { - expect(el.getAttribute('href')).toEqual(props.link); - }); - - it('renders provided cssClass as class attribute', () => { - expect(el.getAttribute('class')).toEqual(props.cssClass); - }); - - it('renders View app text', () => { - expect(el.textContent.trim()).toEqual('View app'); - }); - - it('renders svg icon', () => { - expect(el.querySelector('svg')).not.toBeNull(); - }); - - it('tracks an event when clicked', () => { - const spy = mockTracking('_category_', el, spyOn); - triggerEvent(el); - - expect(spy).toHaveBeenCalledWith('_category_', 'open_review_app', { - label: 'review_app', - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js deleted file mode 100644 index 29a257b0e24..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import archivedComponent from '~/vue_merge_request_widget/components/states/mr_widget_archived.vue'; - -describe('MRWidgetArchived', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(archivedComponent); - vm = mountComponent(Component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders a ci status failed icon', () => { - expect(vm.$el.querySelector('.ci-status-icon')).not.toBeNull(); - }); - - it('renders a disabled button', () => { - expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled'); - expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Merge'); - }); - - it('renders information', () => { - expect(vm.$el.querySelector('.bold').textContent.trim()).toEqual( - 'This project is archived, write access has been disabled', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js deleted file mode 100644 index 73b65178ecf..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js +++ /dev/null @@ -1,230 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { trimText } from 'spec/helpers/text_helper'; -import autoMergeEnabledComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue'; -import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; -import eventHub from '~/vue_merge_request_widget/event_hub'; -import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants'; - -describe('MRWidgetAutoMergeEnabled', () => { - let vm; - const targetBranchPath = '/foo/bar'; - const targetBranch = 'foo'; - const sha = '1EA2EZ34'; - - beforeEach(() => { - const Component = Vue.extend(autoMergeEnabledComponent); - spyOn(eventHub, '$emit'); - - vm = mountComponent(Component, { - mr: { - shouldRemoveSourceBranch: false, - canRemoveSourceBranch: true, - canCancelAutomaticMerge: true, - mergeUserId: 1, - currentUserId: 1, - setToAutoMergeBy: {}, - sha, - targetBranchPath, - targetBranch, - autoMergeStrategy: MWPS_MERGE_STRATEGY, - }, - service: new MRWidgetService({}), - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('canRemoveSourceBranch', () => { - it('should return true when user is able to remove source branch', () => { - expect(vm.canRemoveSourceBranch).toBeTruthy(); - }); - - it('should return false when user id is not the same with who set the MWPS', () => { - vm.mr.mergeUserId = 2; - - expect(vm.canRemoveSourceBranch).toBeFalsy(); - - vm.mr.currentUserId = 2; - - expect(vm.canRemoveSourceBranch).toBeTruthy(); - - vm.mr.currentUserId = 3; - - expect(vm.canRemoveSourceBranch).toBeFalsy(); - }); - - it('should return false when shouldRemoveSourceBranch set to false', () => { - vm.mr.shouldRemoveSourceBranch = true; - - expect(vm.canRemoveSourceBranch).toBeFalsy(); - }); - - it('should return false if user is not able to remove the source branch', () => { - vm.mr.canRemoveSourceBranch = false; - - expect(vm.canRemoveSourceBranch).toBeFalsy(); - }); - }); - - describe('statusTextBeforeAuthor', () => { - it('should return "Set by" if the MWPS is selected', () => { - Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY); - - expect(vm.statusTextBeforeAuthor).toBe('Set by'); - }); - }); - - describe('statusTextAfterAuthor', () => { - it('should return "to be merged automatically..." if MWPS is selected', () => { - Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY); - - expect(vm.statusTextAfterAuthor).toBe( - 'to be merged automatically when the pipeline succeeds', - ); - }); - }); - - describe('cancelButtonText', () => { - it('should return "Cancel automatic merge" if MWPS is selected', () => { - Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY); - - expect(vm.cancelButtonText).toBe('Cancel automatic merge'); - }); - }); - }); - - describe('methods', () => { - describe('cancelAutomaticMerge', () => { - it('should set flag and call service then tell main component to update the widget with data', done => { - const mrObj = { - is_new_mr_data: true, - }; - spyOn(vm.service, 'cancelAutomaticMerge').and.returnValue( - new Promise(resolve => { - resolve({ - data: mrObj, - }); - }), - ); - - vm.cancelAutomaticMerge(); - setTimeout(() => { - expect(vm.isCancellingAutoMerge).toBeTruthy(); - expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj); - done(); - }, 333); - }); - }); - - describe('removeSourceBranch', () => { - it('should set flag and call service then request main component to update the widget', done => { - spyOn(vm.service, 'merge').and.returnValue( - Promise.resolve({ - data: { - status: MWPS_MERGE_STRATEGY, - }, - }), - ); - - vm.removeSourceBranch(); - setTimeout(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - expect(vm.service.merge).toHaveBeenCalledWith({ - sha, - auto_merge_strategy: MWPS_MERGE_STRATEGY, - should_remove_source_branch: true, - }); - done(); - }, 333); - }); - }); - }); - - describe('template', () => { - it('should have correct elements', () => { - expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(vm.$el.innerText).toContain('to be merged automatically when the pipeline succeeds'); - - expect(vm.$el.innerText).toContain('The changes will be merged into'); - expect(vm.$el.innerText).toContain(targetBranch); - expect(vm.$el.innerText).toContain('The source branch will not be deleted'); - expect(vm.$el.querySelector('.js-cancel-auto-merge').innerText).toContain( - 'Cancel automatic merge', - ); - - expect(vm.$el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeFalsy(); - expect(vm.$el.querySelector('.js-remove-source-branch').innerText).toContain( - 'Delete source branch', - ); - - expect(vm.$el.querySelector('.js-remove-source-branch').getAttribute('disabled')).toBeFalsy(); - }); - - it('should disable cancel auto merge button when the action is in progress', done => { - vm.isCancellingAutoMerge = true; - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeTruthy(); - done(); - }); - }); - - it('should show source branch will be deleted text when it source branch set to remove', done => { - vm.mr.shouldRemoveSourceBranch = true; - - Vue.nextTick(() => { - const normalizedText = vm.$el.innerText.replace(/\s+/g, ' '); - - expect(normalizedText).toContain('The source branch will be deleted'); - expect(normalizedText).not.toContain('The source branch will not be deleted'); - done(); - }); - }); - - it('should not show delete source branch button when user not able to delete source branch', done => { - vm.mr.currentUserId = 4; - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.js-remove-source-branch')).toEqual(null); - done(); - }); - }); - - it('should disable delete source branch button when the action is in progress', done => { - vm.isRemovingSourceBranch = true; - - Vue.nextTick(() => { - expect( - vm.$el.querySelector('.js-remove-source-branch').getAttribute('disabled'), - ).toBeTruthy(); - done(); - }); - }); - - it('should render the status text as "...to merged automatically" if MWPS is selected', done => { - Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY); - - Vue.nextTick(() => { - const statusText = trimText(vm.$el.querySelector('.js-status-text-after-author').innerText); - - expect(statusText).toBe('to be merged automatically when the pipeline succeeds'); - done(); - }); - }); - - it('should render the cancel button as "Cancel automatic merge" if MWPS is selected', done => { - Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY); - - Vue.nextTick(() => { - const cancelButtonText = trimText(vm.$el.querySelector('.js-cancel-auto-merge').innerText); - - expect(cancelButtonText).toBe('Cancel automatic merge'); - done(); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js deleted file mode 100644 index efccd507fe2..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue'; - -describe('MRWidgetChecking', () => { - let Component; - let vm; - - beforeEach(() => { - Component = Vue.extend(checkingComponent); - vm = mountComponent(Component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders disabled button', () => { - expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled'); - }); - - it('renders loading icon', () => { - expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('gl-spinner'); - }); - - it('renders information about merging', () => { - expect(vm.$el.querySelector('.media-body').textContent.trim()).toEqual( - 'Checking ability to merge automatically…', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js deleted file mode 100644 index bbbaed0d2f5..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js +++ /dev/null @@ -1,69 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue'; - -describe('MRWidgetClosed', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(closedComponent); - vm = mountComponent(Component, { - mr: { - metrics: { - mergedBy: {}, - closedBy: { - name: 'Administrator', - username: 'root', - webUrl: 'http://localhost:3000/root', - avatarUrl: - 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - }, - mergedAt: 'Jan 24, 2018 1:02pm GMT+0000', - closedAt: 'Jan 24, 2018 1:02pm GMT+0000', - readableMergedAt: '', - readableClosedAt: 'less than a minute ago', - }, - targetBranchPath: '/twitter/flight/commits/so_long_jquery', - targetBranch: 'so_long_jquery', - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders warning icon', () => { - expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull(); - }); - - it('renders closed by information with author and time', () => { - expect( - vm.$el - .querySelector('.js-mr-widget-author') - .textContent.trim() - .replace(/\s\s+/g, ' '), - ).toContain('Closed by Administrator less than a minute ago'); - }); - - it('links to the user that closed the MR', () => { - expect(vm.$el.querySelector('.author-link').getAttribute('href')).toEqual( - 'http://localhost:3000/root', - ); - }); - - it('renders information about the changes not being merged', () => { - expect( - vm.$el - .querySelector('.mr-info-list') - .textContent.trim() - .replace(/\s\s+/g, ' '), - ).toContain('The changes were not merged into so_long_jquery'); - }); - - it('renders link for target branch', () => { - expect(vm.$el.querySelector('.label-branch').getAttribute('href')).toEqual( - '/twitter/flight/commits/so_long_jquery', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js deleted file mode 100644 index 9035bc6f65d..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js +++ /dev/null @@ -1,225 +0,0 @@ -import $ from 'jquery'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import { removeBreakLine } from 'spec/helpers/text_helper'; -import ConflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; - -describe('MRWidgetConflicts', () => { - let vm; - const path = '/conflicts'; - - function createComponent(propsData = {}) { - const localVue = createLocalVue(); - - vm = shallowMount(localVue.extend(ConflictsComponent), { - propsData, - }); - } - - beforeEach(() => { - spyOn($.fn, 'popover').and.callThrough(); - }); - - afterEach(() => { - vm.destroy(); - }); - - // There are two permissions we need to consider: - // - // 1. Is the user allowed to merge to the target branch? - // 2. Is the user allowed to push to the source branch? - // - // This yields 4 possible permutations that we need to test, and - // we test them below. A user who can push to the source - // branch should be allowed to resolve conflicts. This is - // consistent with what the backend does. - describe('when allowed to merge but not allowed to push to source branch', () => { - beforeEach(() => { - createComponent({ - mr: { - canMerge: true, - canPushToSourceBranch: false, - conflictResolutionPath: path, - conflictsDocsPath: '', - }, - }); - }); - - 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'); - }); - - it('should not allow you to resolve the conflicts', () => { - expect(vm.text()).not.toContain('Resolve conflicts'); - }); - - it('should have merge buttons', () => { - const mergeLocallyButton = vm.find('.js-merge-locally-button'); - - expect(mergeLocallyButton.text()).toContain('Merge locally'); - }); - }); - - describe('when not allowed to merge but allowed to push to source branch', () => { - beforeEach(() => { - createComponent({ - mr: { - canMerge: false, - canPushToSourceBranch: true, - conflictResolutionPath: path, - conflictsDocsPath: '', - }, - }); - }); - - it('should tell you about conflicts', () => { - expect(vm.text()).toContain('There are merge conflicts'); - expect(vm.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); - }); - - it('should not have merge buttons', () => { - expect(vm.text()).not.toContain('Merge locally'); - }); - }); - - describe('when allowed to merge and push to source branch', () => { - beforeEach(() => { - createComponent({ - mr: { - canMerge: true, - canPushToSourceBranch: true, - conflictResolutionPath: path, - conflictsDocsPath: '', - }, - }); - }); - - 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'); - }); - - 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); - }); - - it('should have merge buttons', () => { - const mergeLocallyButton = vm.find('.js-merge-locally-button'); - - expect(mergeLocallyButton.text()).toContain('Merge locally'); - }); - }); - - describe('when user does not have permission to push to source branch', () => { - it('should show proper message', () => { - createComponent({ - mr: { - canMerge: false, - canPushToSourceBranch: false, - conflictsDocsPath: '', - }, - }); - - expect( - vm - .text() - .trim() - .replace(/\s\s+/g, ' '), - ).toContain('ask someone with write access'); - }); - - it('should not have action buttons', () => { - createComponent({ - mr: { - canMerge: false, - canPushToSourceBranch: false, - conflictsDocsPath: '', - }, - }); - - expect(vm.contains('.js-resolve-conflicts-button')).toBe(false); - expect(vm.contains('.js-merge-locally-button')).toBe(false); - }); - - it('should not have resolve button when no conflict resolution path', () => { - createComponent({ - mr: { - canMerge: true, - conflictResolutionPath: null, - conflictsDocsPath: '', - }, - }); - - expect(vm.contains('.js-resolve-conflicts-button')).toBe(false); - }); - }); - - describe('when fast-forward or semi-linear merge enabled', () => { - it('should tell you to rebase locally', () => { - createComponent({ - mr: { - shouldBeRebased: true, - conflictsDocsPath: '', - }, - }); - - expect(removeBreakLine(vm.text()).trim()).toContain( - 'Fast-forward merge is not possible. To merge this request, first rebase locally.', - ); - }); - }); - - describe('when source branch protected', () => { - beforeEach(() => { - createComponent({ - mr: { - canMerge: true, - canPushToSourceBranch: true, - conflictResolutionPath: gl.TEST_HOST, - sourceBranchProtected: true, - conflictsDocsPath: '', - }, - }); - }); - - it('sets resolve button as disabled', () => { - expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe('disabled'); - }); - - it('renders popover', () => { - expect($.fn.popover).toHaveBeenCalled(); - }); - }); - - describe('when source branch not protected', () => { - beforeEach(() => { - createComponent({ - mr: { - canMerge: true, - canPushToSourceBranch: true, - conflictResolutionPath: gl.TEST_HOST, - sourceBranchProtected: false, - conflictsDocsPath: '', - }, - }); - }); - - it('sets resolve button as disabled', () => { - expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe(undefined); - }); - - it('renders popover', () => { - expect($.fn.popover).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js deleted file mode 100644 index ef76e617c07..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ /dev/null @@ -1,156 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import failedToMergeComponent 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; - - beforeEach(() => { - Component = Vue.extend(failedToMergeComponent); - spyOn(eventHub, '$emit'); - spyOn(window, 'setInterval').and.returnValue(dummyIntervalId); - spyOn(window, 'clearInterval').and.stub(); - 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); - }); - - it('clears interval when destroying ', () => { - vm.$destroy(); - - 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...'); - - vm.timer = 1; - - expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...'); - }); - }); - - describe('mergeError', () => { - it('removes forced line breaks', done => { - mr.mergeError = 'contains<br />line breaks<br />'; - - Vue.nextTick() - .then(() => { - expect(vm.mergeError).toBe('contains line breaks'); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('created', () => { - it('should disable polling', () => { - expect(eventHub.$emit).toHaveBeenCalledWith('DisablePolling'); - }); - }); - - describe('methods', () => { - describe('refresh', () => { - it('should emit event to request component refresh', () => { - expect(vm.isRefreshing).toEqual(false); - - vm.refresh(); - - expect(vm.isRefreshing).toEqual(true); - expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - expect(eventHub.$emit).toHaveBeenCalledWith('EnablePolling'); - }); - }); - - describe('updateTimer', () => { - it('should update timer and emit event when timer end', () => { - spyOn(vm, 'refresh'); - - expect(vm.timer).toEqual(10); - - for (let i = 0; i < 10; i += 1) { - expect(vm.timer).toEqual(10 - i); - vm.updateTimer(); - } - - expect(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(); - }); - }); - }); - - describe('while it is not regresing', () => { - it('renders warning icon and disabled merge button', () => { - expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull(); - expect(vm.$el.querySelector('.js-disabled-merge-button').getAttribute('disabled')).toEqual( - 'disabled', - ); - }); - - it('renders given error', () => { - expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual( - 'Merge error happened', - ); - }); - - it('renders refresh button', () => { - expect(vm.$el.querySelector('.js-refresh-button').textContent.trim()).toEqual('Refresh now'); - }); - - it('renders remaining time', () => { - expect(vm.$el.querySelector('.has-custom-error').textContent.trim()).toEqual( - '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; - - Vue.nextTick(() => { - expect(vm.$el.innerText).toContain('Merge failed.'); - expect(vm.$el.innerText).not.toContain('Merge error happened.'); - done(); - }); - }); - - 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(); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js deleted file mode 100644 index 423c800bfbc..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js +++ /dev/null @@ -1,219 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue'; -import eventHub from '~/vue_merge_request_widget/event_hub'; - -describe('MRWidgetMerged', () => { - let vm; - const targetBranch = 'foo'; - const selectors = { - get copyMergeShaButton() { - return vm.$el.querySelector('button.js-mr-merged-copy-sha'); - }, - get mergeCommitShaLink() { - return vm.$el.querySelector('a.js-mr-merged-commit-sha'); - }, - }; - - beforeEach(() => { - const Component = Vue.extend(mergedComponent); - const mr = { - isRemovingSourceBranch: false, - cherryPickInForkPath: false, - canCherryPickInCurrentMR: true, - revertInForkPath: false, - canRevertInCurrentMR: true, - canRemoveSourceBranch: true, - sourceBranchRemoved: true, - metrics: { - mergedBy: { - name: 'Administrator', - username: 'root', - webUrl: 'http://localhost:3000/root', - avatarUrl: - 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - }, - mergedAt: 'Jan 24, 2018 1:02pm GMT+0000', - readableMergedAt: '', - closedBy: {}, - closedAt: 'Jan 24, 2018 1:02pm GMT+0000', - readableClosedAt: '', - }, - updatedAt: 'mergedUpdatedAt', - shortMergeCommitSha: '958c0475', - mergeCommitSha: '958c047516e182dfc52317f721f696e8a1ee85ed', - mergeCommitPath: - 'http://localhost:3000/root/nautilus/commit/f7ce827c314c9340b075657fd61c789fb01cf74d', - sourceBranch: 'bar', - targetBranch, - }; - - const service = { - removeSourceBranch() {}, - }; - - spyOn(eventHub, '$emit'); - - vm = mountComponent(Component, { mr, service }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('shouldShowRemoveSourceBranch', () => { - it('returns true when sourceBranchRemoved is false', () => { - vm.mr.sourceBranchRemoved = false; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(true); - }); - - it('returns false when sourceBranchRemoved is true', () => { - vm.mr.sourceBranchRemoved = true; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(false); - }); - - it('returns false when canRemoveSourceBranch is false', () => { - vm.mr.sourceBranchRemoved = false; - vm.mr.canRemoveSourceBranch = false; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(false); - }); - - it('returns false when is making request', () => { - vm.mr.canRemoveSourceBranch = true; - vm.isMakingRequest = true; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(false); - }); - - it('returns true when all are true', () => { - vm.mr.isRemovingSourceBranch = true; - vm.mr.canRemoveSourceBranch = true; - vm.isMakingRequest = true; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(false); - }); - }); - - describe('shouldShowSourceBranchRemoving', () => { - it('should correct value when fields changed', () => { - vm.mr.sourceBranchRemoved = false; - - expect(vm.shouldShowSourceBranchRemoving).toEqual(false); - - vm.mr.sourceBranchRemoved = true; - - expect(vm.shouldShowRemoveSourceBranch).toEqual(false); - - vm.mr.sourceBranchRemoved = false; - vm.isMakingRequest = true; - - expect(vm.shouldShowSourceBranchRemoving).toEqual(true); - - vm.isMakingRequest = false; - vm.mr.isRemovingSourceBranch = true; - - expect(vm.shouldShowSourceBranchRemoving).toEqual(true); - }); - }); - }); - - describe('methods', () => { - describe('removeSourceBranch', () => { - it('should set flag and call service then request main component to update the widget', done => { - spyOn(vm.service, 'removeSourceBranch').and.returnValue( - new Promise(resolve => { - resolve({ - data: { - message: 'Branch was deleted', - }, - }); - }), - ); - - vm.removeSourceBranch(); - setTimeout(() => { - const args = eventHub.$emit.calls.argsFor(0); - - expect(vm.isMakingRequest).toEqual(true); - expect(args[0]).toEqual('MRWidgetUpdateRequested'); - expect(args[1]).not.toThrow(); - done(); - }, 333); - }); - }); - }); - - it('has merged by information', () => { - expect(vm.$el.textContent).toContain('Merged by'); - expect(vm.$el.textContent).toContain('Administrator'); - }); - - it('renders branch information', () => { - expect(vm.$el.textContent).toContain('The changes were merged into'); - expect(vm.$el.textContent).toContain(targetBranch); - }); - - it('renders information about branch being deleted', () => { - expect(vm.$el.textContent).toContain('The source branch has been deleted'); - }); - - it('shows revert and cherry-pick buttons', () => { - expect(vm.$el.textContent).toContain('Revert'); - expect(vm.$el.textContent).toContain('Cherry-pick'); - }); - - it('shows button to copy commit SHA to clipboard', () => { - expect(selectors.copyMergeShaButton).toExist(); - expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe( - vm.mr.mergeCommitSha, - ); - }); - - it('hides button to copy commit SHA if SHA does not exist', done => { - vm.mr.mergeCommitSha = null; - - Vue.nextTick(() => { - expect(selectors.copyMergeShaButton).not.toExist(); - expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with'); - done(); - }); - }); - - it('shows merge commit SHA link', () => { - expect(selectors.mergeCommitShaLink).toExist(); - expect(selectors.mergeCommitShaLink.text).toContain(vm.mr.shortMergeCommitSha); - expect(selectors.mergeCommitShaLink.href).toBe(vm.mr.mergeCommitPath); - }); - - it('should not show source branch deleted text', done => { - vm.mr.sourceBranchRemoved = false; - - Vue.nextTick(() => { - expect(vm.$el.innerText).toContain('You can delete the source branch now'); - expect(vm.$el.innerText).not.toContain('The source branch has been deleted'); - done(); - }); - }); - - it('should show source branch deleting text', done => { - vm.mr.isRemovingSourceBranch = true; - vm.mr.sourceBranchRemoved = false; - - Vue.nextTick(() => { - expect(vm.$el.innerText).toContain('The source branch is being deleted'); - expect(vm.$el.innerText).not.toContain('You can delete the source branch now'); - expect(vm.$el.innerText).not.toContain('The source branch has been deleted'); - done(); - }); - }); - - it('should use mergedEvent mergedAt as tooltip title', () => { - expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toBe( - 'Jan 24, 2018 1:02pm GMT+0000', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js deleted file mode 100644 index 06d236064dd..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js +++ /dev/null @@ -1,43 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue'; - -describe('MRWidgetMerging', () => { - let vm; - beforeEach(() => { - const Component = Vue.extend(mergingComponent); - - vm = mountComponent(Component, { - mr: { - targetBranchPath: '/branch-path', - targetBranch: 'branch', - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders information about merge request being merged', () => { - expect( - vm.$el - .querySelector('.media-body') - .textContent.trim() - .replace(/\s\s+/g, ' ') - .replace(/[\r\n]+/g, ' '), - ).toContain('This merge request is in the process of being merged'); - }); - - it('renders branch information', () => { - expect( - vm.$el - .querySelector('.mr-info-list') - .textContent.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'); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js deleted file mode 100644 index 47b989e2022..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue'; - -describe('MRWidgetMissingBranch', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(missingBranchComponent); - vm = mountComponent(Component, { mr: { sourceBranchRemoved: true } }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('missingBranchName', () => { - it('should return proper branch name', () => { - expect(vm.missingBranchName).toEqual('source'); - - vm.mr.sourceBranchRemoved = false; - - expect(vm.missingBranchName).toEqual('target'); - }); - }); - }); - - describe('template', () => { - it('should have correct elements', () => { - const el = vm.$el; - const content = el.textContent.replace(/\n(\s)+/g, ' ').trim(); - - expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(content.replace(/\s\s+/g, ' ')).toContain('source branch does not exist.'); - expect(content).toContain('Please restore it or use a different source branch'); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js deleted file mode 100644 index b1cb91663c9..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js +++ /dev/null @@ -1,26 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import notAllowedComponent from '~/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue'; - -describe('MRWidgetNotAllowed', () => { - let vm; - beforeEach(() => { - const Component = Vue.extend(notAllowedComponent); - vm = mountComponent(Component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders success icon', () => { - expect(vm.$el.querySelector('.ci-status-icon-success')).not.toBe(null); - }); - - it('renders informative text', () => { - expect(vm.$el.innerText).toContain('Ready to be merged automatically.'); - expect(vm.$el.innerText).toContain( - 'Ask someone with write access to this repository to merge this request', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js deleted file mode 100644 index bd0bd36ebc2..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import Vue from 'vue'; -import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing_to_merge.vue'; - -describe('NothingToMerge', () => { - describe('template', () => { - const Component = Vue.extend(NothingToMerge); - const newBlobPath = '/foo'; - const vm = new Component({ - el: document.createElement('div'), - propsData: { - mr: { newBlobPath }, - }, - }); - - 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.', - ); - }); - - 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); - }); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js deleted file mode 100644 index 0bca86b12b2..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js +++ /dev/null @@ -1,26 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { removeBreakLine } from 'spec/helpers/text_helper'; -import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue'; - -describe('MRWidgetPipelineBlocked', () => { - let vm; - beforeEach(() => { - const Component = Vue.extend(pipelineBlockedComponent); - vm = mountComponent(Component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders warning icon', () => { - expect(vm.$el.querySelector('.ci-status-icon-warning')).not.toBe(null); - }); - - it('renders information text', () => { - expect(removeBreakLine(vm.$el.textContent).trim()).toContain( - 'Pipeline blocked. The pipeline for this merge request requires a manual action to proceed', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js deleted file mode 100644 index 85f65d024a8..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js +++ /dev/null @@ -1,19 +0,0 @@ -import Vue from 'vue'; -import { removeBreakLine } from 'spec/helpers/text_helper'; -import PipelineFailed from '~/vue_merge_request_widget/components/states/pipeline_failed.vue'; - -describe('PipelineFailed', () => { - describe('template', () => { - const Component = Vue.extend(PipelineFailed); - const vm = new Component({ - el: document.createElement('div'), - }); - it('should have correct elements', () => { - expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(removeBreakLine(vm.$el.innerText).trim()).toContain( - 'The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure', - ); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js deleted file mode 100644 index 9ba429c3d20..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ /dev/null @@ -1,983 +0,0 @@ -import Vue from 'vue'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue'; -import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue'; -import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue'; -import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue'; -import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue'; -import eventHub from '~/vue_merge_request_widget/event_hub'; -import { MWPS_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants'; - -const commitMessage = 'This is the commit message'; -const squashCommitMessage = 'This is the squash commit message'; -const commitMessageWithDescription = 'This is the commit message description'; -const createTestMr = customConfig => { - const mr = { - isPipelineActive: false, - pipeline: null, - isPipelineFailed: false, - isPipelinePassing: false, - isMergeAllowed: true, - isApproved: true, - onlyAllowMergeIfPipelineSucceeds: false, - ffOnlyEnabled: false, - hasCI: false, - ciStatus: null, - sha: '12345678', - squash: false, - commitMessage, - squashCommitMessage, - commitMessageWithDescription, - shouldRemoveSourceBranch: true, - canRemoveSourceBranch: false, - targetBranch: 'master', - preferredAutoMergeStrategy: MWPS_MERGE_STRATEGY, - availableAutoMergeStrategies: [MWPS_MERGE_STRATEGY], - }; - - Object.assign(mr, customConfig.mr); - - return mr; -}; - -const createTestService = () => ({ - merge() {}, - poll() {}, -}); - -const createComponent = (customConfig = {}) => { - const Component = Vue.extend(ReadyToMerge); - - return new Component({ - el: document.createElement('div'), - propsData: { - mr: createTestMr(customConfig), - service: createTestService(), - }, - }); -}; - -describe('ReadyToMerge', () => { - let vm; - let updateMrCountSpy; - - beforeEach(() => { - vm = createComponent(); - updateMrCountSpy = spyOnDependency(ReadyToMerge, 'refreshUserMergeRequestCounts'); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('props', () => { - it('should have props', () => { - const { mr, service } = ReadyToMerge.props; - - expect(mr.type instanceof Object).toBeTruthy(); - expect(mr.required).toBeTruthy(); - - expect(service.type instanceof Object).toBeTruthy(); - expect(service.required).toBeTruthy(); - }); - }); - - describe('data', () => { - it('should have default data', () => { - expect(vm.mergeWhenBuildSucceeds).toBeFalsy(); - expect(vm.useCommitMessageWithDescription).toBeFalsy(); - expect(vm.showCommitMessageEditor).toBeFalsy(); - expect(vm.isMakingRequest).toBeFalsy(); - expect(vm.isMergingImmediately).toBeFalsy(); - expect(vm.commitMessage).toBe(vm.mr.commitMessage); - expect(vm.successSvg).toBeDefined(); - expect(vm.warningSvg).toBeDefined(); - }); - }); - - describe('computed', () => { - describe('isAutoMergeAvailable', () => { - it('should return true when at least one merge strategy is available', () => { - vm.mr.availableAutoMergeStrategies = [MWPS_MERGE_STRATEGY]; - - expect(vm.isAutoMergeAvailable).toBe(true); - }); - - it('should return false when no merge strategies are available', () => { - vm.mr.availableAutoMergeStrategies = []; - - expect(vm.isAutoMergeAvailable).toBe(false); - }); - }); - - describe('status', () => { - it('defaults to success', () => { - Vue.set(vm.mr, 'pipeline', true); - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.status).toEqual('success'); - }); - - it('returns failed when MR has CI but also has an unknown status', () => { - Vue.set(vm.mr, 'hasCI', true); - - expect(vm.status).toEqual('failed'); - }); - - it('returns default when MR has no pipeline', () => { - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.status).toEqual('success'); - }); - - it('returns pending when pipeline is active', () => { - Vue.set(vm.mr, 'pipeline', {}); - Vue.set(vm.mr, 'isPipelineActive', true); - - expect(vm.status).toEqual('pending'); - }); - - it('returns failed when pipeline is failed', () => { - Vue.set(vm.mr, 'pipeline', {}); - Vue.set(vm.mr, 'isPipelineFailed', true); - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.status).toEqual('failed'); - }); - }); - - describe('mergeButtonVariant', () => { - it('defaults to success class', () => { - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.mergeButtonVariant).toEqual('success'); - }); - - it('returns success class for success status', () => { - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - Vue.set(vm.mr, 'pipeline', true); - - expect(vm.mergeButtonVariant).toEqual('success'); - }); - - it('returns info class for pending status', () => { - Vue.set(vm.mr, 'availableAutoMergeStrategies', [MTWPS_MERGE_STRATEGY]); - - expect(vm.mergeButtonVariant).toEqual('info'); - }); - - it('returns danger class for failed status', () => { - vm.mr.hasCI = true; - - expect(vm.mergeButtonVariant).toEqual('danger'); - }); - }); - - describe('status icon', () => { - it('defaults to tick icon', () => { - expect(vm.iconClass).toEqual('success'); - }); - - it('shows tick for success status', () => { - vm.mr.pipeline = true; - - expect(vm.iconClass).toEqual('success'); - }); - - it('shows tick for pending status', () => { - vm.mr.pipeline = {}; - vm.mr.isPipelineActive = true; - - expect(vm.iconClass).toEqual('success'); - }); - - it('shows warning icon for failed status', () => { - vm.mr.hasCI = true; - - expect(vm.iconClass).toEqual('warning'); - }); - - it('shows warning icon for merge not allowed', () => { - vm.mr.hasCI = true; - - expect(vm.iconClass).toEqual('warning'); - }); - }); - - describe('mergeButtonText', () => { - it('should return "Merge" when no auto merge strategies are available', () => { - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.mergeButtonText).toEqual('Merge'); - }); - - it('should return "Merge in progress"', () => { - Vue.set(vm, 'isMergingImmediately', true); - - expect(vm.mergeButtonText).toEqual('Merge in progress'); - }); - - it('should return "Merge when pipeline succeeds" when the MWPS auto merge strategy is available', () => { - Vue.set(vm, 'isMergingImmediately', false); - Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY); - - expect(vm.mergeButtonText).toEqual('Merge when pipeline succeeds'); - }); - }); - - describe('autoMergeText', () => { - it('should return Merge when pipeline succeeds', () => { - Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY); - - expect(vm.autoMergeText).toEqual('Merge when pipeline succeeds'); - }); - }); - - describe('shouldShowMergeImmediatelyDropdown', () => { - it('should return false if no pipeline is active', () => { - Vue.set(vm.mr, 'isPipelineActive', false); - Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', false); - - expect(vm.shouldShowMergeImmediatelyDropdown).toBe(false); - }); - - it('should return false if "Pipelines must succeed" is enabled for the current project', () => { - Vue.set(vm.mr, 'isPipelineActive', true); - Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true); - - expect(vm.shouldShowMergeImmediatelyDropdown).toBe(false); - }); - - it('should return true if the MR\'s pipeline is active and "Pipelines must succeed" is not enabled for the current project', () => { - Vue.set(vm.mr, 'isPipelineActive', true); - Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', false); - - expect(vm.shouldShowMergeImmediatelyDropdown).toBe(true); - }); - }); - - describe('isMergeButtonDisabled', () => { - it('should return false with initial data', () => { - Vue.set(vm.mr, 'isMergeAllowed', true); - - expect(vm.isMergeButtonDisabled).toBe(false); - }); - - it('should return true when there is no commit message', () => { - Vue.set(vm.mr, 'isMergeAllowed', true); - Vue.set(vm, 'commitMessage', ''); - - expect(vm.isMergeButtonDisabled).toBe(true); - }); - - it('should return true if merge is not allowed', () => { - Vue.set(vm.mr, 'isMergeAllowed', false); - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true); - - expect(vm.isMergeButtonDisabled).toBe(true); - }); - - it('should return true when the vm instance is making request', () => { - Vue.set(vm.mr, 'isMergeAllowed', true); - Vue.set(vm, 'isMakingRequest', true); - - expect(vm.isMergeButtonDisabled).toBe(true); - }); - }); - - describe('isMergeImmediatelyDangerous', () => { - it('should always return false in CE', () => { - expect(vm.isMergeImmediatelyDangerous).toBe(false); - }); - }); - }); - - describe('methods', () => { - describe('shouldShowMergeControls', () => { - it('should return false when an external pipeline is running and required to succeed', () => { - Vue.set(vm.mr, 'isMergeAllowed', false); - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.shouldShowMergeControls).toBe(false); - }); - - it('should return true when the build succeeded or build not required to succeed', () => { - Vue.set(vm.mr, 'isMergeAllowed', true); - Vue.set(vm.mr, 'availableAutoMergeStrategies', []); - - expect(vm.shouldShowMergeControls).toBe(true); - }); - - it('should return true when showing the MWPS button and a pipeline is running that needs to be successful', () => { - Vue.set(vm.mr, 'isMergeAllowed', false); - Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]); - - expect(vm.shouldShowMergeControls).toBe(true); - }); - - it('should return true when showing the MWPS button but not required for the pipeline to succeed', () => { - Vue.set(vm.mr, 'isMergeAllowed', true); - Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]); - - expect(vm.shouldShowMergeControls).toBe(true); - }); - }); - - describe('updateMergeCommitMessage', () => { - it('should revert flag and change commitMessage', () => { - expect(vm.commitMessage).toEqual(commitMessage); - vm.updateMergeCommitMessage(true); - - expect(vm.commitMessage).toEqual(commitMessageWithDescription); - vm.updateMergeCommitMessage(false); - - expect(vm.commitMessage).toEqual(commitMessage); - }); - }); - - describe('handleMergeButtonClick', () => { - const returnPromise = status => - new Promise(resolve => { - resolve({ - data: { - status, - }, - }); - }); - - it('should handle merge when pipeline succeeds', done => { - spyOn(eventHub, '$emit'); - spyOn(vm.service, 'merge').and.returnValue(returnPromise('merge_when_pipeline_succeeds')); - vm.removeSourceBranch = false; - vm.handleMergeButtonClick(true); - - setTimeout(() => { - expect(vm.isMakingRequest).toBeTruthy(); - expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - - const params = vm.service.merge.calls.argsFor(0)[0]; - - expect(params).toEqual( - jasmine.objectContaining({ - sha: vm.mr.sha, - commit_message: vm.mr.commitMessage, - should_remove_source_branch: false, - auto_merge_strategy: 'merge_when_pipeline_succeeds', - }), - ); - done(); - }, 333); - }); - - it('should handle merge failed', done => { - spyOn(eventHub, '$emit'); - spyOn(vm.service, 'merge').and.returnValue(returnPromise('failed')); - vm.handleMergeButtonClick(false, true); - - setTimeout(() => { - expect(vm.isMakingRequest).toBeTruthy(); - expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined); - - const params = vm.service.merge.calls.argsFor(0)[0]; - - expect(params.should_remove_source_branch).toBeTruthy(); - expect(params.auto_merge_strategy).toBeUndefined(); - done(); - }, 333); - }); - - it('should handle merge action accepted case', done => { - spyOn(vm.service, 'merge').and.returnValue(returnPromise('success')); - spyOn(vm, 'initiateMergePolling'); - vm.handleMergeButtonClick(); - - setTimeout(() => { - expect(vm.isMakingRequest).toBeTruthy(); - expect(vm.initiateMergePolling).toHaveBeenCalled(); - - const params = vm.service.merge.calls.argsFor(0)[0]; - - expect(params.should_remove_source_branch).toBeTruthy(); - expect(params.auto_merge_strategy).toBeUndefined(); - done(); - }, 333); - }); - }); - - describe('initiateMergePolling', () => { - beforeEach(() => { - jasmine.clock().install(); - }); - - afterEach(() => { - jasmine.clock().uninstall(); - }); - - it('should call simplePoll', () => { - const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll'); - vm.initiateMergePolling(); - - expect(simplePoll).toHaveBeenCalledWith(jasmine.any(Function), { timeout: 0 }); - }); - - it('should call handleMergePolling', () => { - spyOn(vm, 'handleMergePolling'); - - vm.initiateMergePolling(); - - jasmine.clock().tick(2000); - - expect(vm.handleMergePolling).toHaveBeenCalled(); - }); - }); - - describe('handleMergePolling', () => { - const returnPromise = state => - new Promise(resolve => { - resolve({ - data: { - state, - source_branch_exists: true, - }, - }); - }); - - beforeEach(() => { - loadFixtures('merge_requests/merge_request_of_current_user.html'); - }); - - it('should call start and stop polling when MR merged', done => { - spyOn(eventHub, '$emit'); - spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged')); - spyOn(vm, 'initiateRemoveSourceBranchPolling'); - - let cpc = false; // continuePollingCalled - let spc = false; // stopPollingCalled - - vm.handleMergePolling( - () => { - cpc = true; - }, - () => { - spc = true; - }, - ); - setTimeout(() => { - expect(vm.service.poll).toHaveBeenCalled(); - expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - expect(eventHub.$emit).toHaveBeenCalledWith('FetchActionsContent'); - expect(vm.initiateRemoveSourceBranchPolling).toHaveBeenCalled(); - expect(updateMrCountSpy).toHaveBeenCalled(); - expect(cpc).toBeFalsy(); - expect(spc).toBeTruthy(); - - done(); - }, 333); - }); - - it('updates status box', done => { - spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged')); - spyOn(vm, 'initiateRemoveSourceBranchPolling'); - - vm.handleMergePolling(() => {}, () => {}); - - setTimeout(() => { - const statusBox = document.querySelector('.status-box'); - - expect(statusBox.classList.contains('status-box-mr-merged')).toBeTruthy(); - expect(statusBox.textContent).toContain('Merged'); - - done(); - }); - }); - - it('hides close button', done => { - spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged')); - spyOn(vm, 'initiateRemoveSourceBranchPolling'); - - vm.handleMergePolling(() => {}, () => {}); - - setTimeout(() => { - expect(document.querySelector('.btn-close').classList.contains('hidden')).toBeTruthy(); - - done(); - }); - }); - - it('updates merge request count badge', done => { - spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged')); - spyOn(vm, 'initiateRemoveSourceBranchPolling'); - - vm.handleMergePolling(() => {}, () => {}); - - setTimeout(() => { - expect(document.querySelector('.js-merge-counter').textContent).toBe('0'); - - done(); - }); - }); - - it('should continue polling until MR is merged', done => { - spyOn(vm.service, 'poll').and.returnValue(returnPromise('some_other_state')); - spyOn(vm, 'initiateRemoveSourceBranchPolling'); - - let cpc = false; // continuePollingCalled - let spc = false; // stopPollingCalled - - vm.handleMergePolling( - () => { - cpc = true; - }, - () => { - spc = true; - }, - ); - setTimeout(() => { - expect(cpc).toBeTruthy(); - expect(spc).toBeFalsy(); - - done(); - }, 333); - }); - }); - - describe('initiateRemoveSourceBranchPolling', () => { - it('should emit event and call simplePoll', () => { - spyOn(eventHub, '$emit'); - const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll'); - - vm.initiateRemoveSourceBranchPolling(); - - expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [true]); - expect(simplePoll).toHaveBeenCalled(); - }); - }); - - describe('handleRemoveBranchPolling', () => { - const returnPromise = state => - new Promise(resolve => { - resolve({ - data: { - source_branch_exists: state, - }, - }); - }); - - it('should call start and stop polling when MR merged', done => { - spyOn(eventHub, '$emit'); - spyOn(vm.service, 'poll').and.returnValue(returnPromise(false)); - - let cpc = false; // continuePollingCalled - let spc = false; // stopPollingCalled - - vm.handleRemoveBranchPolling( - () => { - cpc = true; - }, - () => { - spc = true; - }, - ); - setTimeout(() => { - expect(vm.service.poll).toHaveBeenCalled(); - - const args = eventHub.$emit.calls.argsFor(0); - - expect(args[0]).toEqual('MRWidgetUpdateRequested'); - expect(args[1]).toBeDefined(); - args[1](); - - expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]); - - expect(cpc).toBeFalsy(); - expect(spc).toBeTruthy(); - - done(); - }, 333); - }); - - it('should continue polling until MR is merged', done => { - spyOn(vm.service, 'poll').and.returnValue(returnPromise(true)); - - let cpc = false; // continuePollingCalled - let spc = false; // stopPollingCalled - - vm.handleRemoveBranchPolling( - () => { - cpc = true; - }, - () => { - spc = true; - }, - ); - setTimeout(() => { - expect(cpc).toBeTruthy(); - expect(spc).toBeFalsy(); - - done(); - }, 333); - }); - }); - }); - - describe('Remove source branch checkbox', () => { - describe('when user can merge but cannot delete branch', () => { - it('should be disabled in the rendered output', () => { - const checkboxElement = vm.$el.querySelector('#remove-source-branch-input'); - - expect(checkboxElement).toBeNull(); - }); - }); - - describe('when user can merge and can delete branch', () => { - beforeEach(() => { - vm = createComponent({ - mr: { canRemoveSourceBranch: true }, - }); - }); - - it('isRemoveSourceBranchButtonDisabled should be false', () => { - expect(vm.isRemoveSourceBranchButtonDisabled).toBe(false); - }); - - it('removed source branch should be enabled in rendered output', () => { - const checkboxElement = vm.$el.querySelector('#remove-source-branch-input'); - - expect(checkboxElement).not.toBeNull(); - }); - }); - }); - - describe('render children components', () => { - let wrapper; - const localVue = createLocalVue(); - - const createLocalComponent = (customConfig = {}) => { - wrapper = shallowMount(localVue.extend(ReadyToMerge), { - localVue, - propsData: { - mr: createTestMr(customConfig), - service: createTestService(), - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - const findCheckboxElement = () => wrapper.find(SquashBeforeMerge); - const findCommitsHeaderElement = () => wrapper.find(CommitsHeader); - const findCommitEditElements = () => wrapper.findAll(CommitEdit); - const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown); - const findFirstCommitEditLabel = () => - findCommitEditElements() - .at(0) - .props('label'); - - describe('squash checkbox', () => { - it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => { - createLocalComponent({ - mr: { commitsCount: 2, enableSquashBeforeMerge: true }, - }); - - expect(findCheckboxElement().exists()).toBeTruthy(); - }); - - it('should not be rendered when squash before merge is disabled', () => { - createLocalComponent({ mr: { commitsCount: 2, enableSquashBeforeMerge: false } }); - - expect(findCheckboxElement().exists()).toBeFalsy(); - }); - - it('should not be rendered when there is only 1 commit', () => { - createLocalComponent({ mr: { commitsCount: 1, enableSquashBeforeMerge: true } }); - - expect(findCheckboxElement().exists()).toBeFalsy(); - }); - }); - - describe('commits count collapsible header', () => { - it('should be rendered when fast-forward is disabled', () => { - createLocalComponent(); - - expect(findCommitsHeaderElement().exists()).toBeTruthy(); - }); - - describe('when fast-forward is enabled', () => { - it('should be rendered if squash and squash before are enabled and there is more than 1 commit', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - enableSquashBeforeMerge: true, - squash: true, - commitsCount: 2, - }, - }); - - expect(findCommitsHeaderElement().exists()).toBeTruthy(); - }); - - it('should not be rendered if squash before merge is disabled', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - enableSquashBeforeMerge: false, - squash: true, - commitsCount: 2, - }, - }); - - expect(findCommitsHeaderElement().exists()).toBeFalsy(); - }); - - it('should not be rendered if squash is disabled', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: false, - enableSquashBeforeMerge: true, - commitsCount: 2, - }, - }); - - expect(findCommitsHeaderElement().exists()).toBeFalsy(); - }); - - it('should not be rendered if commits count is 1', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: true, - enableSquashBeforeMerge: true, - commitsCount: 1, - }, - }); - - expect(findCommitsHeaderElement().exists()).toBeFalsy(); - }); - }); - }); - - describe('commits edit components', () => { - describe('when fast-forward merge is enabled', () => { - it('should not be rendered if squash is disabled', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: false, - enableSquashBeforeMerge: true, - commitsCount: 2, - }, - }); - - expect(findCommitEditElements().length).toBe(0); - }); - - it('should not be rendered if squash before merge is disabled', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: true, - enableSquashBeforeMerge: false, - commitsCount: 2, - }, - }); - - expect(findCommitEditElements().length).toBe(0); - }); - - it('should not be rendered if there is only one commit', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: true, - enableSquashBeforeMerge: true, - commitsCount: 1, - }, - }); - - expect(findCommitEditElements().length).toBe(0); - }); - - it('should have one edit component if squash is enabled and there is more than 1 commit', () => { - createLocalComponent({ - mr: { - ffOnlyEnabled: true, - squash: true, - enableSquashBeforeMerge: true, - commitsCount: 2, - }, - }); - - expect(findCommitEditElements().length).toBe(1); - expect(findFirstCommitEditLabel()).toBe('Squash commit message'); - }); - }); - - it('should have one edit component when squash is disabled', () => { - createLocalComponent(); - - expect(findCommitEditElements().length).toBe(1); - }); - - it('should have two edit components when squash is enabled and there is more than 1 commit', () => { - createLocalComponent({ - mr: { - commitsCount: 2, - squash: true, - enableSquashBeforeMerge: true, - }, - }); - - expect(findCommitEditElements().length).toBe(2); - }); - - it('should have one edit components when squash is enabled and there is 1 commit only', () => { - createLocalComponent({ - mr: { - commitsCount: 1, - squash: true, - enableSquashBeforeMerge: true, - }, - }); - - expect(findCommitEditElements().length).toBe(1); - }); - - it('should have correct edit merge commit label', () => { - createLocalComponent(); - - expect(findFirstCommitEditLabel()).toBe('Merge commit message'); - }); - - it('should have correct edit squash commit label', () => { - createLocalComponent({ - mr: { - commitsCount: 2, - squash: true, - enableSquashBeforeMerge: true, - }, - }); - - expect(findFirstCommitEditLabel()).toBe('Squash commit message'); - }); - }); - - describe('commits dropdown', () => { - it('should not be rendered if squash is disabled', () => { - createLocalComponent(); - - expect(findCommitDropdownElement().exists()).toBeFalsy(); - }); - - it('should be rendered if squash is enabled and there is more than 1 commit', () => { - createLocalComponent({ - mr: { enableSquashBeforeMerge: true, squash: true, commitsCount: 2 }, - }); - - expect(findCommitDropdownElement().exists()).toBeTruthy(); - }); - }); - }); - - describe('Merge controls', () => { - describe('when allowed to merge', () => { - beforeEach(() => { - vm = createComponent({ - mr: { isMergeAllowed: true, canRemoveSourceBranch: true }, - }); - }); - - it('shows remove source branch checkbox', () => { - expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).not.toBeNull(); - }); - - it('shows modify commit message button', () => { - expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined(); - }); - - it('does not show message about needing to resolve items', () => { - expect(vm.$el.querySelector('.js-resolve-mr-widget-items-message')).toBeNull(); - }); - }); - - describe('when not allowed to merge', () => { - beforeEach(() => { - vm = createComponent({ - mr: { isMergeAllowed: false }, - }); - }); - - it('does not show remove source branch checkbox', () => { - expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).toBeNull(); - }); - - it('shows message to resolve all items before being allowed to merge', () => { - expect(vm.$el.querySelector('.js-resolve-mr-widget-items-message')).toBeDefined(); - }); - }); - }); - - describe('Merge request project settings', () => { - describe('when the merge commit merge method is enabled', () => { - beforeEach(() => { - vm = createComponent({ - mr: { ffOnlyEnabled: false }, - }); - }); - - it('should not show fast forward message', () => { - expect(vm.$el.querySelector('.mr-fast-forward-message')).toBeNull(); - }); - - it('should show "Modify commit message" button', () => { - expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined(); - }); - }); - - describe('when the fast-forward merge method is enabled', () => { - beforeEach(() => { - vm = createComponent({ - mr: { ffOnlyEnabled: true }, - }); - }); - - it('should show fast forward message', () => { - expect(vm.$el.querySelector('.mr-fast-forward-message')).toBeDefined(); - }); - - it('should not show "Modify commit message" button', () => { - expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeNull(); - }); - }); - }); - - describe('with a mismatched SHA', () => { - const findMismatchShaBlock = () => vm.$el.querySelector('.js-sha-mismatch'); - - beforeEach(() => { - vm = createComponent({ - mr: { - isSHAMismatch: true, - mergeRequestDiffsPath: '/merge_requests/1/diffs', - }, - }); - }); - - it('displays a warning message', () => { - expect(findMismatchShaBlock()).toExist(); - }); - - it('warns the user to refresh to review', () => { - expect(findMismatchShaBlock().textContent.trim()).toBe( - 'New changes were added. Reload the page to review them', - ); - }); - - it('displays link to the diffs tab', () => { - expect(findMismatchShaBlock().querySelector('a').href).toContain(vm.mr.mergeRequestDiffsPath); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js deleted file mode 100644 index 11eb0fef9b2..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js +++ /dev/null @@ -1,25 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { removeBreakLine } from 'spec/helpers/text_helper'; -import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue'; - -describe('ShaMismatch', () => { - let vm; - - beforeEach(() => { - const Component = Vue.extend(ShaMismatch); - vm = mountComponent(Component); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('should render information message', () => { - expect(vm.$el.querySelector('button').disabled).toEqual(true); - - expect(removeBreakLine(vm.$el.textContent).trim()).toContain( - 'The source branch HEAD has recently changed. Please reload the page and review the changes before merging', - ); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js deleted file mode 100644 index b70d580ed04..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js +++ /dev/null @@ -1,99 +0,0 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue'; - -const localVue = createLocalVue(); - -describe('Squash before merge component', () => { - let wrapper; - - const createComponent = props => { - wrapper = shallowMount(localVue.extend(SquashBeforeMerge), { - localVue, - propsData: { - ...props, - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('checkbox', () => { - const findCheckbox = () => wrapper.find('.js-squash-checkbox'); - - it('is unchecked if passed value prop is false', () => { - createComponent({ - value: false, - }); - - expect(findCheckbox().element.checked).toBeFalsy(); - }); - - it('is checked if passed value prop is true', () => { - createComponent({ - value: true, - }); - - expect(findCheckbox().element.checked).toBeTruthy(); - }); - - it('changes value on click', done => { - createComponent({ - value: false, - }); - - findCheckbox().element.checked = true; - - findCheckbox().trigger('change'); - - wrapper.vm.$nextTick(() => { - expect(findCheckbox().element.checked).toBeTruthy(); - done(); - }); - }); - - it('is disabled if isDisabled prop is true', () => { - createComponent({ - value: false, - isDisabled: true, - }); - - expect(findCheckbox().attributes('disabled')).toBeTruthy(); - }); - }); - - describe('about link', () => { - it('is not rendered if no help path is passed', () => { - createComponent({ - value: false, - }); - - const aboutLink = wrapper.find('a'); - - expect(aboutLink.exists()).toBeFalsy(); - }); - - it('is rendered if help path is passed', () => { - createComponent({ - value: false, - helpPath: 'test-path', - }); - - const aboutLink = wrapper.find('a'); - - expect(aboutLink.exists()).toBeTruthy(); - }); - - it('should have a correct help path if passed', () => { - createComponent({ - value: false, - helpPath: 'test-path', - }); - - const aboutLink = wrapper.find('a'); - - expect(aboutLink.attributes('href')).toEqual('test-path'); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js deleted file mode 100644 index e8367caa438..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js +++ /dev/null @@ -1,45 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import UnresolvedDiscussions from '~/vue_merge_request_widget/components/states/unresolved_discussions.vue'; - -describe('UnresolvedDiscussions', () => { - const Component = Vue.extend(UnresolvedDiscussions); - let vm; - - afterEach(() => { - vm.$destroy(); - }); - - describe('with threads path', () => { - beforeEach(() => { - vm = mountComponent(Component, { - mr: { - createIssueToResolveDiscussionsPath: gl.TEST_HOST, - }, - }); - }); - - it('should have correct elements', () => { - expect(vm.$el.innerText).toContain( - 'There are unresolved threads. Please resolve these threads', - ); - - expect(vm.$el.innerText).toContain('Create an issue to resolve them later'); - expect(vm.$el.querySelector('.js-create-issue').getAttribute('href')).toEqual(gl.TEST_HOST); - }); - }); - - describe('without threads path', () => { - beforeEach(() => { - vm = mountComponent(Component, { mr: {} }); - }); - - it('should not show create issue link if user cannot create issue', () => { - expect(vm.$el.innerText).toContain( - 'There are unresolved threads. Please resolve these threads', - ); - - expect(vm.$el.querySelector('.js-create-issue')).toEqual(null); - }); - }); -}); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js deleted file mode 100644 index 9153231b974..00000000000 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js +++ /dev/null @@ -1,99 +0,0 @@ -import Vue from 'vue'; -import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue'; -import eventHub from '~/vue_merge_request_widget/event_hub'; - -const createComponent = () => { - const Component = Vue.extend(WorkInProgress); - const mr = { - title: 'The best MR ever', - removeWIPPath: '/path/to/remove/wip', - }; - const service = { - removeWIP() {}, - }; - return new Component({ - el: document.createElement('div'), - propsData: { mr, service }, - }); -}; - -describe('Wip', () => { - describe('props', () => { - it('should have props', () => { - const { mr, service } = WorkInProgress.props; - - expect(mr.type instanceof Object).toBeTruthy(); - expect(mr.required).toBeTruthy(); - - expect(service.type instanceof Object).toBeTruthy(); - expect(service.required).toBeTruthy(); - }); - }); - - describe('data', () => { - it('should have default data', () => { - const vm = createComponent(); - - expect(vm.isMakingRequest).toBeFalsy(); - }); - }); - - describe('methods', () => { - const mrObj = { - is_new_mr_data: true, - }; - - describe('handleRemoveWIP', () => { - it('should make a request to service and handle response', done => { - const vm = createComponent(); - - const flashSpy = spyOnDependency(WorkInProgress, 'createFlash').and.returnValue(true); - spyOn(eventHub, '$emit'); - spyOn(vm.service, 'removeWIP').and.returnValue( - new Promise(resolve => { - resolve({ - data: mrObj, - }); - }), - ); - - vm.handleRemoveWIP(); - setTimeout(() => { - expect(vm.isMakingRequest).toBeTruthy(); - expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj); - expect(flashSpy).toHaveBeenCalledWith('The merge request can now be merged.', 'notice'); - done(); - }, 333); - }); - }); - }); - - describe('template', () => { - let vm; - let el; - - beforeEach(() => { - vm = createComponent(); - el = vm.$el; - }); - - it('should have correct elements', () => { - expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.innerText).toContain('This is a Work in Progress'); - expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(el.querySelector('button').innerText).toContain('Merge'); - expect(el.querySelector('.js-remove-wip').innerText.replace(/\s\s+/g, ' ')).toContain( - 'Resolve WIP status', - ); - }); - - it('should not show removeWIP button is user cannot update MR', done => { - vm.mr.removeWIPPath = ''; - - Vue.nextTick(() => { - expect(el.querySelector('.js-remove-wip')).toEqual(null); - done(); - }); - }); - }); -}); |