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
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"node": ">=6"
},
"dependencies": {
"@splitsoftware/splitio-commons": "1.5.0",
"@splitsoftware/splitio-commons": "1.5.1-rc.0",
"@types/google.analytics": "0.0.40",
"@types/ioredis": "^4.28.0",
"ioredis": "^4.28.0",
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/browser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ tape('## E2E CI Tests ##', function(assert) {
assert.test('E2E / Readiness', readinessSuite.bind(null, fetchMock));
/* Validate headers for ip and hostname are not sended with requests (ignore setting IPAddressesEnabled) */
assert.test('E2E / Ignore setting IPAddressesEnabled', ignoreIpAddressesSettingSuite.bind(null, fetchMock));
/* Check that impressions and events are sended to backend via Beacon API or Fetch when page unload is triggered. */
assert.test('E2E / Use Beacon API (or Fetch if not available) to send remaining impressions and events when browser page is unload', useBeaconApiSuite.bind(null, fetchMock));
assert.test('E2E / Use Beacon API DEBUG (or Fetch if not available) to send remaining impressions and events when browser page is unload', useBeaconDebugApiSuite.bind(null, fetchMock));
/* Check that impressions and events are sended to backend via Beacon API or Fetch when pagehide/visibilitychange events are triggered. */
assert.test('E2E / Use Beacon API (or Fetch if not available) to send remaining impressions and events when browser page is unload or hidden', useBeaconApiSuite.bind(null, fetchMock));
assert.test('E2E / Use Beacon API DEBUG (or Fetch if not available) to send remaining impressions and events when browser page is unload or hidden', useBeaconDebugApiSuite.bind(null, fetchMock));
/* Validate ready from cache behaviour (might be merged into another suite if we end up having simple behavior around it as expected) */
assert.test('E2E / Readiness from cache', readyFromCache.bind(null, fetchMock));
/* Validate readiness with ready promises */
Expand Down
23 changes: 12 additions & 11 deletions src/__tests__/browserSuites/use-beacon-api.debug.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
import mySegmentsFacundo from '../mocks/mysegments.facundo@split.io.json';
import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants';
import { url } from '../testUtils';
import { triggerUnloadEvent } from '../testUtils/browser';
import { triggerPagehideEvent, triggerVisibilitychange } from '../testUtils/browser';

const config = {
core: {
Expand Down Expand Up @@ -61,7 +61,7 @@ const assertCallsToBeaconAPI = (assert) => {
assertEventSent(assert, parsedPayload.entries[0]);
};

// This E2E test checks that Beacon API is not called when page unload is triggered and there are not events or impressions to send.
// This E2E test checks that Beacon API is not called when page is hidden and there are not events or impressions to send.
function beaconApiNotSendTestDebug(fetchMock, assert) {
sendBeaconSpyDebug = sinon.spy(window.navigator, 'sendBeacon');

Expand All @@ -75,8 +75,9 @@ function beaconApiNotSendTestDebug(fetchMock, assert) {
const client = splitio.client();
client.on(client.Event.SDK_READY, () => {

// trigger unload event, without tracked events and impressions
triggerUnloadEvent();
// trigger events, without tracked events and impressions
triggerPagehideEvent();
triggerVisibilitychange();

// destroy the client and execute the next E2E test named beaconApiSendTest
setTimeout(() => {
Expand All @@ -90,7 +91,7 @@ function beaconApiNotSendTestDebug(fetchMock, assert) {
});
}

// This E2E test checks that impressions and events are sent to backend via Beacon API when page unload is triggered.
// This E2E test checks that impressions and events are sent to backend via Beacon API when page is hidden.
function beaconApiSendTestDebug(fetchMock, assert) {

// Init and run Split client
Expand All @@ -100,8 +101,8 @@ function beaconApiSendTestDebug(fetchMock, assert) {
client.getTreatment('hierarchical_splits_test');
client.track('sometraffictype', 'someEvent', 10);

// trigger unload event inmmediatly, before scheduled push of events and impressions
triggerUnloadEvent();
// trigger visibilitychange event inmmediatly, before scheduled push of events and impressions
triggerVisibilitychange();

// queue the assertion of the Beacon requests, destroy the client and execute the next E2E test named fallbackTest
setTimeout(() => {
Expand All @@ -115,7 +116,7 @@ function beaconApiSendTestDebug(fetchMock, assert) {
});
}

// This E2E test checks that impressions and events are sent to backend via Axios when page unload is triggered and Beacon API is not available.
// This E2E test checks that impressions and events are sent to backend via Fetch API when page is hidden and Beacon API is not available.
function fallbackTest(fetchMock, assert) {

// destroy reference to Beacon API
Expand All @@ -136,7 +137,7 @@ function fallbackTest(fetchMock, assert) {
}, 0);
})();

// Mock endpoints used by Axios
// Mock endpoints
fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, opts) => {
const resp = JSON.parse(opts.body);
assert.ok(opts, 'Fallback to /testImpressions/bulk');
Expand All @@ -155,8 +156,8 @@ function fallbackTest(fetchMock, assert) {
client.on(client.Event.SDK_READY, () => {
client.getTreatment('hierarchical_splits_test');
client.track('sometraffictype', 'someEvent', 10);
// trigger unload event inmmediatly, before scheduled push of events and impressions
triggerUnloadEvent();
// trigger pagehide event inmmediatly, before scheduled push of events and impressions
triggerPagehideEvent();
});
}

Expand Down
25 changes: 14 additions & 11 deletions src/__tests__/browserSuites/use-beacon-api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
import mySegmentsFacundo from '../mocks/mysegments.facundo@split.io.json';
import { url } from '../testUtils';
import { OPTIMIZED } from '@splitsoftware/splitio-commons/src/utils/constants';
import { triggerUnloadEvent } from '../testUtils/browser';
import { triggerPagehideEvent, triggerVisibilitychange } from '../testUtils/browser';

const config = {
core: {
Expand Down Expand Up @@ -73,7 +73,7 @@ const assertCallsToBeaconAPI = (assert) => {
assertImpressionsCountSent(assert, parsedPayload.entries);
};

// This E2E test checks that Beacon API is not called when page unload is triggered and there are not events or impressions to send.
// This E2E test checks that Beacon API is not called when page is hidden and there are not events or impressions to send.
function beaconApiNotSendTest(fetchMock, assert) {
sendBeaconSpy = sinon.spy(window.navigator, 'sendBeacon');

Expand All @@ -87,8 +87,9 @@ function beaconApiNotSendTest(fetchMock, assert) {
const client = splitio.client();
client.on(client.Event.SDK_READY, () => {

// trigger unload event, without tracked events and impressions
triggerUnloadEvent();
// trigger events, without tracked events and impressions
triggerPagehideEvent();
triggerVisibilitychange();

// destroy the client and execute the next E2E test named beaconApiSendTest
setTimeout(() => {
Expand All @@ -102,7 +103,7 @@ function beaconApiNotSendTest(fetchMock, assert) {
});
}

// This E2E test checks that impressions and events are sent to backend via Beacon API when page unload is triggered.
// This E2E test checks that impressions and events are sent to backend via Beacon API when page is hidden.
function beaconApiSendTest(fetchMock, assert) {

// Init and run Split client
Expand All @@ -112,8 +113,9 @@ function beaconApiSendTest(fetchMock, assert) {
client.getTreatment('hierarchical_splits_test');
client.track('sometraffictype', 'someEvent', 10);

// trigger unload event inmmediatly, before scheduled push of events and impressions
triggerUnloadEvent();
// trigger both events inmmediatly, before scheduled push of events and impressions, to assert that beacon requests are not duplicated
triggerPagehideEvent();
triggerVisibilitychange();

// queue the assertion of the Beacon requests, destroy the client and execute the next E2E test named fallbackTest
setTimeout(() => {
Expand All @@ -127,7 +129,7 @@ function beaconApiSendTest(fetchMock, assert) {
});
}

// This E2E test checks that impressions and events are sent to backend via Axios when page unload is triggered and Beacon API is not available.
// This E2E test checks that impressions and events are sent to backend via Fetch API when page is hidden and Beacon API is not available.
function fallbackTest(fetchMock, assert) {

// destroy reference to Beacon API
Expand All @@ -149,7 +151,7 @@ function fallbackTest(fetchMock, assert) {
}, 0);
})();

// Mock endpoints used by Axios
// Mock endpoints
fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, opts) => {
const resp = JSON.parse(opts.body);
assert.ok(opts, 'Fallback to /testImpressions/bulk');
Expand All @@ -175,8 +177,9 @@ function fallbackTest(fetchMock, assert) {
client.on(client.Event.SDK_READY, () => {
client.getTreatment('hierarchical_splits_test');
client.track('sometraffictype', 'someEvent', 10);
// trigger unload event inmmediatly, before scheduled push of events and impressions
triggerUnloadEvent();
// trigger both events inmmediatly, before scheduled push of events and impressions, to assert that POST requests are not duplicated
triggerPagehideEvent();
triggerVisibilitychange();
});
}

Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/browserSuites/user-consent.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sinon from 'sinon';
import { SplitFactory } from '../../';
import { triggerUnloadEvent } from '../testUtils/browser';
import { triggerPagehideEvent } from '../testUtils/browser';
import { nearlyEqual, url } from '../testUtils';

const trackedImpressions = [];
Expand Down Expand Up @@ -97,9 +97,9 @@ export default function userConsent(fetchMock, t) {
], ['on', 'on', 'on', 'on', 'on', 'on', 'on', 'on'], 'evaluating on SDK ready');
if (isTracking) expectedTrackedImpressions += 8;

// Trigger unload event to validate browser listener behaviour
// Trigger pagehide event to validate browser listener behaviour
// Beacon API is used only if user consent is GRANTED
triggerUnloadEvent();
triggerPagehideEvent();
if (factory.UserConsent.getStatus() === factory.UserConsent.Status.GRANTED) {
assert.ok(sendBeaconSpy.calledThrice, 'sendBeacon should have been called thrice');
} else {
Expand Down
20 changes: 16 additions & 4 deletions src/__tests__/testUtils/browser.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
// Util method to trigger 'unload' DOM event
export function triggerUnloadEvent() {
function triggerEvent(eventName) {
const event = document.createEvent('HTMLEvents');
event.initEvent('unload', true, true);
event.eventName = 'unload';
event.initEvent(eventName, true, true);
event.eventName = eventName;
window.dispatchEvent(event);
}

export function triggerUnloadEvent() {
triggerEvent('unload');
}

export function triggerPagehideEvent() {
triggerEvent('pagehide');
}

export function triggerVisibilitychange(state = 'hidden' /* 'hidden' | 'visible' */) {
Object.defineProperty(document, 'visibilityState', { value: state, writable: true });
document.dispatchEvent(new Event('visibilitychange'));
}