Commit b4a35f5a authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'rk/214679-track-client-design-views' into 'master'

Track Client Design Detail View Event

See merge request gitlab-org/gitlab!30516
parents e47f8abd adf5f83e
...@@ -35,6 +35,7 @@ import { ...@@ -35,6 +35,7 @@ import {
UPDATE_NOTE_ERROR, UPDATE_NOTE_ERROR,
designDeletionError, designDeletionError,
} from '../../utils/error_messages'; } from '../../utils/error_messages';
import { trackDesignDetailView } from '../../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../../router/constants'; import { DESIGNS_ROUTE_NAME } from '../../router/constants';
export default { export default {
...@@ -257,8 +258,21 @@ export default { ...@@ -257,8 +258,21 @@ export default {
query: this.$route.query, query: this.$route.query,
}); });
}, },
trackEvent() {
trackDesignDetailView(
'issue-design-collection',
this.$route.query.version || this.latestVersionId,
this.isLatestVersion,
);
},
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.trackEvent();
});
}, },
beforeRouteUpdate(to, from, next) { beforeRouteUpdate(to, from, next) {
this.trackEvent();
this.closeCommentForm(); this.closeCommentForm();
next(); next();
}, },
......
import Tracking from '~/tracking';
function assembleDesignPayload(payloadArr) {
return {
value: {
'internal-object-refrerer': payloadArr[0],
'version-number': payloadArr[1],
'current-version': payloadArr[2],
},
};
}
// Tracking Constants
const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design';
// eslint-disable-next-line import/prefer-default-export
export function trackDesignDetailView(refrerer = '', designVersion = 1, latestVersion = false) {
Tracking.event(DESIGN_TRACKING_PAGE_NAME, 'design_viewed', {
label: 'design_viewed',
...assembleDesignPayload([refrerer, designVersion, latestVersion]),
});
}
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import App from '~/design_management/components/app.vue'; import App from '~/design_management/components/app.vue';
import Designs from '~/design_management/pages/index.vue'; import Designs from '~/design_management/pages/index.vue';
...@@ -11,74 +12,66 @@ import { ...@@ -11,74 +12,66 @@ import {
} from '~/design_management/router/constants'; } from '~/design_management/router/constants';
import '~/commons/bootstrap'; import '~/commons/bootstrap';
jest.mock('mousetrap', () => ({ function factory(routeArg) {
bind: jest.fn(), const localVue = createLocalVue();
unbind: jest.fn(), localVue.use(VueRouter);
}));
describe('Design management router', () => {
let vm;
let router;
function factory() {
const localVue = createLocalVue();
localVue.use(VueRouter);
window.gon = { sprite_icons: '' }; window.gon = { sprite_icons: '' };
router = createRouter('/'); const router = createRouter('/');
if (routeArg !== undefined) {
router.push(routeArg);
}
vm = mount(App, { return mount(App, {
localVue, localVue,
router, router,
mocks: { mocks: {
$apollo: { $apollo: {
queries: { queries: {
designs: { loading: true }, designs: { loading: true },
design: { loading: true }, design: { loading: true },
permissions: { loading: true }, permissions: { loading: true },
},
}, },
}, },
}); },
}
beforeEach(() => {
factory();
}); });
}
afterEach(() => { jest.mock('mousetrap', () => ({
vm.destroy(); bind: jest.fn(),
unbind: jest.fn(),
}));
router.app.$destroy(); describe('Design management router', () => {
afterEach(() => {
window.location.hash = ''; window.location.hash = '';
}); });
describe.each([['/'], [{ name: ROOT_ROUTE_NAME }]])('root route', pushArg => { describe.each([['/'], [{ name: ROOT_ROUTE_NAME }]])('root route', routeArg => {
it('pushes home component', () => { it('pushes home component', () => {
router.push(pushArg); const wrapper = factory(routeArg);
expect(vm.find(Designs).exists()).toBe(true); expect(wrapper.find(Designs).exists()).toBe(true);
}); });
}); });
describe.each([['/designs'], [{ name: DESIGNS_ROUTE_NAME }]])('designs route', pushArg => { describe.each([['/designs'], [{ name: DESIGNS_ROUTE_NAME }]])('designs route', routeArg => {
it('pushes designs root component', () => { it('pushes designs root component', () => {
router.push(pushArg); const wrapper = factory(routeArg);
expect(vm.find(Designs).exists()).toBe(true); expect(wrapper.find(Designs).exists()).toBe(true);
}); });
}); });
describe.each([['/designs/1'], [{ name: DESIGN_ROUTE_NAME, params: { id: '1' } }]])( describe.each([['/designs/1'], [{ name: DESIGN_ROUTE_NAME, params: { id: '1' } }]])(
'designs detail route', 'designs detail route',
pushArg => { routeArg => {
it('pushes designs detail component', () => { it('pushes designs detail component', () => {
router.push(pushArg); const wrapper = factory(routeArg);
return vm.vm.$nextTick().then(() => { return nextTick().then(() => {
const detail = vm.find(DesignDetail); const detail = wrapper.find(DesignDetail);
expect(detail.exists()).toBe(true); expect(detail.exists()).toBe(true);
expect(detail.props('id')).toEqual('1'); expect(detail.props('id')).toEqual('1');
}); });
......
import { mockTracking } from 'helpers/tracking_helper';
import { trackDesignDetailView } from '~/design_management/utils/tracking';
function getTrackingSpy(key) {
return mockTracking(key, undefined, jest.spyOn);
}
describe('Tracking Events', () => {
describe('trackDesignDetailView', () => {
const eventKey = 'projects:issues:design';
const eventName = 'design_viewed';
it('trackDesignDetailView fires a tracking event when called', () => {
const trackingSpy = getTrackingSpy(eventKey);
trackDesignDetailView();
expect(trackingSpy).toHaveBeenCalledWith(
eventKey,
eventName,
expect.objectContaining({
label: eventName,
value: {
'internal-object-refrerer': '',
'version-number': 1,
'current-version': false,
},
}),
);
});
it('trackDesignDetailView allows to customize the value payload', () => {
const trackingSpy = getTrackingSpy(eventKey);
trackDesignDetailView('from-a-test', 100, true);
expect(trackingSpy).toHaveBeenCalledWith(
eventKey,
eventName,
expect.objectContaining({
label: eventName,
value: {
'internal-object-refrerer': 'from-a-test',
'version-number': 100,
'current-version': true,
},
}),
);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment