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/widget')
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js37
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js129
4 files changed, 151 insertions, 25 deletions
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
index 08424077269..e9a34453930 100644
--- 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
@@ -1,13 +1,13 @@
// 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\\">
+"<content-row-stub level=\\"2\\" statusiconname=\\"success\\" widgetname=\\"MyWidget\\" header=\\"This is a header,This is a subheader\\" helppopover=\\"[object Object]\\" actionbuttons=\\"\\">
<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\\">
+ <gl-badge-stub size=\\"md\\" variant=\\"info\\" iconsize=\\"md\\">
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>
@@ -15,7 +15,7 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render
</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\\">
+ <content-row-stub level=\\"3\\" statusiconname=\\"\\" widgetname=\\"MyWidget\\" header=\\"Child row header\\" actionbuttons=\\"\\" 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>
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
index b7753a58747..527e800ddcf 100644
--- 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
@@ -25,6 +25,10 @@ describe('~/vue_merge_request_widget/components/widget/dynamic_content.vue', ()
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',
+ helpPopover: {
+ options: { title: 'Widget help popover title' },
+ content: { text: 'Widget help popover content' },
+ },
icon: {
name: EXTENSION_ICONS.success,
},
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
index 9eddd091ad0..e4bee6b8652 100644
--- 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
@@ -1,11 +1,15 @@
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';
+import ActionButtons from '~/vue_merge_request_widget/components/action_buttons.vue';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue', () => {
let wrapper;
const findStatusIcon = () => wrapper.findComponent(StatusIcon);
+ const findHelpPopover = () => wrapper.findComponent(HelpPopover);
+ const findActionButtons = () => wrapper.findComponent(ActionButtons);
const createComponent = ({ propsData, slots } = {}) => {
wrapper = shallowMountExtended(WidgetContentRow, {
@@ -61,5 +65,38 @@ describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue',
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);
});
+
+ it('renders a help popover', () => {
+ createComponent({
+ propsData: {
+ helpPopover: {
+ options: { title: 'Help popover title' },
+ content: { text: 'Help popover content', learnMorePath: '/path/to/docs' },
+ },
+ },
+ });
+
+ expect(findHelpPopover().props('options')).toEqual({ title: 'Help popover title' });
+ expect(wrapper.findByText('Help popover content').exists()).toBe(true);
+ expect(wrapper.findByText('Learn more').attributes('href')).toBe('/path/to/docs');
+ expect(wrapper.findByText('Learn more').attributes('target')).toBe('_blank');
+ });
+
+ it('does not render help popover when it is not provided', () => {
+ createComponent({});
+ expect(findHelpPopover().exists()).toBe(false);
+ });
+
+ it('does not display action buttons if actionButtons is not provided', () => {
+ createComponent({});
+ expect(findActionButtons().exists()).toBe(false);
+ });
+
+ it('does display action buttons if actionButtons is provided', () => {
+ const actionButtons = [{ text: 'click-me', href: '#' }];
+
+ createComponent({ propsData: { actionButtons } });
+ expect(findActionButtons().props('tertiaryButtons')).toEqual(actionButtons);
+ });
});
});
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 4826fecf98d..9635e050e4d 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
@@ -1,12 +1,21 @@
import { nextTick } from 'vue';
import * as Sentry from '@sentry/browser';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
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';
+jest.mock('~/vue_merge_request_widget/components/extensions/telemetry', () => ({
+ createTelemetryHub: jest.fn().mockReturnValue({
+ viewed: jest.fn(),
+ expanded: jest.fn(),
+ fullReportClicked: jest.fn(),
+ }),
+}));
+
describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
let wrapper;
@@ -14,13 +23,15 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
const findExpandedSection = () => wrapper.findByTestId('widget-extension-collapsed-section');
const findActionButtons = () => wrapper.findComponent(ActionButtons);
const findToggleButton = () => wrapper.findByTestId('toggle-button');
+ const findHelpPopover = () => wrapper.findComponent(HelpPopover);
const createComponent = ({ propsData, slots } = {}) => {
wrapper = shallowMountExtended(Widget, {
propsData: {
isCollapsible: false,
loadingText: 'Loading widget',
- widgetName: 'MyWidget',
+ widgetName: 'WidgetTest',
+ fetchCollapsedData: () => Promise.resolve([]),
value: {
collapsed: null,
expanded: null,
@@ -30,6 +41,7 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
slots,
stubs: {
StatusIcon,
+ ActionButtons,
ContentRow: WidgetContentRow,
},
});
@@ -52,8 +64,9 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
it('sets the error text when fetch method fails', async () => {
- const fetchCollapsedData = jest.fn().mockReturnValue(() => Promise.reject());
- createComponent({ propsData: { fetchCollapsedData } });
+ createComponent({
+ propsData: { fetchCollapsedData: jest.fn().mockRejectedValue('Something went wrong') },
+ });
await waitForPromises();
expect(wrapper.findByText('Failed to load').exists()).toBe(true);
expect(findStatusIcon().props()).toMatchObject({ iconName: 'failed', isLoading: false });
@@ -79,12 +92,24 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
it('displays the loading text', async () => {
- const fetchCollapsedData = jest.fn().mockReturnValue(() => Promise.reject());
- createComponent({ propsData: { fetchCollapsedData, statusIconName: 'warning' } });
+ createComponent({
+ propsData: {
+ statusIconName: 'warning',
+ },
+ });
+
expect(wrapper.text()).not.toContain('Loading');
await nextTick();
expect(wrapper.text()).toContain('Loading');
});
+
+ it('validates widget name', () => {
+ expect(() => {
+ createComponent({
+ propsData: { widgetName: 'InvalidWidgetName' },
+ });
+ }).toThrow();
+ });
});
describe('fetch', () => {
@@ -136,7 +161,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
summary: 'Hello world',
- fetchCollapsedData: () => Promise.resolve(),
},
});
@@ -145,28 +169,22 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
it.todo('displays content property when content slot is not provided');
- it('displays the summary slot when provided', () => {
+ it('displays the summary slot when provided', async () => {
createComponent({
- propsData: {
- fetchCollapsedData: () => Promise.resolve(),
- },
slots: {
summary: '<b>More complex summary</b>',
},
});
+ await waitForPromises();
+
expect(wrapper.findByTestId('widget-extension-top-level-summary').text()).toBe(
'More complex summary',
);
});
it('does not display action buttons if actionButtons is not provided', () => {
- createComponent({
- propsData: {
- fetchCollapsedData: () => Promise.resolve(),
- },
- });
-
+ createComponent();
expect(findActionButtons().exists()).toBe(false);
});
@@ -175,7 +193,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
- fetchCollapsedData: () => Promise.resolve(),
actionButtons,
},
});
@@ -184,12 +201,34 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
});
+ describe('help popover', () => {
+ it('renders a help popover', () => {
+ createComponent({
+ propsData: {
+ helpPopover: {
+ options: { title: 'My help popover title' },
+ content: { text: 'Help popover content', learnMorePath: '/path/to/docs' },
+ },
+ },
+ });
+
+ expect(findHelpPopover().props('options')).toEqual({ title: 'My help popover title' });
+ expect(wrapper.findByText('Help popover content').exists()).toBe(true);
+ expect(wrapper.findByText('Learn more').attributes('href')).toBe('/path/to/docs');
+ expect(wrapper.findByText('Learn more').attributes('target')).toBe('_blank');
+ });
+
+ it('does not render help popover when it is not provided', () => {
+ createComponent();
+ expect(findHelpPopover().exists()).toBe(false);
+ });
+ });
+
describe('handle collapse toggle', () => {
it('displays the toggle button correctly', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve(),
},
slots: {
content: '<b>More complex content</b>',
@@ -204,7 +243,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve(),
},
slots: {
content: '<b>More complex content</b>',
@@ -221,7 +259,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: false,
- fetchCollapsedData: () => Promise.resolve(),
},
});
@@ -278,7 +315,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve([]),
fetchExpandedData,
},
});
@@ -306,7 +342,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve([]),
fetchExpandedData,
},
});
@@ -323,4 +358,54 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
expect(wrapper.findByText('Failed to load').exists()).toBe(false);
});
});
+
+ describe('telemetry - enabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ actionButtons: [
+ {
+ fullReport: true,
+ href: '#',
+ target: '_blank',
+ id: 'full-report-button',
+ text: 'Full Report',
+ },
+ ],
+ },
+ });
+ });
+
+ it('should call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).not.toBe(null);
+ });
+
+ it('should call the viewed state', async () => {
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.viewed).toHaveBeenCalledTimes(1);
+ });
+
+ it('when full report is clicked it should call the respective telemetry event', async () => {
+ expect(wrapper.vm.telemetryHub.fullReportClicked).not.toHaveBeenCalled();
+ wrapper.findByText('Full Report').vm.$emit('click');
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.fullReportClicked).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('telemetry - disabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ telemetry: false,
+ },
+ });
+ });
+
+ it('should not call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).toBe(null);
+ });
+ });
});