summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_mr_widget
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_mr_widget')
-rw-r--r--spec/frontend/vue_mr_widget/components/approvals/approvals_spec.js70
-rw-r--r--spec/frontend/vue_mr_widget/components/extensions/utils_spec.js2
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_memory_usage_spec.js44
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js31
-rw-r--r--spec/frontend/vue_mr_widget/extensions/test_report/index_spec.js149
-rw-r--r--spec/frontend/vue_mr_widget/mr_widget_options_spec.js121
-rw-r--r--spec/frontend/vue_mr_widget/stores/artifacts_list/actions_spec.js35
-rw-r--r--spec/frontend/vue_mr_widget/test_extensions.js9
8 files changed, 298 insertions, 163 deletions
diff --git a/spec/frontend/vue_mr_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_mr_widget/components/approvals/approvals_spec.js
index 36850e623c7..4985417ad99 100644
--- a/spec/frontend/vue_mr_widget/components/approvals/approvals_spec.js
+++ b/spec/frontend/vue_mr_widget/components/approvals/approvals_spec.js
@@ -1,3 +1,4 @@
+import { nextTick } from 'vue';
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import createFlash from '~/flash';
@@ -28,11 +29,6 @@ const testApprovals = () => ({
});
const testApprovalRulesResponse = () => ({ rules: [{ id: 2 }] });
-// For some reason, the `Promise.resolve()` needs to be deferred
-// or the timing doesn't work.
-const tick = () => Promise.resolve();
-const waitForTick = (done) => tick().then(done).catch(done.fail);
-
describe('MRWidget approvals', () => {
let wrapper;
let service;
@@ -105,7 +101,7 @@ describe('MRWidget approvals', () => {
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ fetchingApprovals: true });
- return tick().then(() => {
+ return nextTick().then(() => {
expect(wrapper.text()).toContain(FETCH_LOADING);
});
});
@@ -116,10 +112,10 @@ describe('MRWidget approvals', () => {
});
describe('when fetch approvals error', () => {
- beforeEach((done) => {
+ beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockReturnValue(Promise.reject());
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('still shows loading message', () => {
@@ -133,13 +129,13 @@ describe('MRWidget approvals', () => {
describe('action button', () => {
describe('when mr is closed', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.isOpen = false;
mr.approvals.user_has_approved = false;
mr.approvals.user_can_approve = true;
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('action is not rendered', () => {
@@ -148,12 +144,12 @@ describe('MRWidget approvals', () => {
});
describe('when user cannot approve', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.user_has_approved = false;
mr.approvals.user_can_approve = false;
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('action is not rendered', () => {
@@ -168,9 +164,9 @@ describe('MRWidget approvals', () => {
});
describe('and MR is unapproved', () => {
- beforeEach((done) => {
+ beforeEach(() => {
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('approve action is rendered', () => {
@@ -188,10 +184,10 @@ describe('MRWidget approvals', () => {
});
describe('with no approvers', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.approved_by = [];
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('approve action (with inverted style) is rendered', () => {
@@ -204,10 +200,10 @@ describe('MRWidget approvals', () => {
});
describe('with approvers', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.approved_by = [{ user: { id: 7 } }];
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('approve additionally action is rendered', () => {
@@ -221,9 +217,9 @@ describe('MRWidget approvals', () => {
});
describe('when approve action is clicked', () => {
- beforeEach((done) => {
+ beforeEach(() => {
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('shows loading icon', () => {
@@ -234,15 +230,15 @@ describe('MRWidget approvals', () => {
action.vm.$emit('click');
- return tick().then(() => {
+ return nextTick().then(() => {
expect(action.props('loading')).toBe(true);
});
});
describe('and after loading', () => {
- beforeEach((done) => {
+ beforeEach(() => {
findAction().vm.$emit('click');
- waitForTick(done);
+ return nextTick();
});
it('calls service approve', () => {
@@ -259,10 +255,10 @@ describe('MRWidget approvals', () => {
});
describe('and error', () => {
- beforeEach((done) => {
+ beforeEach(() => {
jest.spyOn(service, 'approveMergeRequest').mockReturnValue(Promise.reject());
findAction().vm.$emit('click');
- waitForTick(done);
+ return nextTick();
});
it('flashes error message', () => {
@@ -273,12 +269,12 @@ describe('MRWidget approvals', () => {
});
describe('when user has approved', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.user_has_approved = true;
mr.approvals.user_can_approve = false;
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('revoke action is rendered', () => {
@@ -291,9 +287,9 @@ describe('MRWidget approvals', () => {
describe('when revoke action is clicked', () => {
describe('and successful', () => {
- beforeEach((done) => {
+ beforeEach(() => {
findAction().vm.$emit('click');
- waitForTick(done);
+ return nextTick();
});
it('calls service unapprove', () => {
@@ -310,10 +306,10 @@ describe('MRWidget approvals', () => {
});
describe('and error', () => {
- beforeEach((done) => {
+ beforeEach(() => {
jest.spyOn(service, 'unapproveMergeRequest').mockReturnValue(Promise.reject());
findAction().vm.$emit('click');
- waitForTick(done);
+ return nextTick();
});
it('flashes error message', () => {
@@ -333,11 +329,11 @@ describe('MRWidget approvals', () => {
});
describe('and can approve', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.user_can_approve = true;
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('is shown', () => {
@@ -350,11 +346,11 @@ describe('MRWidget approvals', () => {
});
describe('and cannot approve', () => {
- beforeEach((done) => {
+ beforeEach(() => {
mr.approvals.user_can_approve = false;
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('is shown', () => {
@@ -369,9 +365,9 @@ describe('MRWidget approvals', () => {
});
describe('approvals summary', () => {
- beforeEach((done) => {
+ beforeEach(() => {
createComponent();
- waitForTick(done);
+ return nextTick();
});
it('is rendered with props', () => {
diff --git a/spec/frontend/vue_mr_widget/components/extensions/utils_spec.js b/spec/frontend/vue_mr_widget/components/extensions/utils_spec.js
index 64e802c4fa5..98cfc04eb25 100644
--- a/spec/frontend/vue_mr_widget/components/extensions/utils_spec.js
+++ b/spec/frontend/vue_mr_widget/components/extensions/utils_spec.js
@@ -8,7 +8,7 @@ describe('generateText', () => {
${'%{danger_start}Hello world%{danger_end}'} | ${'<span class="gl-font-weight-bold gl-text-red-500">Hello world</span>'}
${'%{critical_start}Hello world%{critical_end}'} | ${'<span class="gl-font-weight-bold gl-text-red-800">Hello world</span>'}
${'%{same_start}Hello world%{same_end}'} | ${'<span class="gl-font-weight-bold gl-text-gray-700">Hello world</span>'}
- ${'%{small_start}Hello world%{small_end}'} | ${'<span class="gl-font-sm">Hello world</span>'}
+ ${'%{small_start}Hello world%{small_end}'} | ${'<span class="gl-font-sm gl-text-gray-700">Hello world</span>'}
${'%{strong_start}%{danger_start}Hello world%{danger_end}%{strong_end}'} | ${'<span class="gl-font-weight-bold"><span class="gl-font-weight-bold gl-text-red-500">Hello world</span></span>'}
${'%{no_exist_start}Hello world%{no_exist_end}'} | ${'Hello world'}
${['array']} | ${null}
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 c0a30a5093d..f0106914674 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
@@ -175,22 +175,19 @@ describe('MemoryUsage', () => {
expect(el.querySelector('.js-usage-info')).toBeDefined();
});
- it('should show loading metrics message while metrics are being loaded', (done) => {
+ it('should show loading metrics message while metrics are being loaded', async () => {
vm.loadingMetrics = true;
vm.hasMetrics = false;
vm.loadFailed = false;
- nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-loading')).toBeDefined();
+ await nextTick();
- expect(el.querySelector('.js-usage-info .usage-info-load-spinner')).toBeDefined();
-
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadingMetrics);
- done();
- });
+ 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);
});
- it('should show deployment memory usage when metrics are loaded', (done) => {
+ it('should show deployment memory usage when metrics are loaded', async () => {
// ignore BoostrapVue warnings
jest.spyOn(console, 'warn').mockImplementation();
@@ -199,37 +196,32 @@ describe('MemoryUsage', () => {
vm.loadFailed = false;
vm.memoryMetrics = metricsMockData.metrics.memory_values[0].values;
- nextTick(() => {
- expect(el.querySelector('.memory-graph-container')).toBeDefined();
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.hasMetrics);
- done();
- });
+ await nextTick();
+
+ expect(el.querySelector('.memory-graph-container')).toBeDefined();
+ expect(el.querySelector('.js-usage-info').innerText).toContain(messages.hasMetrics);
});
- it('should show failure message when metrics loading failed', (done) => {
+ it('should show failure message when metrics loading failed', async () => {
vm.loadingMetrics = false;
vm.hasMetrics = false;
vm.loadFailed = true;
- nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-failed')).toBeDefined();
+ await nextTick();
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadFailed);
- done();
- });
+ expect(el.querySelector('.js-usage-info.usage-info-failed')).toBeDefined();
+ expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadFailed);
});
- it('should show metrics unavailable message when metrics loading failed', (done) => {
+ it('should show metrics unavailable message when metrics loading failed', async () => {
vm.loadingMetrics = false;
vm.hasMetrics = false;
vm.loadFailed = false;
- nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-unavailable')).toBeDefined();
+ await nextTick();
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.metricsUnavailable);
- done();
- });
+ 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/mr_widget_merged_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
index 7d86e453bc7..8efc4d84624 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
@@ -198,14 +198,13 @@ describe('MRWidgetMerged', () => {
);
});
- it('hides button to copy commit SHA if SHA does not exist', (done) => {
+ it('hides button to copy commit SHA if SHA does not exist', async () => {
vm.mr.mergeCommitSha = null;
- nextTick(() => {
- expect(selectors.copyMergeShaButton).toBe(null);
- expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
- done();
- });
+ await nextTick();
+
+ expect(selectors.copyMergeShaButton).toBe(null);
+ expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
});
it('shows merge commit SHA link', () => {
@@ -214,24 +213,22 @@ describe('MRWidgetMerged', () => {
expect(selectors.mergeCommitShaLink.href).toBe(vm.mr.mergeCommitPath);
});
- it('should not show source branch deleted text', (done) => {
+ it('should not show source branch deleted text', async () => {
vm.mr.sourceBranchRemoved = false;
- nextTick(() => {
- expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
- done();
- });
+ await nextTick();
+
+ expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
});
- it('should show source branch deleting text', (done) => {
+ it('should show source branch deleting text', async () => {
vm.mr.isRemovingSourceBranch = true;
vm.mr.sourceBranchRemoved = false;
- 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();
- });
+ await nextTick();
+
+ expect(vm.$el.innerText).toContain('The source branch is being deleted');
+ expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
});
it('should use mergedEvent mergedAt as tooltip title', () => {
diff --git a/spec/frontend/vue_mr_widget/extensions/test_report/index_spec.js b/spec/frontend/vue_mr_widget/extensions/test_report/index_spec.js
new file mode 100644
index 00000000000..88b8e32bd5d
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/extensions/test_report/index_spec.js
@@ -0,0 +1,149 @@
+import { GlButton } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import testReportExtension from '~/vue_merge_request_widget/extensions/test_report';
+import { i18n } from '~/vue_merge_request_widget/extensions/test_report/constants';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { trimText } from 'helpers/text_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
+import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
+import httpStatusCodes from '~/lib/utils/http_status';
+
+import { failedReport } from 'jest/reports/mock_data/mock_data';
+import mixedResultsTestReports from 'jest/reports/mock_data/new_and_fixed_failures_report.json';
+import newErrorsTestReports from 'jest/reports/mock_data/new_errors_report.json';
+import newFailedTestReports from 'jest/reports/mock_data/new_failures_report.json';
+import successTestReports from 'jest/reports/mock_data/no_failures_report.json';
+import resolvedFailures from 'jest/reports/mock_data/resolved_failures.json';
+
+const reportWithParsingErrors = failedReport;
+reportWithParsingErrors.suites[0].suite_errors = {
+ head: 'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
+ base: 'JUnit data parsing failed: string not matched',
+};
+
+describe('Test report extension', () => {
+ let wrapper;
+ let mock;
+
+ registerExtension(testReportExtension);
+
+ const endpoint = '/root/repo/-/merge_requests/4/test_reports.json';
+
+ const mockApi = (statusCode, data = mixedResultsTestReports) => {
+ mock.onGet(endpoint).reply(statusCode, data);
+ };
+
+ const findToggleCollapsedButton = () => wrapper.findByTestId('toggle-button');
+ const findTertiaryButton = () => wrapper.find(GlButton);
+ const findAllExtensionListItems = () => wrapper.findAllByTestId('extension-list-item');
+
+ const createComponent = () => {
+ wrapper = mountExtended(extensionsContainer, {
+ propsData: {
+ mr: {
+ testResultsPath: endpoint,
+ headBlobPath: 'head/blob/path',
+ pipeline: { path: 'pipeline/path' },
+ },
+ },
+ });
+ };
+
+ const createExpandedWidgetWithData = async (data = mixedResultsTestReports) => {
+ mockApi(httpStatusCodes.OK, data);
+ createComponent();
+ await waitForPromises();
+ findToggleCollapsedButton().trigger('click');
+ await waitForPromises();
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ describe('summary', () => {
+ it('displays loading text', () => {
+ mockApi(httpStatusCodes.OK);
+ createComponent();
+
+ expect(wrapper.text()).toContain(i18n.loading);
+ });
+
+ it('displays failed loading text', async () => {
+ mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain(i18n.error);
+ });
+
+ it.each`
+ description | mockData | expectedResult
+ ${'mixed test results'} | ${mixedResultsTestReports} | ${'Test summary: 2 failed and 2 fixed test results, 11 total tests'}
+ ${'unchanged test results'} | ${successTestReports} | ${'Test summary: no changed test results, 11 total tests'}
+ ${'tests with errors'} | ${newErrorsTestReports} | ${'Test summary: 2 errors, 11 total tests'}
+ ${'failed test results'} | ${newFailedTestReports} | ${'Test summary: 2 failed, 11 total tests'}
+ ${'resolved failures'} | ${resolvedFailures} | ${'Test summary: 4 fixed test results, 11 total tests'}
+ `('displays summary text for $description', async ({ mockData, expectedResult }) => {
+ mockApi(httpStatusCodes.OK, mockData);
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain(expectedResult);
+ });
+
+ it('displays a link to the full report', async () => {
+ mockApi(httpStatusCodes.OK);
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findTertiaryButton().text()).toBe('Full report');
+ expect(findTertiaryButton().attributes('href')).toBe('pipeline/path/test_report');
+ });
+
+ it('shows an error when a suite has a parsing error', async () => {
+ mockApi(httpStatusCodes.OK, reportWithParsingErrors);
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain(i18n.error);
+ });
+ });
+
+ describe('expanded data', () => {
+ it('displays summary for each suite', async () => {
+ await createExpandedWidgetWithData();
+
+ expect(trimText(findAllExtensionListItems().at(0).text())).toBe(
+ 'rspec:pg: 1 failed and 2 fixed test results, 8 total tests',
+ );
+ expect(trimText(findAllExtensionListItems().at(1).text())).toBe(
+ 'java ant: 1 failed, 3 total tests',
+ );
+ });
+
+ it('displays suite parsing errors', async () => {
+ await createExpandedWidgetWithData(reportWithParsingErrors);
+
+ const suiteText = trimText(findAllExtensionListItems().at(0).text());
+
+ expect(suiteText).toContain(
+ 'Head report parsing error: JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
+ );
+ expect(suiteText).toContain(
+ 'Base report parsing error: JUnit data parsing failed: string not matched',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
index 0540107ea5f..9719e81fe12 100644
--- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
@@ -46,6 +46,8 @@ describe('MrWidgetOptions', () => {
let mock;
const COLLABORATION_MESSAGE = 'Members who can merge are allowed to add commits';
+ const findExtensionToggleButton = () =>
+ wrapper.find('[data-testid="widget-extension"] [data-testid="toggle-button"]');
beforeEach(() => {
gl.mrWidgetData = { ...mockData };
@@ -187,9 +189,9 @@ describe('MrWidgetOptions', () => {
});
describe('when merge request is opened', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.isOpen = true;
- nextTick(done);
+ return nextTick();
});
it('should render collaboration status', () => {
@@ -198,9 +200,9 @@ describe('MrWidgetOptions', () => {
});
describe('when merge request is not opened', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.isOpen = false;
- nextTick(done);
+ return nextTick();
});
it('should not render collaboration status', () => {
@@ -215,9 +217,9 @@ describe('MrWidgetOptions', () => {
});
describe('when merge request is opened', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.isOpen = true;
- nextTick(done);
+ return nextTick();
});
it('should not render collaboration status', () => {
@@ -229,11 +231,11 @@ describe('MrWidgetOptions', () => {
describe('showMergePipelineForkWarning', () => {
describe('when the source project and target project are the same', () => {
- beforeEach((done) => {
+ beforeEach(() => {
Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
Vue.set(wrapper.vm.mr, 'targetProjectId', 1);
- nextTick(done);
+ return nextTick();
});
it('should be false', () => {
@@ -242,11 +244,11 @@ describe('MrWidgetOptions', () => {
});
describe('when merge pipelines are not enabled', () => {
- beforeEach((done) => {
+ beforeEach(() => {
Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', false);
Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
Vue.set(wrapper.vm.mr, 'targetProjectId', 2);
- nextTick(done);
+ return nextTick();
});
it('should be false', () => {
@@ -255,11 +257,11 @@ describe('MrWidgetOptions', () => {
});
describe('when merge pipelines are enabled _and_ the source project and target project are different', () => {
- beforeEach((done) => {
+ beforeEach(() => {
Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
Vue.set(wrapper.vm.mr, 'targetProjectId', 2);
- nextTick(done);
+ return nextTick();
});
it('should be true', () => {
@@ -439,15 +441,10 @@ describe('MrWidgetOptions', () => {
expect(setFaviconOverlay).toHaveBeenCalledWith(overlayDataUrl);
});
- it('should not call setFavicon when there is no ciStatusFaviconPath', (done) => {
+ it('should not call setFavicon when there is no ciStatusFaviconPath', async () => {
wrapper.vm.mr.ciStatusFaviconPath = null;
- wrapper.vm
- .setFaviconHelper()
- .then(() => {
- expect(faviconElement.getAttribute('href')).toEqual(null);
- done();
- })
- .catch(done.fail);
+ await wrapper.vm.setFaviconHelper();
+ expect(faviconElement.getAttribute('href')).toEqual(null);
});
});
@@ -534,44 +531,36 @@ describe('MrWidgetOptions', () => {
expect(wrapper.find('.close-related-link').exists()).toBe(true);
});
- it('does not render if state is nothingToMerge', (done) => {
+ it('does not render if state is nothingToMerge', async () => {
wrapper.vm.mr.state = stateKey.nothingToMerge;
- nextTick(() => {
- expect(wrapper.find('.close-related-link').exists()).toBe(false);
- done();
- });
+ await nextTick();
+ expect(wrapper.find('.close-related-link').exists()).toBe(false);
});
});
describe('rendering source branch removal status', () => {
- it('renders when user cannot remove branch and branch should be removed', (done) => {
+ it('renders when user cannot remove branch and branch should be removed', async () => {
wrapper.vm.mr.canRemoveSourceBranch = false;
wrapper.vm.mr.shouldRemoveSourceBranch = true;
wrapper.vm.mr.state = 'readyToMerge';
- nextTick(() => {
- const tooltip = wrapper.find('[data-testid="question-o-icon"]');
-
- expect(wrapper.text()).toContain('Deletes the source branch');
- expect(tooltip.attributes('title')).toBe(
- 'A user with write access to the source branch selected this option',
- );
+ await nextTick();
+ const tooltip = wrapper.find('[data-testid="question-o-icon"]');
- done();
- });
+ expect(wrapper.text()).toContain('Deletes the source branch');
+ expect(tooltip.attributes('title')).toBe(
+ 'A user with write access to the source branch selected this option',
+ );
});
- it('does not render in merged state', (done) => {
+ it('does not render in merged state', async () => {
wrapper.vm.mr.canRemoveSourceBranch = false;
wrapper.vm.mr.shouldRemoveSourceBranch = true;
wrapper.vm.mr.state = 'merged';
- nextTick(() => {
- expect(wrapper.text()).toContain('The source branch has been deleted');
- expect(wrapper.text()).not.toContain('Deletes the source branch');
-
- done();
- });
+ await nextTick();
+ expect(wrapper.text()).toContain('The source branch has been deleted');
+ expect(wrapper.text()).not.toContain('Deletes the source branch');
});
});
@@ -605,7 +594,7 @@ describe('MrWidgetOptions', () => {
status: SUCCESS,
};
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.deployments.push(
{
...deploymentMockData,
@@ -616,7 +605,7 @@ describe('MrWidgetOptions', () => {
},
);
- nextTick(done);
+ return nextTick();
});
it('renders multiple deployments', () => {
@@ -639,7 +628,7 @@ describe('MrWidgetOptions', () => {
describe('pipeline for target branch after merge', () => {
describe('with information for target branch pipeline', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.state = 'merged';
wrapper.vm.mr.mergePipeline = {
id: 127,
@@ -747,7 +736,7 @@ describe('MrWidgetOptions', () => {
},
cancel_path: '/root/ci-web-terminal/pipelines/127/cancel',
};
- nextTick(done);
+ return nextTick();
});
it('renders pipeline block', () => {
@@ -755,7 +744,7 @@ describe('MrWidgetOptions', () => {
});
describe('with post merge deployments', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.postMergeDeployments = [
{
id: 15,
@@ -787,7 +776,7 @@ describe('MrWidgetOptions', () => {
},
];
- nextTick(done);
+ return nextTick();
});
it('renders post deployment information', () => {
@@ -797,10 +786,10 @@ describe('MrWidgetOptions', () => {
});
describe('without information for target branch pipeline', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.state = 'merged';
- nextTick(done);
+ return nextTick();
});
it('does not render pipeline block', () => {
@@ -809,10 +798,10 @@ describe('MrWidgetOptions', () => {
});
describe('when state is not merged', () => {
- beforeEach((done) => {
+ beforeEach(() => {
wrapper.vm.mr.state = 'archived';
- nextTick(done);
+ return nextTick();
});
it('does not render pipeline block', () => {
@@ -905,7 +894,7 @@ describe('MrWidgetOptions', () => {
beforeEach(() => {
pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
- registerExtension(workingExtension);
+ registerExtension(workingExtension());
createComponent();
});
@@ -937,9 +926,7 @@ describe('MrWidgetOptions', () => {
it('renders full data', async () => {
await waitForPromises();
- wrapper
- .find('[data-testid="widget-extension"] [data-testid="toggle-button"]')
- .trigger('click');
+ findExtensionToggleButton().trigger('click');
await nextTick();
@@ -975,6 +962,24 @@ describe('MrWidgetOptions', () => {
});
});
+ describe('expansion', () => {
+ it('hides collapse button', async () => {
+ registerExtension(workingExtension(false));
+ createComponent();
+ await waitForPromises();
+
+ expect(findExtensionToggleButton().exists()).toBe(false);
+ });
+
+ it('shows collapse button', async () => {
+ registerExtension(workingExtension(true));
+ createComponent();
+ await waitForPromises();
+
+ expect(findExtensionToggleButton().exists()).toBe(true);
+ });
+ });
+
describe('mock polling extension', () => {
let pollRequest;
let pollStop;
@@ -1025,7 +1030,7 @@ describe('MrWidgetOptions', () => {
it('captures sentry error and displays error when poll has failed', () => {
expect(captureException).toHaveBeenCalledTimes(1);
expect(captureException).toHaveBeenCalledWith(new Error('Fetch error'));
- expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('error');
+ expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('failed');
});
});
});
@@ -1036,7 +1041,7 @@ describe('MrWidgetOptions', () => {
const itHandlesTheException = () => {
expect(captureException).toHaveBeenCalledTimes(1);
expect(captureException).toHaveBeenCalledWith(new Error('Fetch error'));
- expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('error');
+ expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('failed');
};
beforeEach(() => {
diff --git a/spec/frontend/vue_mr_widget/stores/artifacts_list/actions_spec.js b/spec/frontend/vue_mr_widget/stores/artifacts_list/actions_spec.js
index 9423fa17c44..22562bb4ddb 100644
--- a/spec/frontend/vue_mr_widget/stores/artifacts_list/actions_spec.js
+++ b/spec/frontend/vue_mr_widget/stores/artifacts_list/actions_spec.js
@@ -22,27 +22,25 @@ describe('Artifacts App Store Actions', () => {
});
describe('setEndpoint', () => {
- it('should commit SET_ENDPOINT mutation', (done) => {
- testAction(
+ it('should commit SET_ENDPOINT mutation', () => {
+ return testAction(
setEndpoint,
'endpoint.json',
mockedState,
[{ type: types.SET_ENDPOINT, payload: 'endpoint.json' }],
[],
- done,
);
});
});
describe('requestArtifacts', () => {
- it('should commit REQUEST_ARTIFACTS mutation', (done) => {
- testAction(
+ it('should commit REQUEST_ARTIFACTS mutation', () => {
+ return testAction(
requestArtifacts,
null,
mockedState,
[{ type: types.REQUEST_ARTIFACTS }],
[],
- done,
);
});
});
@@ -62,7 +60,7 @@ describe('Artifacts App Store Actions', () => {
});
describe('success', () => {
- it('dispatches requestArtifacts and receiveArtifactsSuccess ', (done) => {
+ it('dispatches requestArtifacts and receiveArtifactsSuccess ', () => {
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, [
{
text: 'result.txt',
@@ -72,7 +70,7 @@ describe('Artifacts App Store Actions', () => {
},
]);
- testAction(
+ return testAction(
fetchArtifacts,
null,
mockedState,
@@ -96,7 +94,6 @@ describe('Artifacts App Store Actions', () => {
type: 'receiveArtifactsSuccess',
},
],
- done,
);
});
});
@@ -106,8 +103,8 @@ describe('Artifacts App Store Actions', () => {
mock.onGet(`${TEST_HOST}/endpoint.json`).reply(500);
});
- it('dispatches requestArtifacts and receiveArtifactsError ', (done) => {
- testAction(
+ it('dispatches requestArtifacts and receiveArtifactsError ', () => {
+ return testAction(
fetchArtifacts,
null,
mockedState,
@@ -120,45 +117,41 @@ describe('Artifacts App Store Actions', () => {
type: 'receiveArtifactsError',
},
],
- done,
);
});
});
});
describe('receiveArtifactsSuccess', () => {
- it('should commit RECEIVE_ARTIFACTS_SUCCESS mutation with 200', (done) => {
- testAction(
+ it('should commit RECEIVE_ARTIFACTS_SUCCESS mutation with 200', () => {
+ return testAction(
receiveArtifactsSuccess,
{ data: { summary: {} }, status: 200 },
mockedState,
[{ type: types.RECEIVE_ARTIFACTS_SUCCESS, payload: { summary: {} } }],
[],
- done,
);
});
- it('should not commit RECEIVE_ARTIFACTS_SUCCESS mutation with 204', (done) => {
- testAction(
+ it('should not commit RECEIVE_ARTIFACTS_SUCCESS mutation with 204', () => {
+ return testAction(
receiveArtifactsSuccess,
{ data: { summary: {} }, status: 204 },
mockedState,
[],
[],
- done,
);
});
});
describe('receiveArtifactsError', () => {
- it('should commit RECEIVE_ARTIFACTS_ERROR mutation', (done) => {
- testAction(
+ it('should commit RECEIVE_ARTIFACTS_ERROR mutation', () => {
+ return testAction(
receiveArtifactsError,
null,
mockedState,
[{ type: types.RECEIVE_ARTIFACTS_ERROR }],
[],
- done,
);
});
});
diff --git a/spec/frontend/vue_mr_widget/test_extensions.js b/spec/frontend/vue_mr_widget/test_extensions.js
index 986c1d6545a..6344636873f 100644
--- a/spec/frontend/vue_mr_widget/test_extensions.js
+++ b/spec/frontend/vue_mr_widget/test_extensions.js
@@ -1,6 +1,6 @@
import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants';
-export const workingExtension = {
+export const workingExtension = (shouldCollapse = true) => ({
name: 'WidgetTestExtension',
props: ['targetProjectFullPath'],
expandEvent: 'test_expand_event',
@@ -11,6 +11,9 @@ export const workingExtension = {
statusIcon({ count }) {
return count > 0 ? EXTENSION_ICONS.warning : EXTENSION_ICONS.success;
},
+ shouldCollapse() {
+ return shouldCollapse;
+ },
},
methods: {
fetchCollapsedData({ targetProjectFullPath }) {
@@ -36,7 +39,7 @@ export const workingExtension = {
]);
},
},
-};
+});
export const collapsedDataErrorExtension = {
name: 'WidgetTestCollapsedErrorExtension',
@@ -99,7 +102,7 @@ export const fullDataErrorExtension = {
};
export const pollingExtension = {
- ...workingExtension,
+ ...workingExtension(),
enablePolling: true,
};