import API from '~/api';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import InternalEvents from '~/tracking/internal_events';
import {
GITLAB_INTERNAL_EVENT_CATEGORY,
SERVICE_PING_SCHEMA,
LOAD_INTERNAL_EVENTS_SELECTOR,
} from '~/tracking/constants';
import * as utils from '~/tracking/utils';
import { Tracker } from '~/tracking/tracker';
import { extraContext } from './mock_data';
jest.mock('~/api', () => ({
trackInternalEvent: jest.fn(),
}));
jest.mock('~/tracking/utils', () => ({
...jest.requireActual('~/tracking/utils'),
getInternalEventHandlers: jest.fn(),
}));
Tracker.enabled = jest.fn();
const event = 'TestEvent';
describe('InternalEvents', () => {
describe('trackEvent', () => {
it('trackEvent calls API.trackInternalEvent with correct arguments', () => {
InternalEvents.trackEvent(event);
expect(API.trackInternalEvent).toHaveBeenCalledTimes(1);
expect(API.trackInternalEvent).toHaveBeenCalledWith(event);
});
it('trackEvent calls trackBrowserSDK with correct arguments', () => {
jest.spyOn(InternalEvents, 'trackBrowserSDK').mockImplementation(() => {});
InternalEvents.trackEvent(event);
expect(InternalEvents.trackBrowserSDK).toHaveBeenCalledTimes(1);
expect(InternalEvents.trackBrowserSDK).toHaveBeenCalledWith(event);
});
it('trackEvent calls tracking.event functions with correct arguments', () => {
const trackingSpy = mockTracking(GITLAB_INTERNAL_EVENT_CATEGORY, undefined, jest.spyOn);
InternalEvents.trackEvent(event, { context: extraContext });
expect(trackingSpy).toHaveBeenCalledTimes(1);
expect(trackingSpy).toHaveBeenCalledWith(GITLAB_INTERNAL_EVENT_CATEGORY, event, {
context: [
{
schema: SERVICE_PING_SCHEMA,
data: {
event_name: event,
data_source: 'redis_hll',
},
},
extraContext,
],
});
});
});
describe('mixin', () => {
let wrapper;
const Component = {
template: `
`,
methods: {
handleButton1Click() {
this.trackEvent(event);
},
handleButton2Click() {
this.trackEvent(event, extraContext);
},
},
mixins: [InternalEvents.mixin()],
};
beforeEach(() => {
wrapper = shallowMountExtended(Component);
});
it('this.trackEvent function calls InternalEvent`s track function with an event', async () => {
const trackEventSpy = jest.spyOn(InternalEvents, 'trackEvent');
await wrapper.findByTestId('button1').trigger('click');
expect(trackEventSpy).toHaveBeenCalledTimes(1);
expect(trackEventSpy).toHaveBeenCalledWith(event, {});
});
it("this.trackEvent function calls InternalEvent's track function with an event and data", async () => {
const data = extraContext;
const trackEventSpy = jest.spyOn(InternalEvents, 'trackEvent');
await wrapper.findByTestId('button2').trigger('click');
expect(trackEventSpy).toHaveBeenCalledTimes(1);
expect(trackEventSpy).toHaveBeenCalledWith(event, data);
});
});
describe('bindInternalEventDocument', () => {
it('should not bind event handlers if tracker is not enabled', () => {
Tracker.enabled.mockReturnValue(false);
const result = InternalEvents.bindInternalEventDocument();
expect(result).toEqual([]);
expect(utils.getInternalEventHandlers).not.toHaveBeenCalled();
});
it('should not bind event handlers if already bound', () => {
Tracker.enabled.mockReturnValue(true);
document.internalEventsTrackingBound = true;
const result = InternalEvents.bindInternalEventDocument();
expect(result).toEqual([]);
expect(utils.getInternalEventHandlers).not.toHaveBeenCalled();
});
it('should bind event handlers when not bound yet', () => {
Tracker.enabled.mockReturnValue(true);
document.internalEventsTrackingBound = false;
const addEventListenerMock = jest.spyOn(document, 'addEventListener');
const result = InternalEvents.bindInternalEventDocument();
expect(addEventListenerMock).toHaveBeenCalledWith('click', expect.any(Function));
expect(result).toEqual({ name: 'click', func: expect.any(Function) });
});
});
describe('trackInternalLoadEvents', () => {
let querySelectorAllMock;
let mockElements;
const action = 'i_devops_action';
beforeEach(() => {
Tracker.enabled.mockReturnValue(true);
querySelectorAllMock = jest.fn();
document.querySelectorAll = querySelectorAllMock;
});
it('should return an empty array if Tracker is not enabled', () => {
Tracker.enabled.mockReturnValue(false);
const result = InternalEvents.trackInternalLoadEvents();
expect(result).toEqual([]);
});
describe('tracking', () => {
let trackEventSpy;
beforeEach(() => {
trackEventSpy = jest.spyOn(InternalEvents, 'trackEvent');
});
it('should track event if action exists', () => {
mockElements = [{ dataset: { eventTracking: action, eventTrackingLoad: true } }];
querySelectorAllMock.mockReturnValue(mockElements);
const result = InternalEvents.trackInternalLoadEvents();
expect(trackEventSpy).toHaveBeenCalledWith(action);
expect(trackEventSpy).toHaveBeenCalledTimes(1);
expect(querySelectorAllMock).toHaveBeenCalledWith(LOAD_INTERNAL_EVENTS_SELECTOR);
expect(result).toEqual(mockElements);
});
it('should not track event if action is not present', () => {
mockElements = [{ dataset: { eventTracking: undefined, eventTrackingLoad: true } }];
querySelectorAllMock.mockReturnValue(mockElements);
InternalEvents.trackInternalLoadEvents();
expect(trackEventSpy).toHaveBeenCalledTimes(0);
});
});
});
describe('initBrowserSDK', () => {
beforeEach(() => {
window.glClient = {
setDocumentTitle: jest.fn(),
page: jest.fn(),
};
window.gl = {
environment: 'testing',
key: 'value',
};
});
it('should not call setDocumentTitle or page methods when window.glClient is undefined', () => {
window.glClient = undefined;
InternalEvents.initBrowserSDK();
expect(window.glClient?.setDocumentTitle).toBeUndefined();
expect(window.glClient?.page).toBeUndefined();
});
it('should call setDocumentTitle and page methods on window.glClient when it is defined', () => {
InternalEvents.initBrowserSDK();
expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab');
expect(window.glClient.page).toHaveBeenCalledWith({
title: 'GitLab',
});
});
it('should call setDocumentTitle and page methods with default data when window.gl is undefined', () => {
window.gl = undefined;
InternalEvents.initBrowserSDK();
expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab');
expect(window.glClient.page).toHaveBeenCalledWith({
title: 'GitLab',
});
});
});
describe('trackBrowserSDK', () => {
beforeEach(() => {
window.glClient = {
track: jest.fn(),
};
});
it('should not call glClient.track if Tracker is not enabled', () => {
Tracker.enabled.mockReturnValue(false);
InternalEvents.trackBrowserSDK(event);
expect(window.glClient.track).not.toHaveBeenCalled();
});
it('should call glClient.track with correct arguments if Tracker is enabled', () => {
Tracker.enabled.mockReturnValue(true);
InternalEvents.trackBrowserSDK(event);
expect(window.glClient.track).toHaveBeenCalledTimes(1);
expect(window.glClient.track).toHaveBeenCalledWith(event);
});
});
});