Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions src/listeners/__tests__/browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import { IEventsCacheSync, IImpressionCountsCacheSync, IImpressionsCacheSync, IS
import { ISplitApi } from '../../services/types';
import { fullSettings } from '../../utils/settingsValidation/__tests__/settings.mocks';

jest.mock('../../sync/submitters/telemetrySubmitter', () => {
return {
telemetryCacheStatsAdapter: () => {
return {
isEmpty: () => false,
clear: () => { },
state: () => ({}),
};
}
};
});

/* Mocks start */

const fakeImpression = {
Expand All @@ -26,6 +38,7 @@ const fakeImpressionCounts = {
'someFeature::0': 1
};

// Storage with impressionsCount and telemetry cache
const fakeStorageOptimized = { // @ts-expect-error
impressions: {
isEmpty: jest.fn(),
Expand All @@ -48,6 +61,7 @@ const fakeStorageOptimized = { // @ts-expect-error
return fakeImpressionCounts;
}
} as IImpressionCountsCacheSync,
telemetry: {}
};

const fakeStorageDebug = {
Expand All @@ -59,7 +73,8 @@ const fakeStorageDebug = {
const fakeSplitApi = {
postTestImpressionsBulk: jest.fn(() => Promise.resolve()),
postEventsBulk: jest.fn(() => Promise.resolve()),
postTestImpressionsCount: jest.fn(() => Promise.resolve())
postTestImpressionsCount: jest.fn(() => Promise.resolve()),
postMetricsUsage: jest.fn(() => Promise.resolve()),
} as ISplitApi;

const UNLOAD_DOM_EVENT = 'unload';
Expand Down Expand Up @@ -131,7 +146,7 @@ test('Browser JS listener / consumer mode', () => {
expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]);
});

test('Browser JS listener / standalone mode / Impressions optimized mode', () => {
test('Browser JS listener / standalone mode / Impressions optimized mode with telemetry', () => {
const syncManagerMock = {};

// @ts-expect-error
Expand All @@ -144,8 +159,8 @@ test('Browser JS listener / standalone mode / Impressions optimized mode', () =>

triggerUnloadEvent();

// Unload event was triggered. Thus sendBeacon method should have been called three times.
expect(global.window.navigator.sendBeacon).toBeCalledTimes(3);
// Unload event was triggered. Thus sendBeacon method should have been called four times.
expect(global.window.navigator.sendBeacon).toBeCalledTimes(4);

// Http post services should have not been called
expect(fakeSplitApi.postTestImpressionsBulk).not.toBeCalled();
Expand Down Expand Up @@ -195,7 +210,7 @@ test('Browser JS listener / standalone mode / Impressions debug mode', () => {
});

test('Browser JS listener / standalone mode / Impressions debug mode without sendBeacon API', () => {
// remove sendBeacon API
// remove sendBeacon API temporally
const sendBeacon = global.navigator.sendBeacon; // @ts-expect-error
global.navigator.sendBeacon = undefined;
const syncManagerMockWithoutPushManager = {};
Expand Down Expand Up @@ -254,8 +269,8 @@ test('Browser JS listener / standalone mode / user consent status', () => {
settings.userConsent = undefined;
triggerUnloadEvent();

// Unload event was triggered when user consent was granted and undefined. Thus sendBeacon should be called 6 times (3 times per event in optimized mode).
expect(global.window.navigator.sendBeacon).toBeCalledTimes(6);
// Unload event was triggered when user consent was granted and undefined. Thus sendBeacon should be called 8 times (4 times per event in optimized mode with telemetry).
expect(global.window.navigator.sendBeacon).toBeCalledTimes(8);

listener.stop();
});
7 changes: 6 additions & 1 deletion src/listeners/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
import { ISyncManager } from '../sync/types';
import { isConsentGranted } from '../consent';
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';

// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
const UNLOAD_DOM_EVENT = 'unload';
Expand Down Expand Up @@ -77,7 +78,11 @@ export class BrowserSignalListener implements ISignalListener {
this._flushData(eventsUrl + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
if (this.storage.impressionCounts) this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
// No beacon endpoint for `/metrics/usage`
if (this.storage.telemetry) {
const telemetryUrl = this.settings.urls.telemetry;
const telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
}
}

// Close streaming connection
Expand Down