From 7671216b60e2796a050358ff808b4a0c2de3d22f Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 24 Feb 2020 21:09:08 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../components/mr_widget_suggest_pipeline_spec.js | 55 +++++--- .../states/mr_widget_pipeline_tour_spec.js | 143 +++++++++++++++++++++ .../components/states/pipeline_tour_mock_data.js | 10 ++ 3 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_tour_spec.js create mode 100644 spec/frontend/vue_mr_widget/components/states/pipeline_tour_mock_data.js (limited to 'spec/frontend/vue_mr_widget') diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js index 77293a5b187..8b0253dc01a 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js @@ -1,16 +1,24 @@ import { mount } from '@vue/test-utils'; import { GlLink } from '@gitlab/ui'; import suggestPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue'; +import stubChildren from 'helpers/stub_children'; +import PipelineTourState from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue'; import MrWidgetIcon from '~/vue_merge_request_widget/components/mr_widget_icon.vue'; +import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper'; describe('MRWidgetHeader', () => { let wrapper; const pipelinePath = '/foo/bar/add/pipeline/path'; + const pipelineSvgPath = '/foo/bar/pipeline/svg/path'; + const humanAccess = 'maintainer'; const iconName = 'status_notfound'; beforeEach(() => { wrapper = mount(suggestPipelineComponent, { - propsData: { pipelinePath }, + propsData: { pipelinePath, pipelineSvgPath, humanAccess }, + stubs: { + ...stubChildren(PipelineTourState), + }, }); }); @@ -22,30 +30,47 @@ describe('MRWidgetHeader', () => { it('renders add pipeline file link', () => { const link = wrapper.find(GlLink); - return wrapper.vm.$nextTick().then(() => { - expect(link.exists()).toBe(true); - expect(link.attributes().href).toBe(pipelinePath); - }); + expect(link.exists()).toBe(true); + expect(link.attributes().href).toBe(pipelinePath); }); it('renders the expected text', () => { const messageText = /\s*No pipeline\s*Add the .gitlab-ci.yml file\s*to create one./; - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.text()).toMatch(messageText); - }); + expect(wrapper.text()).toMatch(messageText); }); it('renders widget icon', () => { const icon = wrapper.find(MrWidgetIcon); - return wrapper.vm.$nextTick().then(() => { - expect(icon.exists()).toBe(true); - expect(icon.props()).toEqual( - expect.objectContaining({ - name: iconName, - }), - ); + expect(icon.exists()).toBe(true); + expect(icon.props()).toEqual( + expect.objectContaining({ + name: iconName, + }), + ); + }); + + describe('tracking', () => { + let spy; + + beforeEach(() => { + spy = mockTracking('_category_', wrapper.element, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + + it('send an event when ok button is clicked', () => { + const link = wrapper.find(GlLink); + triggerEvent(link.element); + + expect(spy).toHaveBeenCalledWith('_category_', 'click_link', { + label: 'no_pipeline_noticed', + property: humanAccess, + value: '30', + }); }); }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_tour_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_tour_spec.js new file mode 100644 index 00000000000..e8f95e099cc --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_tour_spec.js @@ -0,0 +1,143 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlPopover } from '@gitlab/ui'; +import Cookies from 'js-cookie'; +import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper'; +import pipelineTourState from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue'; +import { popoverProps, cookieKey } from './pipeline_tour_mock_data'; + +describe('MRWidgetPipelineTour', () => { + let wrapper; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('template', () => { + describe(`when ${cookieKey} cookie is set`, () => { + beforeEach(() => { + Cookies.set(cookieKey, true); + wrapper = shallowMount(pipelineTourState, { + propsData: popoverProps, + }); + }); + + it('does not render the popover', () => { + const popover = wrapper.find(GlPopover); + + expect(popover.exists()).toBe(false); + }); + + describe('tracking', () => { + let trackingSpy; + + beforeEach(() => { + trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + it('does not call tracking', () => { + expect(trackingSpy).not.toHaveBeenCalled(); + }); + }); + }); + + describe(`when ${cookieKey} cookie is not set`, () => { + const findOkBtn = () => wrapper.find({ ref: 'ok' }); + const findDismissBtn = () => wrapper.find({ ref: 'no-thanks' }); + + beforeEach(() => { + Cookies.remove(cookieKey); + wrapper = shallowMount(pipelineTourState, { + propsData: popoverProps, + }); + }); + + it('renders the popover', () => { + const popover = wrapper.find(GlPopover); + + expect(popover.exists()).toBe(true); + }); + + it('renders the show me how button', () => { + const button = findOkBtn(); + + expect(button.exists()).toBe(true); + expect(button.attributes().category).toBe('primary'); + }); + + it('renders the dismiss button', () => { + const button = findDismissBtn(); + + expect(button.exists()).toBe(true); + expect(button.attributes().category).toBe('secondary'); + }); + + it('renders the empty pipelines image', () => { + const image = wrapper.find('img'); + + expect(image.exists()).toBe(true); + expect(image.attributes().src).toBe(popoverProps.pipelineSvgPath); + }); + + describe('tracking', () => { + let trackingSpy; + + beforeEach(() => { + trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + + it('send event for basic view of popover', () => { + document.body.dataset.page = 'projects:merge_requests:show'; + + wrapper.vm.trackOnShow(); + + expect(trackingSpy).toHaveBeenCalledWith(undefined, undefined, { + label: popoverProps.trackLabel, + property: popoverProps.humanAccess, + }); + }); + + it('send an event when ok button is clicked', () => { + const okBtn = findOkBtn(); + triggerEvent(okBtn.element); + + expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_button', { + label: popoverProps.trackLabel, + property: popoverProps.humanAccess, + value: '10', + }); + }); + + it('send an event when dismiss button is clicked', () => { + const dismissBtn = findDismissBtn(); + triggerEvent(dismissBtn.element); + + expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_button', { + label: popoverProps.trackLabel, + property: popoverProps.humanAccess, + value: '20', + }); + }); + }); + + describe('dismissPopover', () => { + it('updates popoverDismissed', () => { + const button = findDismissBtn(); + const popover = wrapper.find(GlPopover); + button.vm.$emit('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(Cookies.get(cookieKey)).toBe('true'); + expect(popover.exists()).toBe(false); + }); + }); + }); + }); + }); +}); diff --git a/spec/frontend/vue_mr_widget/components/states/pipeline_tour_mock_data.js b/spec/frontend/vue_mr_widget/components/states/pipeline_tour_mock_data.js new file mode 100644 index 00000000000..39bc89e459c --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/states/pipeline_tour_mock_data.js @@ -0,0 +1,10 @@ +export const popoverProps = { + pipelinePath: '/foo/bar/add/pipeline/path', + pipelineSvgPath: 'assets/illustrations/something.svg', + humanAccess: 'maintainer', + popoverTarget: 'suggest-popover', + popoverContainer: 'suggest-pipeline', + trackLabel: 'some_tracking_label', +}; + +export const cookieKey = 'suggest_pipeline_dismissed'; -- cgit v1.2.3