Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_merge_request_widget/components')
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js14
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_expandable_section_spec.js6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js12
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap10
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js222
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js21
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js77
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/terraform/mr_widget_terraform_container_spec.js175
-rw-r--r--spec/frontend/vue_merge_request_widget/components/terraform/terraform_plan_spec.js93
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap35
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js52
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js65
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_content_section_spec.js39
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js7
26 files changed, 400 insertions, 468 deletions
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
index 05cd1bb5b3d..1f3b6dce620 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
@@ -1,7 +1,7 @@
import { nextTick } from 'vue';
import { GlButton, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Approvals from '~/vue_merge_request_widget/components/approvals/approvals.vue';
import ApprovalsSummary from '~/vue_merge_request_widget/components/approvals/approvals_summary.vue';
import ApprovalsSummaryOptional from '~/vue_merge_request_widget/components/approvals/approvals_summary_optional.vue';
@@ -49,7 +49,7 @@ describe('MRWidget approvals', () => {
});
};
- const findAction = () => wrapper.find(GlButton);
+ const findAction = () => wrapper.findComponent(GlButton);
const findActionData = () => {
const action = findAction();
@@ -61,8 +61,8 @@ describe('MRWidget approvals', () => {
text: action.text(),
};
};
- const findSummary = () => wrapper.find(ApprovalsSummary);
- const findOptionalSummary = () => wrapper.find(ApprovalsSummaryOptional);
+ const findSummary = () => wrapper.findComponent(ApprovalsSummary);
+ const findOptionalSummary = () => wrapper.findComponent(ApprovalsSummaryOptional);
const findInvalidRules = () => wrapper.find('[data-testid="invalid-rules"]');
beforeEach(() => {
@@ -129,7 +129,7 @@ describe('MRWidget approvals', () => {
});
it('flashes error', () => {
- expect(createFlash).toHaveBeenCalledWith({ message: FETCH_ERROR });
+ expect(createAlert).toHaveBeenCalledWith({ message: FETCH_ERROR });
});
});
@@ -268,7 +268,7 @@ describe('MRWidget approvals', () => {
});
it('flashes error message', () => {
- expect(createFlash).toHaveBeenCalledWith({ message: APPROVE_ERROR });
+ expect(createAlert).toHaveBeenCalledWith({ message: APPROVE_ERROR });
});
});
});
@@ -319,7 +319,7 @@ describe('MRWidget approvals', () => {
});
it('flashes error message', () => {
- expect(createFlash).toHaveBeenCalledWith({ message: UNAPPROVE_ERROR });
+ expect(createAlert).toHaveBeenCalledWith({ message: UNAPPROVE_ERROR });
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
index 65cafc647e0..e6fb0495947 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
@@ -18,7 +18,7 @@ describe('MRWidget approvals summary optional', () => {
wrapper = null;
});
- const findHelpLink = () => wrapper.find(GlLink);
+ const findHelpLink = () => wrapper.findComponent(GlLink);
describe('when can approve', () => {
beforeEach(() => {
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
index c2606346292..f4234083346 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
@@ -29,7 +29,7 @@ describe('MRWidget approvals summary', () => {
});
};
- const findAvatars = () => wrapper.find(UserAvatarList);
+ const findAvatars = () => wrapper.findComponent(UserAvatarList);
afterEach(() => {
wrapper.destroy();
@@ -136,7 +136,7 @@ describe('MRWidget approvals summary', () => {
});
it('does not render avatar list', () => {
- expect(wrapper.find(UserAvatarList).exists()).toBe(false);
+ expect(wrapper.findComponent(UserAvatarList).exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
index e2386bc7f2b..73fa4b7b08f 100644
--- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
@@ -60,7 +60,7 @@ describe('Merge Requests Artifacts list app', () => {
});
it('renders a loading icon', () => {
- const loadingIcon = wrapper.find(GlLoadingIcon);
+ const loadingIcon = wrapper.findComponent(GlLoadingIcon);
expect(loadingIcon.exists()).toBe(true);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
index d519ad2cdb0..b7bf72cd215 100644
--- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
@@ -31,11 +31,11 @@ describe('Artifacts List', () => {
});
it('renders link for the artifact', () => {
- expect(wrapper.find(GlLink).attributes('href')).toEqual(data.artifacts[0].url);
+ expect(wrapper.findComponent(GlLink).attributes('href')).toEqual(data.artifacts[0].url);
});
it('renders artifact name', () => {
- expect(wrapper.find(GlLink).text()).toEqual(data.artifacts[0].text);
+ expect(wrapper.findComponent(GlLink).text()).toEqual(data.artifacts[0].text);
});
it('renders job url', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
index 01fbcb2154f..c253dc63f23 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
@@ -23,7 +23,7 @@ describe('Merge Request Collapsible Extension', () => {
const findTitle = () => wrapper.find('[data-testid="mr-collapsible-title"]');
const findErrorMessage = () => wrapper.find('.js-error-state');
- const findIcon = () => wrapper.find(GlIcon);
+ const findIcon = () => wrapper.findComponent(GlIcon);
afterEach(() => {
wrapper.destroy();
@@ -77,7 +77,7 @@ describe('Merge Request Collapsible Extension', () => {
});
it('renders loading spinner', () => {
- expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).isVisible()).toBe(true);
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
index 8fd93809e01..90a29d15488 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
@@ -32,7 +32,9 @@ describe('MrWidgetAuthorTime', () => {
});
it('renders author', () => {
- expect(wrapper.find(MrWidgetAuthor).props('author')).toStrictEqual(defaultProps.author);
+ expect(wrapper.findComponent(MrWidgetAuthor).props('author')).toStrictEqual(
+ defaultProps.author,
+ );
});
it('renders provided time', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_expandable_section_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_expandable_section_spec.js
index 631aef412a6..8eaed998eb5 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_expandable_section_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_expandable_section_spec.js
@@ -6,8 +6,8 @@ import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_widge
describe('MrWidgetExpanableSection', () => {
let wrapper;
- const findButton = () => wrapper.find(GlButton);
- const findCollapse = () => wrapper.find(GlCollapse);
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findCollapse = () => wrapper.findComponent(GlCollapse);
beforeEach(() => {
wrapper = shallowMount(MrCollapsibleSection, {
@@ -19,7 +19,7 @@ describe('MrWidgetExpanableSection', () => {
});
it('renders Icon', () => {
- expect(wrapper.find(GlIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlIcon).exists()).toBe(true);
});
it('renders header slot', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
index ebd10f31fa7..6a9b019fb4f 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
@@ -21,6 +21,6 @@ describe('MrWidgetIcon', () => {
it('renders icon and container', () => {
expect(wrapper.element.className).toContain('circle-icon-container');
- expect(wrapper.find(GlIcon).props('name')).toEqual(TEST_ICON);
+ expect(wrapper.findComponent(GlIcon).props('name')).toEqual(TEST_ICON);
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
index efe2bf75c3f..c3f6331e560 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
@@ -41,8 +41,8 @@ describe('MrWidgetPipelineContainer', () => {
});
it('renders pipeline', () => {
- expect(wrapper.find(MrWidgetPipeline).exists()).toBe(true);
- expect(wrapper.find(MrWidgetPipeline).props()).toMatchObject({
+ expect(wrapper.findComponent(MrWidgetPipeline).exists()).toBe(true);
+ expect(wrapper.findComponent(MrWidgetPipeline).props()).toMatchObject({
pipeline: mockStore.pipeline,
pipelineCoverageDelta: mockStore.pipelineCoverageDelta,
ciStatus: mockStore.ciStatus,
@@ -82,9 +82,9 @@ describe('MrWidgetPipelineContainer', () => {
});
it('renders pipeline', () => {
- expect(wrapper.find(MrWidgetPipeline).exists()).toBe(true);
+ expect(wrapper.findComponent(MrWidgetPipeline).exists()).toBe(true);
expect(findCIErrorMessage().exists()).toBe(false);
- expect(wrapper.find(MrWidgetPipeline).props()).toMatchObject({
+ expect(wrapper.findComponent(MrWidgetPipeline).props()).toMatchObject({
pipeline: mockStore.mergePipeline,
pipelineCoverageDelta: mockStore.pipelineCoverageDelta,
ciStatus: mockStore.mergePipeline.details.status.text,
@@ -102,7 +102,7 @@ describe('MrWidgetPipelineContainer', () => {
targetBranch: 'Foo<script>alert("XSS")</script>',
},
});
- expect(wrapper.find(MrWidgetPipeline).props().sourceBranchLink).toBe('Foo');
+ expect(wrapper.findComponent(MrWidgetPipeline).props().sourceBranchLink).toBe('Foo');
});
it('renders deployments', () => {
@@ -125,7 +125,7 @@ describe('MrWidgetPipelineContainer', () => {
it('renders the artifacts app', () => {
factory();
- expect(wrapper.find(ArtifactsApp).isVisible()).toBe(true);
+ expect(wrapper.findComponent(ArtifactsApp).isVisible()).toBe(true);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
index d6c67dab381..73358edee78 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
@@ -57,7 +57,7 @@ describe('MRWidgetSuggestPipeline', () => {
});
it('renders widget icon', () => {
- const icon = wrapper.find(MrWidgetIcon);
+ const icon = wrapper.findComponent(MrWidgetIcon);
expect(icon.exists()).toBe(true);
expect(icon.props()).toEqual(
@@ -115,7 +115,7 @@ describe('MRWidgetSuggestPipeline', () => {
});
describe('dismissible', () => {
- const findDismissContainer = () => wrapper.find(dismissibleContainer);
+ const findDismissContainer = () => wrapper.findComponent(dismissibleContainer);
beforeEach(() => {
wrapper = shallowMount(suggestPipelineComponent, { propsData: suggestProps });
diff --git a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
index 635ef0f6b0d..5f383c468d8 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
+++ b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
@@ -72,11 +72,14 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have
<div
class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
>
- <div>
+ <div
+ class="gl-display-flex gl-align-items-flex-start"
+ >
<div
class="dropdown b-dropdown gl-new-dropdown gl-display-block gl-md-display-none! btn-group"
lazy=""
no-caret=""
+ title="Options"
>
<!---->
<button
@@ -246,11 +249,14 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c
<div
class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
>
- <div>
+ <div
+ class="gl-display-flex gl-align-items-flex-start"
+ >
<div
class="dropdown b-dropdown gl-new-dropdown gl-display-block gl-md-display-none! btn-group"
lazy=""
no-caret=""
+ title="Options"
>
<!---->
<button
diff --git a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
index 1900b53ac11..d85574262fe 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
@@ -15,9 +15,9 @@ describe('Merge request widget merge checks failed state component', () => {
});
it.each`
- mrState | displayText
- ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
- ${{ blockingMergeRequests: { total_count: 1 } }} | ${'blockingMergeRequests'}
+ mrState | displayText
+ ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
+ ${{ detailedMergeStatus: 'BLOCKED_STATUS' }} | ${'blockingMergeRequests'}
`('display $displayText text for $mrState', ({ mrState, displayText }) => {
factory({ mr: mrState });
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
index 9320e733636..398a3912882 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
@@ -7,7 +7,7 @@ import eventHub from '~/vue_merge_request_widget/event_hub';
describe('MRWidgetAutoMergeFailed', () => {
let wrapper;
const mergeError = 'This is the merge error';
- const findButton = () => wrapper.find(GlButton);
+ const findButton = () => wrapper.findComponent(GlButton);
const createComponent = (props = {}, mergeRequestWidgetGraphql = false) => {
wrapper = mount(AutoMergeFailedComponent, {
@@ -61,7 +61,7 @@ describe('MRWidgetAutoMergeFailed', () => {
await nextTick();
expect(findButton().attributes('disabled')).toBe('disabled');
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
index 2606933450e..a3aa563b516 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
@@ -1,180 +1,172 @@
import { getByRole } from '@testing-library/dom';
-import Vue from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
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';
+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;
+ let wrapper;
const targetBranch = 'foo';
-
- beforeEach(() => {
- jest.spyOn(document, 'dispatchEvent');
- 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',
+ 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 UTC',
+ readableMergedAt: '',
+ closedBy: {},
+ closedAt: 'Jan 24, 2018 1:02pm UTC',
+ readableClosedAt: '',
+ },
+ updatedAt: 'mergedUpdatedAt',
+ shortMergeCommitSha: '958c0475',
+ mergeCommitSha: '958c047516e182dfc52317f721f696e8a1ee85ed',
+ mergeCommitPath:
+ 'http://localhost:3000/root/nautilus/commit/f7ce827c314c9340b075657fd61c789fb01cf74d',
+ sourceBranch: 'bar',
+ targetBranch,
+ };
+
+ const service = {
+ removeSourceBranch: () => nextTick(),
+ };
+
+ const createComponent = (customMrFields = {}) => {
+ wrapper = mount(MergedComponent, {
+ propsData: {
+ mr: {
+ ...mr,
+ ...customMrFields,
},
- mergedAt: 'Jan 24, 2018 1:02pm UTC',
- readableMergedAt: '',
- closedBy: {},
- closedAt: 'Jan 24, 2018 1:02pm UTC',
- readableClosedAt: '',
+ service,
},
- updatedAt: 'mergedUpdatedAt',
- shortMergeCommitSha: '958c0475',
- mergeCommitSha: '958c047516e182dfc52317f721f696e8a1ee85ed',
- mergeCommitPath:
- 'http://localhost:3000/root/nautilus/commit/f7ce827c314c9340b075657fd61c789fb01cf74d',
- sourceBranch: 'bar',
- targetBranch,
- };
-
- const service = {
- removeSourceBranch() {},
- };
+ });
+ };
+ beforeEach(() => {
+ jest.spyOn(document, 'dispatchEvent');
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
- vm = mountComponent(Component, { mr, service });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.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);
- });
+ const findButtonByText = (text) =>
+ wrapper.findAll('button').wrappers.find((w) => w.text() === text);
+ const findRemoveSourceBranchButton = () => findButtonByText('Delete source branch');
- it('returns true when all are true', () => {
- vm.mr.isRemovingSourceBranch = true;
- vm.mr.canRemoveSourceBranch = true;
- vm.isMakingRequest = true;
+ describe('remove source branch button', () => {
+ it('is displayed when sourceBranchRemoved is false', () => {
+ createComponent({ sourceBranchRemoved: false });
- expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
- });
+ expect(findRemoveSourceBranchButton().exists()).toBe(true);
});
- describe('shouldShowSourceBranchRemoving', () => {
- it('should correct value when fields changed', () => {
- vm.mr.sourceBranchRemoved = false;
+ it('is not displayed when sourceBranchRemoved is true', () => {
+ createComponent({ sourceBranchRemoved: true });
- expect(vm.shouldShowSourceBranchRemoving).toEqual(false);
+ expect(findRemoveSourceBranchButton()).toBe(undefined);
+ });
- vm.mr.sourceBranchRemoved = true;
+ it('is not displayed when canRemoveSourceBranch is true', () => {
+ createComponent({ sourceBranchRemoved: false, canRemoveSourceBranch: false });
- expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
+ expect(findRemoveSourceBranchButton()).toBe(undefined);
+ });
- vm.mr.sourceBranchRemoved = false;
- vm.isMakingRequest = true;
+ it('is not displayed when is making request', async () => {
+ createComponent({ sourceBranchRemoved: false, canRemoveSourceBranch: true });
- expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
+ await findRemoveSourceBranchButton().trigger('click');
- vm.isMakingRequest = false;
- vm.mr.isRemovingSourceBranch = true;
+ expect(findRemoveSourceBranchButton()).toBe(undefined);
+ });
- expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
+ it('is not displayed when all are true', () => {
+ createComponent({
+ isRemovingSourceBranch: true,
+ sourceBranchRemoved: false,
+ canRemoveSourceBranch: true,
});
+
+ expect(findRemoveSourceBranchButton()).toBe(undefined);
});
});
- describe('methods', () => {
- describe('removeSourceBranch', () => {
- 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({
- data: {
- message: 'Branch was deleted',
- },
- });
- }),
- );
+ it('should set flag and call service then request main component to update the widget when branch is removed', async () => {
+ createComponent({ sourceBranchRemoved: false });
+ jest.spyOn(service, 'removeSourceBranch').mockResolvedValue({
+ data: {
+ message: 'Branch was deleted',
+ },
+ });
- vm.removeSourceBranch();
+ await findRemoveSourceBranchButton().trigger('click');
- await waitForPromises();
+ await waitForPromises();
- const args = eventHub.$emit.mock.calls[0];
+ const args = eventHub.$emit.mock.calls[0];
- expect(vm.isMakingRequest).toEqual(true);
- expect(args[0]).toEqual('MRWidgetUpdateRequested');
- expect(args[1]).not.toThrow();
- });
- });
+ expect(args[0]).toEqual('MRWidgetUpdateRequested');
+ expect(args[1]).not.toThrow();
});
it('calls dispatchDocumentEvent to load in the modal component', () => {
+ createComponent();
+
expect(document.dispatchEvent).toHaveBeenCalledWith(new CustomEvent('merged:UpdateActions'));
});
it('emits event to open the revert modal on revert button click', () => {
+ createComponent();
const eventHubSpy = jest.spyOn(modalEventHub, '$emit');
- getByRole(vm.$el, 'button', { name: /Revert/i }).click();
+ getByRole(wrapper.element, 'button', { name: /Revert/i }).click();
expect(eventHubSpy).toHaveBeenCalledWith(OPEN_REVERT_MODAL);
});
it('emits event to open the cherry-pick modal on cherry-pick button click', () => {
+ createComponent();
const eventHubSpy = jest.spyOn(modalEventHub, '$emit');
- getByRole(vm.$el, 'button', { name: /Cherry-pick/i }).click();
+ getByRole(wrapper.element, 'button', { name: /Cherry-pick/i }).click();
expect(eventHubSpy).toHaveBeenCalledWith(OPEN_CHERRY_PICK_MODAL);
});
it('has merged by information', () => {
- expect(vm.$el.textContent).toContain('Merged by');
- expect(vm.$el.textContent).toContain('Administrator');
+ createComponent();
+
+ expect(wrapper.text()).toContain('Merged by');
+ expect(wrapper.text()).toContain('Administrator');
});
it('shows revert and cherry-pick buttons', () => {
- expect(vm.$el.textContent).toContain('Revert');
- expect(vm.$el.textContent).toContain('Cherry-pick');
+ createComponent();
+
+ expect(wrapper.text()).toContain('Revert');
+ expect(wrapper.text()).toContain('Cherry-pick');
});
it('should use mergedEvent mergedAt as tooltip title', () => {
- expect(vm.$el.querySelector('time').getAttribute('title')).toBe('Jan 24, 2018 1:02pm UTC');
+ createComponent();
+
+ expect(wrapper.find('time').attributes('title')).toBe('Jan 24, 2018 1:02pm UTC');
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
index d5619d4996d..bd158d59d74 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
@@ -6,31 +6,42 @@ import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_i
describe('PipelineFailed', () => {
let wrapper;
- const createComponent = () => {
+ const createComponent = (mr = {}) => {
wrapper = shallowMount(PipelineFailed, {
+ propsData: {
+ mr,
+ },
stubs: {
GlSprintf,
},
});
};
- beforeEach(() => {
- createComponent();
- });
-
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render error status icon', () => {
+ createComponent();
+
expect(wrapper.findComponent(StatusIcon).exists()).toBe(true);
expect(wrapper.findComponent(StatusIcon).props().status).toBe('failed');
});
it('should render error message with a disabled merge button', () => {
+ createComponent();
+
expect(wrapper.text()).toContain('Merge blocked: pipeline must succeed.');
expect(wrapper.text()).toContain('Push a commit that fixes the failure');
expect(wrapper.findComponent(GlLink).text()).toContain('learn about other solutions');
});
+
+ it('should render pipeline blocked message', () => {
+ createComponent({ isPipelineBlocked: true });
+
+ expect(wrapper.text()).toContain(
+ "Merge blocked: pipeline must succeed. It's waiting for a manual action to continue.",
+ );
+ });
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
index 9a6bf66909e..48d3f15560b 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -105,16 +105,17 @@ const createComponent = (
},
stubs: {
CommitEdit,
+ GlSprintf,
},
apolloProvider: createMockApollo([[readyToMergeQuery, readyToMergeResponseSpy]]),
});
};
-const findCheckboxElement = () => wrapper.find(SquashBeforeMerge);
+const findCheckboxElement = () => wrapper.findComponent(SquashBeforeMerge);
const findCommitEditElements = () => wrapper.findAllComponents(CommitEdit);
-const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown);
+const findCommitDropdownElement = () => wrapper.findComponent(CommitMessageDropdown);
const findFirstCommitEditLabel = () => findCommitEditElements().at(0).props('label');
-const findTipLink = () => wrapper.find(GlSprintf);
+const findTipLink = () => wrapper.findComponent(GlSprintf);
const findCommitEditWithInputId = (inputId) =>
findCommitEditElements().wrappers.find((x) => x.props('inputId') === inputId);
const findMergeCommitMessage = () => findCommitEditWithInputId('merge-message-edit').props('value');
@@ -300,6 +301,48 @@ describe('ReadyToMerge', () => {
expect(wrapper.vm.isMergeButtonDisabled).toBe(true);
});
});
+
+ describe('sourceBranchDeletedText', () => {
+ const should = 'Source branch will be deleted.';
+ const shouldNot = 'Source branch will not be deleted.';
+ const did = 'Deleted the source branch.';
+ const didNot = 'Did not delete the source branch.';
+ const scenarios = [
+ "the MR hasn't merged yet, and the backend-provided value expects to delete the branch",
+ "the MR hasn't merged yet, and the backend-provided value expects to leave the branch",
+ "the MR hasn't merged yet, and the backend-provided value is a non-boolean falsey value",
+ "the MR hasn't merged yet, and the backend-provided value is a non-boolean truthy value",
+ 'the MR has been merged, and the backend reports that the branch has been removed',
+ 'the MR has been merged, and the backend reports that the branch has not been removed',
+ 'the MR has been merged, and the backend reports a non-boolean falsey value',
+ 'the MR has been merged, and the backend reports a non-boolean truthy value',
+ ];
+
+ it.each`
+ describe | premerge | mrShould | mrRemoved | output
+ ${scenarios[0]} | ${true} | ${true} | ${null} | ${should}
+ ${scenarios[1]} | ${true} | ${false} | ${null} | ${shouldNot}
+ ${scenarios[2]} | ${true} | ${null} | ${null} | ${shouldNot}
+ ${scenarios[3]} | ${true} | ${'yeah'} | ${null} | ${should}
+ ${scenarios[4]} | ${false} | ${null} | ${true} | ${did}
+ ${scenarios[5]} | ${false} | ${null} | ${false} | ${didNot}
+ ${scenarios[6]} | ${false} | ${null} | ${null} | ${didNot}
+ ${scenarios[7]} | ${false} | ${null} | ${'yep'} | ${did}
+ `(
+ 'in the case that $describe, returns "$output"',
+ ({ premerge, mrShould, mrRemoved, output }) => {
+ createComponent({
+ mr: {
+ state: !premerge ? 'merged' : 'literally-anything-else',
+ shouldRemoveSourceBranch: mrShould,
+ sourceBranchRemoved: mrRemoved,
+ },
+ });
+
+ expect(wrapper.vm.sourceBranchDeletedText).toBe(output);
+ },
+ );
+ });
});
describe('methods', () => {
@@ -733,6 +776,34 @@ describe('ReadyToMerge', () => {
});
});
+ describe('source and target branches diverged', () => {
+ describe('when the MR is showing the Merge button', () => {
+ it('does not display the diverged commits message if the source branch is not behind the target', () => {
+ createComponent({ mr: { divergedCommitsCount: 0 } });
+
+ const textBody = wrapper.text();
+
+ expect(textBody).toEqual(
+ expect.not.stringContaining('The source branch is 0 commits behind the target branch'),
+ );
+ expect(textBody).toEqual(
+ expect.not.stringContaining('The source branch is 0 commit behind the target branch'),
+ );
+ expect(textBody).toEqual(
+ expect.not.stringContaining('The source branch is behind the target branch'),
+ );
+ });
+
+ it('shows the diverged commits text when the source branch is behind the target', () => {
+ createComponent({ mr: { divergedCommitsCount: 9001, canMerge: false } });
+
+ expect(wrapper.text()).toEqual(
+ expect.stringContaining('The source branch is 9001 commits behind the target branch'),
+ );
+ });
+ });
+ });
+
describe('Merge button when pipeline has failed', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
index 6ea2e8675d3..c839fa17fe5 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
@@ -18,7 +18,7 @@ describe('Squash before merge component', () => {
wrapper.destroy();
});
- const findCheckbox = () => wrapper.find(GlFormCheckbox);
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
describe('checkbox', () => {
it('is unchecked if passed value prop is false', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
index af52901f508..7259f210b6e 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
@@ -38,7 +38,7 @@ describe('Wip', () => {
it('should have default data', () => {
const vm = createComponent();
- expect(vm.isMakingRequest).toBeFalsy();
+ expect(vm.isMakingRequest).toBe(false);
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/terraform/mr_widget_terraform_container_spec.js b/spec/frontend/vue_merge_request_widget/components/terraform/mr_widget_terraform_container_spec.js
deleted file mode 100644
index 7a868eb8cc9..00000000000
--- a/spec/frontend/vue_merge_request_widget/components/terraform/mr_widget_terraform_container_spec.js
+++ /dev/null
@@ -1,175 +0,0 @@
-import { GlSkeletonLoader, 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';
-import MrWidgetTerraformContainer from '~/vue_merge_request_widget/components/terraform/mr_widget_terraform_container.vue';
-import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue';
-import { invalidPlanWithName, plans, validPlanWithName } from './mock_data';
-
-describe('MrWidgetTerraformConainer', () => {
- let mock;
- let wrapper;
-
- const propsData = { endpoint: '/path/to/terraform/report.json' };
-
- const findHeader = () => wrapper.find('[data-testid="terraform-header-text"]');
- const findPlans = () =>
- wrapper.findAllComponents(TerraformPlan).wrappers.map((x) => x.props('plan'));
-
- const mockPollingApi = (response, body, header) => {
- mock.onGet(propsData.endpoint).reply(response, body, header);
- };
-
- const mountWrapper = () => {
- wrapper = shallowMount(MrWidgetTerraformContainer, {
- propsData,
- stubs: { MrWidgetExpanableSection, GlSprintf },
- });
- return axios.waitForAll();
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- wrapper.destroy();
- mock.restore();
- });
-
- describe('when data is loading', () => {
- beforeEach(async () => {
- mockPollingApi(200, plans, {});
-
- 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', () => {
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
- expect(wrapper.find(MrWidgetExpanableSection).exists()).toBe(false);
- });
- });
-
- describe('when data has finished loading', () => {
- beforeEach(() => {
- mockPollingApi(200, plans, {});
- return mountWrapper();
- });
-
- it('displays terraform content', () => {
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false);
- expect(wrapper.find(MrWidgetExpanableSection).exists()).toBe(true);
- expect(findPlans()).toEqual(Object.values(plans));
- });
-
- describe('when data includes one invalid plan', () => {
- beforeEach(() => {
- const invalidPlanGroup = { bad_plan: invalidPlanWithName };
- mockPollingApi(200, invalidPlanGroup, {});
- return mountWrapper();
- });
-
- it('displays header text for one invalid plan', () => {
- expect(findHeader().text()).toBe('1 Terraform report failed to generate');
- });
- });
-
- describe('when data includes multiple invalid plans', () => {
- beforeEach(() => {
- const invalidPlanGroup = {
- bad_plan_one: invalidPlanWithName,
- bad_plan_two: invalidPlanWithName,
- };
-
- mockPollingApi(200, invalidPlanGroup, {});
- return mountWrapper();
- });
-
- it('displays header text for multiple invalid plans', () => {
- expect(findHeader().text()).toBe('2 Terraform reports failed to generate');
- });
- });
-
- describe('when data includes one valid plan', () => {
- beforeEach(() => {
- const validPlanGroup = { valid_plan: validPlanWithName };
- mockPollingApi(200, validPlanGroup, {});
- return mountWrapper();
- });
-
- it('displays header text for one valid plans', () => {
- expect(findHeader().text()).toBe('1 Terraform report was generated in your pipelines');
- });
- });
-
- describe('when data includes multiple valid plans', () => {
- beforeEach(() => {
- const validPlanGroup = {
- valid_plan_one: validPlanWithName,
- valid_plan_two: validPlanWithName,
- };
- mockPollingApi(200, validPlanGroup, {});
- return mountWrapper();
- });
-
- it('displays header text for multiple valid plans', () => {
- expect(findHeader().text()).toBe('2 Terraform reports were generated in your pipelines');
- });
- });
- });
-
- describe('polling', () => {
- let pollRequest;
- let pollStop;
-
- beforeEach(() => {
- pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
- pollStop = jest.spyOn(Poll.prototype, 'stop');
- });
-
- afterEach(() => {
- pollRequest.mockRestore();
- pollStop.mockRestore();
- });
-
- describe('successful poll', () => {
- beforeEach(() => {
- mockPollingApi(200, plans, {});
-
- return mountWrapper();
- });
-
- it('does not make additional requests after poll is successful', () => {
- expect(pollRequest).toHaveBeenCalledTimes(1);
- expect(pollStop).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('polling fails', () => {
- beforeEach(() => {
- mockPollingApi(500, null, {});
- return mountWrapper();
- });
-
- it('stops loading', () => {
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false);
- });
-
- it('generates one broken plan', () => {
- expect(findPlans()).toEqual([{ tf_report_error: 'api_error' }]);
- });
-
- it('does not make additional requests after poll is unsuccessful', () => {
- expect(pollRequest).toHaveBeenCalledTimes(1);
- expect(pollStop).toHaveBeenCalledTimes(1);
- });
- });
- });
-});
diff --git a/spec/frontend/vue_merge_request_widget/components/terraform/terraform_plan_spec.js b/spec/frontend/vue_merge_request_widget/components/terraform/terraform_plan_spec.js
deleted file mode 100644
index 3c9f6c2e165..00000000000
--- a/spec/frontend/vue_merge_request_widget/components/terraform/terraform_plan_spec.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import { GlLink, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue';
-import {
- invalidPlanWithName,
- invalidPlanWithoutName,
- validPlanWithName,
- validPlanWithoutName,
-} from './mock_data';
-
-describe('TerraformPlan', () => {
- let wrapper;
-
- const findIcon = () => wrapper.find('[data-testid="change-type-icon"]');
- const findLogButton = () => wrapper.find('[data-testid="terraform-report-link"]');
-
- const mountWrapper = (propsData) => {
- wrapper = shallowMount(TerraformPlan, { stubs: { GlLink, GlSprintf }, propsData });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('valid plan with job_name', () => {
- beforeEach(() => {
- mountWrapper({ plan: validPlanWithName });
- });
-
- it('displays a document icon', () => {
- expect(findIcon().attributes('name')).toBe('doc-changes');
- });
-
- it('diplays the header text with a name', () => {
- expect(wrapper.text()).toContain(`The job ${validPlanWithName.job_name} generated a report.`);
- });
-
- it('diplays the reported changes', () => {
- expect(wrapper.text()).toContain(
- `Reported Resource Changes: ${validPlanWithName.create} to add, ${validPlanWithName.update} to change, ${validPlanWithName.delete} to delete`,
- );
- });
-
- it('renders button when url is found', () => {
- expect(findLogButton().exists()).toBe(true);
- expect(findLogButton().text()).toEqual('View full log');
- });
- });
-
- describe('valid plan without job_name', () => {
- beforeEach(() => {
- mountWrapper({ plan: validPlanWithoutName });
- });
-
- it('diplays the header text without a name', () => {
- expect(wrapper.text()).toContain('A report was generated in your pipelines.');
- });
- });
-
- describe('invalid plan with job_name', () => {
- beforeEach(() => {
- mountWrapper({ plan: invalidPlanWithName });
- });
-
- it('displays a warning icon', () => {
- expect(findIcon().attributes('name')).toBe('warning');
- });
-
- it('diplays the header text with a name', () => {
- expect(wrapper.text()).toContain(
- `The job ${invalidPlanWithName.job_name} failed to generate a report.`,
- );
- });
-
- it('diplays generic error since report values are missing', () => {
- expect(wrapper.text()).toContain('Generating the report caused an error.');
- });
- });
-
- describe('invalid plan with out job_name', () => {
- beforeEach(() => {
- mountWrapper({ plan: invalidPlanWithoutName });
- });
-
- it('diplays the header text without a name', () => {
- expect(wrapper.text()).toContain('A report failed to generate.');
- });
-
- it('does not render button because url is missing', () => {
- expect(findLogButton().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
new file mode 100644
index 00000000000..08424077269
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
@@ -0,0 +1,35 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue renders given data 1`] = `
+"<content-row-stub level=\\"2\\" statusiconname=\\"success\\" widgetname=\\"MyWidget\\" header=\\"This is a header,This is a subheader\\">
+ <div class=\\"gl-display-flex gl-flex-direction-column\\">
+ <div>
+ <p class=\\"gl-mb-0\\">Main text for the row</p>
+ <gl-link-stub href=\\"https://gitlab.com\\">Optional link to display after text</gl-link-stub>
+ <!---->
+ <gl-badge-stub size=\\"md\\" variant=\\"info\\">
+ Badge is optional. Text to be displayed inside badge
+ </gl-badge-stub>
+ <actions-stub widget=\\"MyWidget\\" tertiarybuttons=\\"\\" class=\\"gl-ml-auto gl-pl-3\\"></actions-stub>
+ <p class=\\"gl-m-0 gl-font-sm\\">Optional: Smaller sub-text to be displayed below the main text</p>
+ </div>
+ <ul class=\\"gl-m-0 gl-p-0 gl-list-style-none\\">
+ <li>
+ <content-row-stub level=\\"3\\" statusiconname=\\"\\" widgetname=\\"MyWidget\\" header=\\"Child row header\\" data-qa-selector=\\"child_content\\">
+ <div class=\\"gl-display-flex gl-flex-direction-column\\">
+ <div>
+ <p class=\\"gl-mb-0\\">This is recursive. It will be listed in level 3.</p>
+ <!---->
+ <!---->
+ <!---->
+ <actions-stub widget=\\"MyWidget\\" tertiarybuttons=\\"\\" class=\\"gl-ml-auto gl-pl-3\\"></actions-stub>
+ <!---->
+ </div>
+ <!---->
+ </div>
+ </content-row-stub>
+ </li>
+ </ul>
+ </div>
+</content-row-stub>"
+`;
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js
new file mode 100644
index 00000000000..b7753a58747
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js
@@ -0,0 +1,52 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants';
+import DynamicContent from '~/vue_merge_request_widget/components/widget/dynamic_content.vue';
+
+describe('~/vue_merge_request_widget/components/widget/dynamic_content.vue', () => {
+ let wrapper;
+
+ const createComponent = ({ propsData } = {}) => {
+ wrapper = shallowMountExtended(DynamicContent, {
+ propsData: {
+ widgetName: 'MyWidget',
+ ...propsData,
+ },
+ stubs: {
+ DynamicContent,
+ },
+ });
+ };
+
+ it('renders given data', () => {
+ createComponent({
+ propsData: {
+ data: {
+ id: 'row-id',
+ header: ['This is a header', 'This is a subheader'],
+ text: 'Main text for the row',
+ subtext: 'Optional: Smaller sub-text to be displayed below the main text',
+ icon: {
+ name: EXTENSION_ICONS.success,
+ },
+ badge: {
+ text: 'Badge is optional. Text to be displayed inside badge',
+ variant: 'info',
+ },
+ link: {
+ text: 'Optional link to display after text',
+ href: 'https://gitlab.com',
+ },
+ children: [
+ {
+ id: 'row-id-2',
+ header: 'Child row header',
+ text: 'This is recursive. It will be listed in level 3.',
+ },
+ ],
+ },
+ },
+ });
+
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js
new file mode 100644
index 00000000000..9eddd091ad0
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js
@@ -0,0 +1,65 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import WidgetContentRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
+import StatusIcon from '~/vue_merge_request_widget/components/widget/status_icon.vue';
+
+describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue', () => {
+ let wrapper;
+
+ const findStatusIcon = () => wrapper.findComponent(StatusIcon);
+
+ const createComponent = ({ propsData, slots } = {}) => {
+ wrapper = shallowMountExtended(WidgetContentRow, {
+ propsData: {
+ widgetName: 'MyWidget',
+ level: 2,
+ ...propsData,
+ },
+ slots,
+ });
+ };
+
+ describe('body', () => {
+ it('renders the status icon when provided', () => {
+ createComponent({ propsData: { statusIconName: 'failed' } });
+ expect(findStatusIcon().exists()).toBe(true);
+ });
+
+ it('does not render the status icon when it is not provided', () => {
+ createComponent();
+ expect(findStatusIcon().exists()).toBe(false);
+ });
+
+ it('renders slots properly', () => {
+ createComponent({
+ propsData: {
+ statusIconName: 'success',
+ },
+ slots: {
+ header: '<span>this is a header</span>',
+ body: '<span>this is a body</span>',
+ },
+ });
+
+ expect(wrapper.findByText('this is a body').exists()).toBe(true);
+ expect(wrapper.findByText('this is a header').exists()).toBe(true);
+ });
+ });
+
+ describe('header', () => {
+ it('renders an array of header and subheader', () => {
+ createComponent({ propsData: { header: ['this is a header', 'this is a subheader'] } });
+ expect(wrapper.findByText('this is a header').exists()).toBe(true);
+ expect(wrapper.findByText('this is a subheader').exists()).toBe(true);
+ });
+
+ it('renders a string', () => {
+ createComponent({ propsData: { header: 'this is a header' } });
+ expect(wrapper.findByText('this is a header').exists()).toBe(true);
+ });
+
+ it('escapes html injection properly', () => {
+ createComponent({ propsData: { header: '<b role="header">this is a header</b>' } });
+ expect(wrapper.findByText('<b role="header">this is a header</b>').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_section_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_section_spec.js
deleted file mode 100644
index c2128d3ff33..00000000000
--- a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_section_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import WidgetContentSection from '~/vue_merge_request_widget/components/widget/widget_content_section.vue';
-import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
-
-describe('~/vue_merge_request_widget/components/widget/widget_content_section.vue', () => {
- let wrapper;
-
- const findStatusIcon = () => wrapper.findComponent(StatusIcon);
-
- const createComponent = ({ propsData, slots } = {}) => {
- wrapper = shallowMountExtended(WidgetContentSection, {
- propsData: {
- widgetName: 'MyWidget',
- ...propsData,
- },
- slots,
- });
- };
-
- it('does not render the status icon when it is not provided', () => {
- createComponent();
- expect(findStatusIcon().exists()).toBe(false);
- });
-
- it('renders the status icon when provided', () => {
- createComponent({ propsData: { statusIconName: 'failed' } });
- expect(findStatusIcon().exists()).toBe(true);
- });
-
- it('renders the default slot', () => {
- createComponent({
- slots: {
- default: 'Hello world',
- },
- });
-
- expect(wrapper.findByText('Hello world').exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
index b67b5703ad5..4826fecf98d 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
@@ -5,8 +5,9 @@ import waitForPromises from 'helpers/wait_for_promises';
import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
import ActionButtons from '~/vue_merge_request_widget/components/action_buttons.vue';
import Widget from '~/vue_merge_request_widget/components/widget/widget.vue';
+import WidgetContentRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
-describe('MR Widget', () => {
+describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
let wrapper;
const findStatusIcon = () => wrapper.findComponent(StatusIcon);
@@ -27,6 +28,10 @@ describe('MR Widget', () => {
...propsData,
},
slots,
+ stubs: {
+ StatusIcon,
+ ContentRow: WidgetContentRow,
+ },
});
};