diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-24 21:09:08 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-24 21:09:08 +0000 |
commit | 7671216b60e2796a050358ff808b4a0c2de3d22f (patch) | |
tree | 605dfc1339a3cd7dc7353ac6d725191086a9acca /spec/frontend | |
parent | c2367afbf57ebc65d5b78a743b5d6a91f0aece9f (diff) | |
download | gitlab-ce-7671216b60e2796a050358ff808b4a0c2de3d22f.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
7 files changed, 332 insertions, 16 deletions
diff --git a/spec/frontend/blob/pipeline_tour_success_spec.js b/spec/frontend/blob/pipeline_tour_success_spec.js new file mode 100644 index 00000000000..f6783b31a73 --- /dev/null +++ b/spec/frontend/blob/pipeline_tour_success_spec.js @@ -0,0 +1,40 @@ +import pipelineTourSuccess from '~/blob/pipeline_tour_success_modal.vue'; +import { shallowMount } from '@vue/test-utils'; +import Cookies from 'js-cookie'; +import { GlSprintf, GlModal } from '@gitlab/ui'; + +describe('PipelineTourSuccessModal', () => { + let wrapper; + let cookieSpy; + const goToPipelinesPath = 'some_pipeline_path'; + const commitCookie = 'some_cookie'; + + beforeEach(() => { + wrapper = shallowMount(pipelineTourSuccess, { + propsData: { + goToPipelinesPath, + commitCookie, + }, + }); + + cookieSpy = jest.spyOn(Cookies, 'remove'); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('has expected structure', () => { + const modal = wrapper.find(GlModal); + const sprintf = modal.find(GlSprintf); + + expect(modal.attributes('title')).toContain("That's it, well done!"); + expect(sprintf.exists()).toBe(true); + }); + + it('calls to remove cookie', () => { + wrapper.vm.disableModalFromRenderingAgain(); + + expect(cookieSpy).toHaveBeenCalledWith(commitCookie); + }); +}); diff --git a/spec/frontend/helpers/tracking_helper.js b/spec/frontend/helpers/tracking_helper.js index 68c1bd2dbca..bd3bd24028c 100644 --- a/spec/frontend/helpers/tracking_helper.js +++ b/spec/frontend/helpers/tracking_helper.js @@ -8,7 +8,7 @@ let handlers; export function mockTracking(category = '_category_', documentOverride, spyMethod) { document = documentOverride || window.document; window.snowplow = () => {}; - Tracking.bindDocument(category, document); + handlers = Tracking.bindDocument(category, document); return spyMethod ? spyMethod(Tracking, 'event') : null; } diff --git a/spec/frontend/tracking_spec.js b/spec/frontend/tracking_spec.js index c3c52844c2c..30a8e138df2 100644 --- a/spec/frontend/tracking_spec.js +++ b/spec/frontend/tracking_spec.js @@ -226,6 +226,14 @@ describe('Tracking', () => { }; }); + it('calls the event method with no category or action defined', () => { + mixin.trackingCategory = mixin.trackingCategory(); + mixin.trackingOptions = mixin.trackingOptions(); + + mixin.track(); + expect(eventSpy).toHaveBeenCalledWith(undefined, undefined, {}); + }); + it('calls the event method', () => { mixin.trackingCategory = mixin.trackingCategory(); mixin.trackingOptions = mixin.trackingOptions(); 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'; diff --git a/spec/frontend/vue_shared/components/file_row_spec.js b/spec/frontend/vue_shared/components/file_row_spec.js new file mode 100644 index 00000000000..420281e844c --- /dev/null +++ b/spec/frontend/vue_shared/components/file_row_spec.js @@ -0,0 +1,90 @@ +import { file } from 'jest/ide/helpers'; +import FileRow from '~/vue_shared/components/file_row.vue'; +import { mount } from '@vue/test-utils'; + +describe('File row component', () => { + let wrapper; + + function createComponent(propsData) { + wrapper = mount(FileRow, { + propsData, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders name', () => { + const fileName = 't4'; + createComponent({ + file: file(fileName), + level: 0, + }); + + const name = wrapper.find('.file-row-name'); + + expect(name.text().trim()).toEqual(fileName); + }); + + it('emits toggleTreeOpen on click', () => { + const fileName = 't3'; + createComponent({ + file: { + ...file(fileName), + type: 'tree', + }, + level: 0, + }); + jest.spyOn(wrapper.vm, '$emit'); + + wrapper.element.click(); + + expect(wrapper.vm.$emit).toHaveBeenCalledWith('toggleTreeOpen', fileName); + }); + + it('calls scrollIntoView if made active', () => { + createComponent({ + file: { + ...file(), + type: 'blob', + active: false, + }, + level: 0, + }); + + jest.spyOn(wrapper.vm, 'scrollIntoView'); + + wrapper.setProps({ + file: Object.assign({}, wrapper.props('file'), { + active: true, + }), + }); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.vm.scrollIntoView).toHaveBeenCalled(); + }); + }); + + it('indents row based on level', () => { + createComponent({ + file: file('t4'), + level: 2, + }); + + expect(wrapper.find('.file-row-name').element.style.marginLeft).toBe('32px'); + }); + + it('renders header for file', () => { + createComponent({ + file: { + isHeader: true, + path: 'app/assets', + tree: [], + }, + level: 0, + }); + + expect(wrapper.element.classList).toContain('js-file-row-header'); + }); +}); |