summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_mr_widget/components
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_mr_widget/components')
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_author_spec.js3
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_expandable_section_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js32
-rw-r--r--spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_pipeline_failed_spec.js.snap2
-rw-r--r--spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js10
-rw-r--r--spec/frontend/vue_mr_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js78
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js39
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js8
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js32
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js27
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js25
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js7
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js4
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js218
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js7
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_wip_spec.js26
-rw-r--r--spec/frontend/vue_mr_widget/components/terraform/mr_widget_terraform_container_spec.js14
19 files changed, 311 insertions, 236 deletions
diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
index 1aeb080aa04..82526af7afa 100644
--- a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
@@ -1,5 +1,6 @@
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue';
describe('Merge Request Collapsible Extension', () => {
@@ -46,9 +47,9 @@ describe('Merge Request Collapsible Extension', () => {
});
describe('onClick', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper.find('button').trigger('click');
- return wrapper.vm.$nextTick();
+ await nextTick();
});
it('rendes the provided slot', () => {
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_author_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_author_spec.js
index e7c10ab4c2d..8a42e2e2ce7 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_author_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_author_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import MrWidgetAuthor from '~/vue_merge_request_widget/components/mr_widget_author.vue';
window.gl = window.gl || {};
@@ -50,7 +51,7 @@ describe('MrWidgetAuthor', () => {
},
});
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(wrapper.find('img').attributes('src')).toBe('no_avatar.png');
});
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_expandable_section_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_expandable_section_spec.js
index 3e111cd308a..631aef412a6 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_expandable_section_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_expandable_section_spec.js
@@ -1,5 +1,6 @@
import { GlButton, GlCollapse, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_widget_expandable_section.vue';
describe('MrWidgetExpanableSection', () => {
@@ -43,9 +44,9 @@ describe('MrWidgetExpanableSection', () => {
});
describe('when collapse section is open', () => {
- beforeEach(() => {
+ beforeEach(async () => {
findButton().vm.$emit('click');
- return wrapper.vm.$nextTick();
+ await nextTick();
});
it('renders button with collapse text', () => {
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js
index f55d313a719..c0a30a5093d 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js
@@ -1,6 +1,7 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
import MemoryUsage from '~/vue_merge_request_widget/components/deployment/memory_usage.vue';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
@@ -152,23 +153,18 @@ describe('MemoryUsage', () => {
});
describe('loadMetrics', () => {
- const returnServicePromise = () =>
- new Promise((resolve) => {
- resolve({
- data: metricsMockData,
- });
+ it('should load metrics data using MRWidgetService', async () => {
+ jest.spyOn(MRWidgetService, 'fetchMetrics').mockResolvedValue({
+ data: metricsMockData,
});
-
- it('should load metrics data using MRWidgetService', (done) => {
- jest.spyOn(MRWidgetService, 'fetchMetrics').mockReturnValue(returnServicePromise(true));
jest.spyOn(vm, 'computeGraphData').mockImplementation(() => {});
vm.loadMetrics();
- setImmediate(() => {
- expect(MRWidgetService.fetchMetrics).toHaveBeenCalledWith(url);
- expect(vm.computeGraphData).toHaveBeenCalledWith(metrics, deployment_time);
- done();
- });
+
+ await waitForPromises();
+
+ expect(MRWidgetService.fetchMetrics).toHaveBeenCalledWith(url);
+ expect(vm.computeGraphData).toHaveBeenCalledWith(metrics, deployment_time);
});
});
});
@@ -184,7 +180,7 @@ describe('MemoryUsage', () => {
vm.hasMetrics = false;
vm.loadFailed = false;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(el.querySelector('.js-usage-info.usage-info-loading')).toBeDefined();
expect(el.querySelector('.js-usage-info .usage-info-load-spinner')).toBeDefined();
@@ -203,7 +199,7 @@ describe('MemoryUsage', () => {
vm.loadFailed = false;
vm.memoryMetrics = metricsMockData.metrics.memory_values[0].values;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(el.querySelector('.memory-graph-container')).toBeDefined();
expect(el.querySelector('.js-usage-info').innerText).toContain(messages.hasMetrics);
done();
@@ -215,7 +211,7 @@ describe('MemoryUsage', () => {
vm.hasMetrics = false;
vm.loadFailed = true;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(el.querySelector('.js-usage-info.usage-info-failed')).toBeDefined();
expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadFailed);
@@ -228,7 +224,7 @@ describe('MemoryUsage', () => {
vm.hasMetrics = false;
vm.loadFailed = false;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(el.querySelector('.js-usage-info.usage-info-unavailable')).toBeDefined();
expect(el.querySelector('.js-usage-info').innerText).toContain(messages.metricsUnavailable);
diff --git a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_pipeline_failed_spec.js.snap b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_pipeline_failed_spec.js.snap
index a124008b36a..98297630792 100644
--- a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_pipeline_failed_spec.js.snap
+++ b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_pipeline_failed_spec.js.snap
@@ -16,7 +16,7 @@ exports[`PipelineFailed should render error message with a disabled merge button
class="bold"
>
<gl-sprintf-stub
- message="The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions."
+ message="Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
/>
</span>
</div>
diff --git a/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js
index c30f6f1dfd1..c0add94e6ed 100644
--- a/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue';
const testCommitMessage = 'Test commit message';
@@ -46,16 +47,15 @@ describe('Commits edit component', () => {
expect(findTextarea().element.value).toBe(testCommitMessage);
});
- it('emits an input event and receives changed value', () => {
+ it('emits an input event and receives changed value', async () => {
const changedCommitMessage = 'Changed commit message';
findTextarea().element.value = changedCommitMessage;
findTextarea().trigger('input');
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted().input[0]).toEqual([changedCommitMessage]);
- expect(findTextarea().element.value).toBe(changedCommitMessage);
- });
+ await nextTick();
+ expect(wrapper.emitted().input[0]).toEqual([changedCommitMessage]);
+ expect(findTextarea().element.value).toBe(changedCommitMessage);
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js b/spec/frontend/vue_mr_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
new file mode 100644
index 00000000000..0e1c38437f0
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
@@ -0,0 +1,78 @@
+import { shallowMount } from '@vue/test-utils';
+import MergeFailedPipelineConfirmationDialog from '~/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog.vue';
+import { trimText } from 'helpers/text_helper';
+
+describe('MergeFailedPipelineConfirmationDialog', () => {
+ let wrapper;
+
+ const GlModal = {
+ template: `
+ <div>
+ <slot></slot>
+ <slot name="modal-footer"></slot>
+ </div>
+ `,
+ methods: {
+ hide: jest.fn(),
+ },
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(MergeFailedPipelineConfirmationDialog, {
+ propsData: {
+ visible: true,
+ },
+ stubs: {
+ GlModal,
+ },
+ attachTo: document.body,
+ });
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findMergeBtn = () => wrapper.find('[data-testid="merge-unverified-changes"]');
+ const findCancelBtn = () => wrapper.find('[data-testid="merge-cancel-btn"]');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render informational text explaining why merging immediately can be dangerous', () => {
+ expect(trimText(wrapper.text())).toContain(
+ 'The latest pipeline for this merge request did not succeed. The latest changes are unverified. Are you sure you want to attempt to merge?',
+ );
+ });
+
+ it('should emit the mergeWithFailedPipeline event', () => {
+ findMergeBtn().vm.$emit('click');
+
+ expect(wrapper.emitted('mergeWithFailedPipeline')).toBeTruthy();
+ });
+
+ it('when the cancel button is clicked should emit cancel and call hide', () => {
+ jest.spyOn(findModal().vm, 'hide');
+
+ findCancelBtn().vm.$emit('click');
+
+ expect(wrapper.emitted('cancel')).toBeTruthy();
+ expect(findModal().vm.hide).toHaveBeenCalled();
+ });
+
+ it('should emit cancel when the hide event is emitted', () => {
+ findModal().vm.$emit('hide');
+
+ expect(wrapper.emitted('cancel')).toBeTruthy();
+ });
+
+ it('when modal is shown it will focus the cancel button', () => {
+ jest.spyOn(findCancelBtn().element, 'focus');
+
+ findModal().vm.$emit('shown');
+
+ expect(findCancelBtn().element.focus).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js
index 52a56af454f..7387ed2d5e9 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import autoMergeEnabledComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue';
import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
import eventHub from '~/vue_merge_request_widget/event_hub';
@@ -185,7 +186,7 @@ describe('MRWidgetAutoMergeEnabled', () => {
describe('methods', () => {
describe('cancelAutomaticMerge', () => {
- it('should set flag and call service then tell main component to update the widget with data', (done) => {
+ it('should set flag and call service then tell main component to update the widget with data', async () => {
factory({
...defaultMrProps(),
});
@@ -201,20 +202,20 @@ describe('MRWidgetAutoMergeEnabled', () => {
);
wrapper.vm.cancelAutomaticMerge();
- setImmediate(() => {
- expect(wrapper.vm.isCancellingAutoMerge).toBeTruthy();
- if (mergeRequestWidgetGraphql) {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- } else {
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- }
- done();
- });
+
+ await waitForPromises();
+
+ expect(wrapper.vm.isCancellingAutoMerge).toBeTruthy();
+ if (mergeRequestWidgetGraphql) {
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
+ } else {
+ expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
+ }
});
});
describe('removeSourceBranch', () => {
- it('should set flag and call service then request main component to update the widget', (done) => {
+ it('should set flag and call service then request main component to update the widget', async () => {
factory({
...defaultMrProps(),
});
@@ -227,14 +228,14 @@ describe('MRWidgetAutoMergeEnabled', () => {
);
wrapper.vm.removeSourceBranch();
- setImmediate(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(wrapper.vm.service.merge).toHaveBeenCalledWith({
- sha,
- auto_merge_strategy: MWPS_MERGE_STRATEGY,
- should_remove_source_branch: true,
- });
- done();
+
+ await waitForPromises();
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
+ expect(wrapper.vm.service.merge).toHaveBeenCalledWith({
+ sha,
+ auto_merge_strategy: MWPS_MERGE_STRATEGY,
+ should_remove_source_branch: true,
});
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
index 4c763f40cbe..663fabb761c 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
@@ -1,5 +1,6 @@
import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
const commits = [
@@ -51,11 +52,10 @@ describe('Commits message dropdown component', () => {
expect(findFirstDropdownElement().text()).toContain('Commit 1');
});
- it('should emit a commit title on selecting commit', () => {
+ it('should emit a commit title on selecting commit', async () => {
findFirstDropdownElement().vm.$emit('click');
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted().input[0]).toEqual(['Update test.txt']);
- });
+ await nextTick();
+ expect(wrapper.emitted().input[0]).toEqual(['Update test.txt']);
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js
index 4d05e732f48..2796403b7d0 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js
@@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
+import { nextTick } from 'vue';
import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue';
describe('Commits header component', () => {
@@ -58,15 +59,14 @@ describe('Commits header component', () => {
expect(findCommitToggle().attributes('aria-label')).toBe('Expand');
});
- it('has a chevron-right icon', () => {
+ it('has a chevron-right icon', async () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ expanded: false });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCommitToggle().props('icon')).toBe('chevron-right');
- });
+ await nextTick();
+ expect(findCommitToggle().props('icon')).toBe('chevron-right');
});
describe('when squash is disabled', () => {
@@ -118,25 +118,19 @@ describe('Commits header component', () => {
wrapper.setData({ expanded: true });
});
- it('toggle has aria-label equal to collapse', (done) => {
- wrapper.vm.$nextTick(() => {
- expect(findCommitToggle().attributes('aria-label')).toBe('Collapse');
- done();
- });
+ it('toggle has aria-label equal to collapse', async () => {
+ await nextTick();
+ expect(findCommitToggle().attributes('aria-label')).toBe('Collapse');
});
- it('has a chevron-down icon', (done) => {
- wrapper.vm.$nextTick(() => {
- expect(findCommitToggle().props('icon')).toBe('chevron-down');
- done();
- });
+ it('has a chevron-down icon', async () => {
+ await nextTick();
+ expect(findCommitToggle().props('icon')).toBe('chevron-down');
});
- it('has a collapse text', (done) => {
- wrapper.vm.$nextTick(() => {
- expect(findHeaderWrapper().text()).toBe('Collapse');
- done();
- });
+ it('has a collapse text', async () => {
+ await nextTick();
+ expect(findHeaderWrapper().text()).toBe('Collapse');
});
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
index ec222e66a97..9dcde3e4f33 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import { removeBreakLine } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
@@ -20,7 +21,7 @@ describe('MRWidgetConflicts', () => {
const resolveConflictsBtnText = 'Resolve conflicts';
const mergeLocallyBtnText = 'Merge locally';
- function createComponent(propsData = {}) {
+ async function createComponent(propsData = {}) {
wrapper = extendedWrapper(
shallowMount(ConflictsComponent, {
propsData,
@@ -55,7 +56,7 @@ describe('MRWidgetConflicts', () => {
});
}
- return wrapper.vm.$nextTick();
+ await nextTick();
}
afterEach(() => {
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
index e0f1f091129..7d86e453bc7 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -1,6 +1,7 @@
import { getByRole } from '@testing-library/dom';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import { OPEN_REVERT_MODAL, OPEN_CHERRY_PICK_MODAL } from '~/projects/commit/constants';
import modalEventHub from '~/projects/commit/event_hub';
import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
@@ -127,7 +128,7 @@ describe('MRWidgetMerged', () => {
describe('methods', () => {
describe('removeSourceBranch', () => {
- it('should set flag and call service then request main component to update the widget', (done) => {
+ it('should set flag and call service then request main component to update the widget', async () => {
jest.spyOn(vm.service, 'removeSourceBranch').mockReturnValue(
new Promise((resolve) => {
resolve({
@@ -139,14 +140,14 @@ describe('MRWidgetMerged', () => {
);
vm.removeSourceBranch();
- setImmediate(() => {
- const args = eventHub.$emit.mock.calls[0];
-
- expect(vm.isMakingRequest).toEqual(true);
- expect(args[0]).toEqual('MRWidgetUpdateRequested');
- expect(args[1]).not.toThrow();
- done();
- });
+
+ await waitForPromises();
+
+ const args = eventHub.$emit.mock.calls[0];
+
+ expect(vm.isMakingRequest).toEqual(true);
+ expect(args[0]).toEqual('MRWidgetUpdateRequested');
+ expect(args[1]).not.toThrow();
});
});
});
@@ -200,7 +201,7 @@ describe('MRWidgetMerged', () => {
it('hides button to copy commit SHA if SHA does not exist', (done) => {
vm.mr.mergeCommitSha = null;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(selectors.copyMergeShaButton).toBe(null);
expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
done();
@@ -216,7 +217,7 @@ describe('MRWidgetMerged', () => {
it('should not show source branch deleted text', (done) => {
vm.mr.sourceBranchRemoved = false;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
done();
});
@@ -226,7 +227,7 @@ describe('MRWidgetMerged', () => {
vm.mr.isRemovingSourceBranch = true;
vm.mr.sourceBranchRemoved = false;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(vm.$el.innerText).toContain('The source branch is being deleted');
expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
done();
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js
index e6b2e9fa176..e16c897a49b 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js
@@ -1,6 +1,11 @@
import { shallowMount } from '@vue/test-utils';
+import simplePoll from '~/lib/utils/simple_poll';
import MrWidgetMerging from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue';
+jest.mock('~/lib/utils/simple_poll', () =>
+ jest.fn().mockImplementation(jest.requireActual('~/lib/utils/simple_poll').default),
+);
+
describe('MRWidgetMerging', () => {
let wrapper;
@@ -11,6 +16,10 @@ describe('MRWidgetMerging', () => {
mr: {
targetBranchPath: '/branch-path',
targetBranch: 'branch',
+ transitionStateMachine() {},
+ },
+ service: {
+ poll: jest.fn().mockResolvedValue(),
},
},
stubs: {
@@ -46,4 +55,20 @@ describe('MRWidgetMerging', () => {
expect(wrapper.find('a').attributes('href')).toBe('/branch-path');
});
+
+ describe('initiateMergePolling', () => {
+ it('should call simplePoll', () => {
+ wrapper.vm.initiateMergePolling();
+
+ expect(simplePoll).toHaveBeenCalledWith(expect.any(Function), { timeout: 0 });
+ });
+
+ it('should call handleMergePolling', () => {
+ jest.spyOn(wrapper.vm, 'handleMergePolling').mockImplementation(() => {});
+
+ wrapper.vm.initiateMergePolling();
+
+ expect(wrapper.vm.handleMergePolling).toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
index 936d673768c..ddce07954ab 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
@@ -1,9 +1,10 @@
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import MissingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue';
let wrapper;
-function factory(sourceBranchRemoved, mergeRequestWidgetGraphql) {
+async function factory(sourceBranchRemoved, mergeRequestWidgetGraphql) {
wrapper = shallowMount(MissingBranchComponent, {
propsData: {
mr: { sourceBranchRemoved },
@@ -19,7 +20,7 @@ function factory(sourceBranchRemoved, mergeRequestWidgetGraphql) {
wrapper.setData({ state: { sourceBranchExists: !sourceBranchRemoved } });
}
- return wrapper.vm.$nextTick();
+ await nextTick();
}
describe('MRWidgetMissingBranch', () => {
@@ -40,7 +41,7 @@ describe('MRWidgetMissingBranch', () => {
async ({ sourceBranchRemoved, branchName }) => {
await factory(sourceBranchRemoved, mergeRequestWidgetGraphql);
- expect(wrapper.find('[data-testid="missingBranchName"]').text()).toContain(branchName);
+ expect(wrapper.find('[data-testid="widget-content"]').text()).toContain(branchName);
},
);
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
index 2c04905d3a9..c7c0b69425d 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing_to_merge.vue';
describe('NothingToMerge', () => {
@@ -20,7 +20,7 @@ describe('NothingToMerge', () => {
it('should not show new blob link if there is no link available', () => {
vm.mr.newBlobPath = null;
- Vue.nextTick(() => {
+ nextTick(() => {
expect(vm.$el.querySelector('[data-testid="createFileButton"]')).toEqual(null);
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index f4ecebbb40c..78585ed75bc 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -1,12 +1,14 @@
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import { nextTick } from 'vue';
import { GlSprintf } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
import simplePoll from '~/lib/utils/simple_poll';
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 CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue';
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 MergeFailedPipelineConfirmationDialog from '~/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog.vue';
import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
import eventHub from '~/vue_merge_request_widget/event_hub';
@@ -61,6 +63,11 @@ const createTestService = () => ({
});
let wrapper;
+
+const findMergeButton = () => wrapper.find('[data-testid="merge-button"]');
+const findPipelineFailedConfirmModal = () =>
+ wrapper.findComponent(MergeFailedPipelineConfirmationDialog);
+
const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) => {
wrapper = shallowMount(ReadyToMerge, {
propsData: {
@@ -132,33 +139,13 @@ describe('ReadyToMerge', () => {
});
});
- describe('mergeButtonVariant', () => {
+ describe('Merge Button Variant', () => {
it('defaults to confirm class', () => {
createComponent({
mr: { availableAutoMergeStrategies: [] },
});
- expect(wrapper.vm.mergeButtonVariant).toEqual('confirm');
- });
-
- it('returns confirm class for success status', () => {
- createComponent({
- mr: { availableAutoMergeStrategies: [], pipeline: true },
- });
-
- expect(wrapper.vm.mergeButtonVariant).toEqual('confirm');
- });
-
- it('returns confirm class for pending status', () => {
- createComponent();
-
- expect(wrapper.vm.mergeButtonVariant).toEqual('confirm');
- });
-
- it('returns danger class for failed status', () => {
- createComponent({ mr: { hasCI: true } });
-
- expect(wrapper.vm.mergeButtonVariant).toEqual('danger');
+ expect(findMergeButton().attributes('variant')).toBe('confirm');
});
});
@@ -196,7 +183,7 @@ describe('ReadyToMerge', () => {
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ isMergingImmediately: true });
- await Vue.nextTick();
+ await nextTick();
expect(wrapper.vm.mergeButtonText).toEqual('Merge in progress');
});
@@ -266,7 +253,7 @@ describe('ReadyToMerge', () => {
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ isMakingRequest: true });
- await Vue.nextTick();
+ await nextTick();
expect(wrapper.vm.isMergeButtonDisabled).toBe(true);
});
@@ -275,110 +262,86 @@ describe('ReadyToMerge', () => {
describe('methods', () => {
describe('handleMergeButtonClick', () => {
- const returnPromise = (status) =>
- new Promise((resolve) => {
- resolve({
- data: {
- status,
- },
- });
- });
+ const response = (status) => ({
+ data: {
+ status,
+ },
+ });
- it('should handle merge when pipeline succeeds', (done) => {
+ it('should handle merge when pipeline succeeds', async () => {
createComponent();
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
jest
.spyOn(wrapper.vm.service, 'merge')
- .mockReturnValue(returnPromise('merge_when_pipeline_succeeds'));
+ .mockResolvedValue(response('merge_when_pipeline_succeeds'));
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ removeSourceBranch: false });
wrapper.vm.handleMergeButtonClick(true);
- setImmediate(() => {
- expect(wrapper.vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
- transition: 'start-auto-merge',
- });
+ await waitForPromises();
- const params = wrapper.vm.service.merge.mock.calls[0][0];
-
- expect(params).toEqual(
- expect.objectContaining({
- sha: wrapper.vm.mr.sha,
- commit_message: wrapper.vm.mr.commitMessage,
- should_remove_source_branch: false,
- auto_merge_strategy: 'merge_when_pipeline_succeeds',
- }),
- );
- done();
+ expect(wrapper.vm.isMakingRequest).toBeTruthy();
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
+ expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
+ transition: 'start-auto-merge',
});
+
+ const params = wrapper.vm.service.merge.mock.calls[0][0];
+
+ expect(params).toEqual(
+ expect.objectContaining({
+ sha: wrapper.vm.mr.sha,
+ commit_message: wrapper.vm.mr.commitMessage,
+ should_remove_source_branch: false,
+ auto_merge_strategy: 'merge_when_pipeline_succeeds',
+ }),
+ );
});
- it('should handle merge failed', (done) => {
+ it('should handle merge failed', async () => {
createComponent();
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(returnPromise('failed'));
+ jest.spyOn(wrapper.vm.service, 'merge').mockResolvedValue(response('failed'));
wrapper.vm.handleMergeButtonClick(false, true);
- setImmediate(() => {
- expect(wrapper.vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
+ await waitForPromises();
- const params = wrapper.vm.service.merge.mock.calls[0][0];
+ expect(wrapper.vm.isMakingRequest).toBeTruthy();
+ expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
- expect(params.should_remove_source_branch).toBeTruthy();
- expect(params.auto_merge_strategy).toBeUndefined();
- done();
- });
+ const params = wrapper.vm.service.merge.mock.calls[0][0];
+
+ expect(params.should_remove_source_branch).toBeTruthy();
+ expect(params.auto_merge_strategy).toBeUndefined();
});
- it('should handle merge action accepted case', (done) => {
+ it('should handle merge action accepted case', async () => {
createComponent();
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(returnPromise('success'));
- jest.spyOn(wrapper.vm, 'initiateMergePolling').mockImplementation(() => {});
+ jest.spyOn(wrapper.vm.service, 'merge').mockResolvedValue(response('success'));
+ jest.spyOn(wrapper.vm.mr, 'transitionStateMachine');
wrapper.vm.handleMergeButtonClick();
expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
transition: 'start-merge',
});
- setImmediate(() => {
- expect(wrapper.vm.isMakingRequest).toBeTruthy();
- expect(wrapper.vm.initiateMergePolling).toHaveBeenCalled();
-
- const params = wrapper.vm.service.merge.mock.calls[0][0];
+ await waitForPromises();
- expect(params.should_remove_source_branch).toBeTruthy();
- expect(params.auto_merge_strategy).toBeUndefined();
- done();
+ expect(wrapper.vm.isMakingRequest).toBeTruthy();
+ expect(wrapper.vm.mr.transitionStateMachine).toHaveBeenCalledWith({
+ transition: 'start-merge',
});
- });
- });
-
- describe('initiateMergePolling', () => {
- it('should call simplePoll', () => {
- createComponent();
-
- wrapper.vm.initiateMergePolling();
-
- expect(simplePoll).toHaveBeenCalledWith(expect.any(Function), { timeout: 0 });
- });
- it('should call handleMergePolling', () => {
- createComponent();
-
- jest.spyOn(wrapper.vm, 'handleMergePolling').mockImplementation(() => {});
+ const params = wrapper.vm.service.merge.mock.calls[0][0];
- wrapper.vm.initiateMergePolling();
-
- expect(wrapper.vm.handleMergePolling).toHaveBeenCalled();
+ expect(params.should_remove_source_branch).toBeTruthy();
+ expect(params.auto_merge_strategy).toBeUndefined();
});
});
@@ -396,20 +359,17 @@ describe('ReadyToMerge', () => {
});
describe('handleRemoveBranchPolling', () => {
- const returnPromise = (state) =>
- new Promise((resolve) => {
- resolve({
- data: {
- source_branch_exists: state,
- },
- });
- });
+ const response = (state) => ({
+ data: {
+ source_branch_exists: state,
+ },
+ });
- it('should call start and stop polling when MR merged', (done) => {
+ it('should call start and stop polling when MR merged', async () => {
createComponent();
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- jest.spyOn(wrapper.vm.service, 'poll').mockReturnValue(returnPromise(false));
+ jest.spyOn(wrapper.vm.service, 'poll').mockResolvedValue(response(false));
let cpc = false; // continuePollingCalled
let spc = false; // stopPollingCalled
@@ -422,28 +382,27 @@ describe('ReadyToMerge', () => {
spc = true;
},
);
- setImmediate(() => {
- expect(wrapper.vm.service.poll).toHaveBeenCalled();
- const args = eventHub.$emit.mock.calls[0];
+ await waitForPromises();
- expect(args[0]).toEqual('MRWidgetUpdateRequested');
- expect(args[1]).toBeDefined();
- args[1]();
+ expect(wrapper.vm.service.poll).toHaveBeenCalled();
- expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]);
+ const args = eventHub.$emit.mock.calls[0];
- expect(cpc).toBeFalsy();
- expect(spc).toBeTruthy();
+ expect(args[0]).toEqual('MRWidgetUpdateRequested');
+ expect(args[1]).toBeDefined();
+ args[1]();
- done();
- });
+ expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]);
+
+ expect(cpc).toBeFalsy();
+ expect(spc).toBeTruthy();
});
- it('should continue polling until MR is merged', (done) => {
+ it('should continue polling until MR is merged', async () => {
createComponent();
- jest.spyOn(wrapper.vm.service, 'poll').mockReturnValue(returnPromise(true));
+ jest.spyOn(wrapper.vm.service, 'poll').mockResolvedValue(response(true));
let cpc = false; // continuePollingCalled
let spc = false; // stopPollingCalled
@@ -456,12 +415,11 @@ describe('ReadyToMerge', () => {
spc = true;
},
);
- setImmediate(() => {
- expect(cpc).toBeTruthy();
- expect(spc).toBeFalsy();
- done();
- });
+ await waitForPromises();
+
+ expect(cpc).toBeTruthy();
+ expect(spc).toBeFalsy();
});
});
});
@@ -710,7 +668,7 @@ describe('ReadyToMerge', () => {
commitsWithoutMergeCommits: {},
},
});
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(findCommitEditElements().length).toBe(2);
});
@@ -794,4 +752,24 @@ describe('ReadyToMerge', () => {
});
});
});
+
+ describe('Merge button when pipeline has failed', () => {
+ beforeEach(() => {
+ createComponent({
+ mr: { pipeline: {}, isPipelineFailed: true, availableAutoMergeStrategies: [] },
+ });
+ });
+
+ it('should display the correct merge text', () => {
+ expect(findMergeButton().text()).toBe('Merge...');
+ });
+
+ it('should display confirmation modal when merge button is clicked', async () => {
+ expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: false });
+
+ await findMergeButton().vm.$emit('click');
+
+ expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: true });
+ });
+ });
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
index 6abdbd11f5e..6ea2e8675d3 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
@@ -1,16 +1,13 @@
import { GlFormCheckbox, GlLink } from '@gitlab/ui';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
import { SQUASH_BEFORE_MERGE } from '~/vue_merge_request_widget/i18n';
-const localVue = createLocalVue();
-
describe('Squash before merge component', () => {
let wrapper;
const createComponent = (props) => {
- wrapper = shallowMount(localVue.extend(SquashBeforeMerge), {
- localVue,
+ wrapper = shallowMount(SquashBeforeMerge, {
propsData: {
...props,
},
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_wip_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_wip_spec.js
index 4070ca8d8dc..4998147c6b6 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_wip_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_wip_spec.js
@@ -1,4 +1,5 @@
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue';
import toast from '~/vue_shared/plugins/global_toast';
import eventHub from '~/vue_merge_request_widget/event_hub';
@@ -47,7 +48,7 @@ describe('Wip', () => {
};
describe('handleRemoveDraft', () => {
- it('should make a request to service and handle response', (done) => {
+ it('should make a request to service and handle response', async () => {
const vm = createComponent();
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
@@ -60,12 +61,12 @@ describe('Wip', () => {
);
vm.handleRemoveDraft();
- setImmediate(() => {
- expect(vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- expect(toast).toHaveBeenCalledWith('Marked as ready. Merging is now allowed.');
- done();
- });
+
+ await waitForPromises();
+
+ expect(vm.isMakingRequest).toBeTruthy();
+ expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
+ expect(toast).toHaveBeenCalledWith('Marked as ready. Merging is now allowed.');
});
});
});
@@ -91,13 +92,12 @@ describe('Wip', () => {
);
});
- it('should not show removeWIP button is user cannot update MR', (done) => {
+ it('should not show removeWIP button is user cannot update MR', async () => {
vm.mr.removeWIPPath = '';
- Vue.nextTick(() => {
- expect(el.querySelector('.js-remove-draft')).toEqual(null);
- done();
- });
+ await nextTick();
+
+ expect(el.querySelector('.js-remove-draft')).toEqual(null);
});
});
});
diff --git a/spec/frontend/vue_mr_widget/components/terraform/mr_widget_terraform_container_spec.js b/spec/frontend/vue_mr_widget/components/terraform/mr_widget_terraform_container_spec.js
index 9048975875a..b7c22b403aa 100644
--- a/spec/frontend/vue_mr_widget/components/terraform/mr_widget_terraform_container_spec.js
+++ b/spec/frontend/vue_mr_widget/components/terraform/mr_widget_terraform_container_spec.js
@@ -1,6 +1,7 @@
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
import MrWidgetExpanableSection from '~/vue_merge_request_widget/components/mr_widget_expandable_section.vue';
@@ -39,15 +40,14 @@ describe('MrWidgetTerraformConainer', () => {
});
describe('when data is loading', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mockPollingApi(200, plans, {});
- return mountWrapper().then(() => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ loading: true });
- return wrapper.vm.$nextTick();
- });
+ await mountWrapper();
+ // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // eslint-disable-next-line no-restricted-syntax
+ wrapper.setData({ loading: true });
+ await nextTick();
});
it('diplays loading skeleton', () => {