diff --git a/app/assets/javascripts/pages/dashboard/projects/index/components/customize_homepage_banner.vue b/app/assets/javascripts/pages/dashboard/projects/index/components/customize_homepage_banner.vue index 6b907f31a37de118fc42b6159c1dc4d67c8e9923..9fa441348c784800f4d836c822e97282b0d70d49 100644 --- a/app/assets/javascripts/pages/dashboard/projects/index/components/customize_homepage_banner.vue +++ b/app/assets/javascripts/pages/dashboard/projects/index/components/customize_homepage_banner.vue @@ -2,11 +2,15 @@ import { GlBanner } from '@gitlab/ui'; import { s__ } from '~/locale'; import axios from '~/lib/utils/axios_utils'; +import Tracking from '~/tracking'; + +const trackingMixin = Tracking.mixin(); export default { components: { GlBanner, }, + mixins: [trackingMixin], inject: { svgPath: { default: '', @@ -20,6 +24,9 @@ export default { calloutsFeatureId: { default: '', }, + trackLabel: { + default: '', + }, }, i18n: { title: s__('CustomizeHomepageBanner|Do you want to customize this page?'), @@ -31,8 +38,19 @@ export default { data() { return { visible: true, + tracking: { + label: this.trackLabel, + }, }; }, + created() { + this.$nextTick(() => { + this.addTrackingAttributesToButton(); + }); + }, + mounted() { + this.trackOnShow(); + }, methods: { handleClose() { axios @@ -45,6 +63,23 @@ export default { }); this.visible = false; + this.track('click_dismiss'); + }, + trackOnShow() { + if (this.visible) this.track('show_home_page_banner'); + }, + addTrackingAttributesToButton() { + // we can't directly add these on the button like we need to due to + // button not being modifiable currently + // https://gitlab.com/gitlab-org/gitlab-ui/-/blob/9209ec424e5cca14bc8a1b5c9fa12636d8c83dad/src/components/base/banner/banner.vue#L60 + const button = this.$refs.banner.$el.querySelector( + `[href='${this.preferencesBehaviorPath}']`, + ); + + if (button) { + button.setAttribute('data-track-event', 'click_go_to_preferences'); + button.setAttribute('data-track-label', this.trackLabel); + } }, }, }; @@ -53,6 +88,7 @@ export default { <template> <gl-banner v-if="visible" + ref="banner" :title="$options.i18n.title" :button-text="$options.i18n.button_text" :button-link="preferencesBehaviorPath" diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml index 54a5624c6dd924e891d3bf01c8bd16eb3e637fc3..e8d5929442eab20e33a8b0ab367d41a20286f999 100644 --- a/app/views/dashboard/projects/index.html.haml +++ b/app/views/dashboard/projects/index.html.haml @@ -9,7 +9,8 @@ .js-customize-homepage-banner{ data: { svg_path: image_path('illustrations/monitoring/getting_started.svg'), preferences_behavior_path: profile_preferences_path(anchor: 'behavior'), callouts_path: user_callouts_path, - callouts_feature_id: UserCalloutsHelper::CUSTOMIZE_HOMEPAGE } } + callouts_feature_id: UserCalloutsHelper::CUSTOMIZE_HOMEPAGE, + track_label: 'home_page' } } = render_dashboard_gold_trial(current_user) diff --git a/spec/frontend/pages/dashboard/projects/index/components/customize_homepage_banner_spec.js b/spec/frontend/pages/dashboard/projects/index/components/customize_homepage_banner_spec.js index b3a297ac2c5861c1441357a287e38ed99f0df2ac..e83fb04a68839d61859090dab13848f6fa682607 100644 --- a/spec/frontend/pages/dashboard/projects/index/components/customize_homepage_banner_spec.js +++ b/spec/frontend/pages/dashboard/projects/index/components/customize_homepage_banner_spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import { GlBanner } from '@gitlab/ui'; import MockAdapter from 'axios-mock-adapter'; +import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper'; import CustomizeHomepageBanner from '~/pages/dashboard/projects/index/components/customize_homepage_banner.vue'; import axios from '~/lib/utils/axios_utils'; @@ -10,18 +11,22 @@ const provide = { preferencesBehaviorPath: 'some/behavior/path', calloutsPath: 'call/out/path', calloutsFeatureId: 'some-feature-id', + trackLabel: 'home_page', }; const createComponent = () => { - return shallowMount(CustomizeHomepageBanner, { provide }); + return shallowMount(CustomizeHomepageBanner, { provide, stubs: { GlBanner } }); }; describe('CustomizeHomepageBanner', () => { + let trackingSpy; let mockAxios; let wrapper; beforeEach(() => { mockAxios = new MockAdapter(axios); + document.body.dataset.page = 'some:page'; + trackingSpy = mockTracking('_category_', undefined, jest.spyOn); wrapper = createComponent(); }); @@ -29,6 +34,7 @@ describe('CustomizeHomepageBanner', () => { wrapper.destroy(); wrapper = null; mockAxios.restore(); + unmockTracking(); }); it('should render the banner when not dismissed', () => { @@ -47,4 +53,56 @@ describe('CustomizeHomepageBanner', () => { it('includes the body text from options', () => { expect(wrapper.html()).toContain(wrapper.vm.$options.i18n.body); }); + + describe('tracking', () => { + const preferencesTrackingEvent = 'click_go_to_preferences'; + const mockTrackingOnWrapper = () => { + unmockTracking(); + trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); + }; + + it('sets the needed data attributes for tracking button', async () => { + await wrapper.vm.$nextTick(); + const button = wrapper.find(`[href='${wrapper.vm.preferencesBehaviorPath}']`); + + expect(button.attributes('data-track-event')).toEqual(preferencesTrackingEvent); + expect(button.attributes('data-track-label')).toEqual(provide.trackLabel); + }); + + it('sends a tracking event when the banner is shown', () => { + const trackCategory = undefined; + const trackEvent = 'show_home_page_banner'; + + expect(trackingSpy).toHaveBeenCalledWith(trackCategory, trackEvent, { + label: provide.trackLabel, + }); + }); + + it('sends a tracking event when the banner is dismissed', async () => { + mockTrackingOnWrapper(); + mockAxios.onPost(provide.calloutsPath).replyOnce(200); + const trackCategory = undefined; + const trackEvent = 'click_dismiss'; + + wrapper.find(GlBanner).vm.$emit('close'); + + await wrapper.vm.$nextTick(); + expect(trackingSpy).toHaveBeenCalledWith(trackCategory, trackEvent, { + label: provide.trackLabel, + }); + }); + + it('sends a tracking event when the button is clicked', async () => { + mockTrackingOnWrapper(); + mockAxios.onPost(provide.calloutsPath).replyOnce(200); + const button = wrapper.find(`[href='${wrapper.vm.preferencesBehaviorPath}']`); + + triggerEvent(button.element); + + await wrapper.vm.$nextTick(); + expect(trackingSpy).toHaveBeenCalledWith('_category_', preferencesTrackingEvent, { + label: provide.trackLabel, + }); + }); + }); });