From 5ca86a9b8998fad70b1737af31be4fbafefd4b7a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 11:52:02 -0300 Subject: [PATCH 1/3] upgrade js-commons --- package-lock.json | 10 +++++----- package.json | 2 +- src/__tests__/testUtils/browser.js | 20 ++++++++++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18dc4171e..56ba5ebf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -437,9 +437,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.4.2-rc.3", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.2-rc.3.tgz", - "integrity": "sha512-IndiNdYzym6uD01m8IR5tCO77/adLXnt0j6L4XsYQ3MRMeS3+8Dqrlq3XBRGNIWs6MzG1T/BdLmGdZ+ZNQF3Fg==", + "version": "1.4.2-rc.4", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.2-rc.4.tgz", + "integrity": "sha512-/Lmvb4WfrTHdKMVd7yDLwqAvHCULqOd7BFQmNqOSDWb1ctMOBW9uGY+xm0ijM9+/lvJHcnccMJzxWEGaA8fGsQ==", "requires": { "tslib": "^2.3.1" } @@ -4037,7 +4037,7 @@ "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, "lodash.flatten": { "version": "4.4.0", @@ -4053,7 +4053,7 @@ "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, "lodash.isequal": { "version": "4.5.0", diff --git a/package.json b/package.json index 60ca714e5..e0e091c1a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.4.2-rc.3", + "@splitsoftware/splitio-commons": "1.4.2-rc.4", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/__tests__/testUtils/browser.js b/src/__tests__/testUtils/browser.js index b185e93da..a04a1e445 100644 --- a/src/__tests__/testUtils/browser.js +++ b/src/__tests__/testUtils/browser.js @@ -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); } + +// Util method to trigger 'unload' DOM event +export function triggerUnloadEvent() { + triggerEvent('unload'); +} + +export function triggerPagehideEvent() { + triggerEvent('pagehide'); +} + +export function triggerVisibilitychangeHidden() { + triggerEvent('visibilitychange'); +} \ No newline at end of file From 9d099ee1462da70da84a1dbb3d39bd2962878083 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 29 Jun 2022 11:42:55 -0300 Subject: [PATCH 2/3] update E2E tests --- src/__tests__/browser.spec.js | 6 ++--- .../use-beacon-api.debug.spec.js | 23 +++++++++-------- .../browserSuites/use-beacon-api.spec.js | 25 +++++++++++-------- .../browserSuites/user-consent.spec.js | 6 ++--- src/__tests__/testUtils/browser.js | 8 +++--- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/__tests__/browser.spec.js b/src/__tests__/browser.spec.js index 618a862b5..9abcfbfc4 100644 --- a/src/__tests__/browser.spec.js +++ b/src/__tests__/browser.spec.js @@ -121,9 +121,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 */ diff --git a/src/__tests__/browserSuites/use-beacon-api.debug.spec.js b/src/__tests__/browserSuites/use-beacon-api.debug.spec.js index 4615f1cd0..9d604b494 100644 --- a/src/__tests__/browserSuites/use-beacon-api.debug.spec.js +++ b/src/__tests__/browserSuites/use-beacon-api.debug.spec.js @@ -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: { @@ -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'); @@ -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(() => { @@ -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 @@ -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(() => { @@ -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 @@ -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'); @@ -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(); }); } diff --git a/src/__tests__/browserSuites/use-beacon-api.spec.js b/src/__tests__/browserSuites/use-beacon-api.spec.js index f6c6505fa..d36ceaf45 100644 --- a/src/__tests__/browserSuites/use-beacon-api.spec.js +++ b/src/__tests__/browserSuites/use-beacon-api.spec.js @@ -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: { @@ -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'); @@ -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(() => { @@ -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 @@ -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(() => { @@ -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 @@ -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'); @@ -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(); }); } diff --git a/src/__tests__/browserSuites/user-consent.spec.js b/src/__tests__/browserSuites/user-consent.spec.js index 32ecd90c4..7dd3cad9e 100644 --- a/src/__tests__/browserSuites/user-consent.spec.js +++ b/src/__tests__/browserSuites/user-consent.spec.js @@ -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 = []; @@ -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 { diff --git a/src/__tests__/testUtils/browser.js b/src/__tests__/testUtils/browser.js index a04a1e445..5a3d52e4c 100644 --- a/src/__tests__/testUtils/browser.js +++ b/src/__tests__/testUtils/browser.js @@ -5,7 +5,6 @@ function triggerEvent(eventName) { window.dispatchEvent(event); } -// Util method to trigger 'unload' DOM event export function triggerUnloadEvent() { triggerEvent('unload'); } @@ -14,6 +13,7 @@ export function triggerPagehideEvent() { triggerEvent('pagehide'); } -export function triggerVisibilitychangeHidden() { - triggerEvent('visibilitychange'); -} \ No newline at end of file +export function triggerVisibilitychange(state = 'hidden' /* 'hidden' | 'visible' */) { + Object.defineProperty(document, 'visibilityState', { value: state, writable: true }); + window.dispatchEvent(new Event('visibilitychange')); +} From 78914761b2ecd4c51ab1428e2923122d8b6d3ee9 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 5 Jul 2022 18:13:31 -0300 Subject: [PATCH 3/3] update js-commons --- package-lock.json | 6 +++--- package.json | 2 +- src/__tests__/testUtils/browser.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8dd9734f..b82e8de45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -437,9 +437,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.0.tgz", - "integrity": "sha512-7vBv4Yn+EKaAxJ+9RdKOqJNee+izj6BieG0ZmivWk8fTpKFpcvqKes/Y0kXk0tfOiMmUFV9dRr2xDHRYIf0lnw==", + "version": "1.5.1-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.1-rc.0.tgz", + "integrity": "sha512-4XgahrK5lS9pyuNoYaxNfkPIPEWk+SX38UVf2/xyL/roRpwEnI5VyGaVvKZvRzfIsFndkNgHSp+78uM/zCRBSg==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index 815066319..7d7cf2bfa 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/__tests__/testUtils/browser.js b/src/__tests__/testUtils/browser.js index 5a3d52e4c..60284923d 100644 --- a/src/__tests__/testUtils/browser.js +++ b/src/__tests__/testUtils/browser.js @@ -15,5 +15,5 @@ export function triggerPagehideEvent() { export function triggerVisibilitychange(state = 'hidden' /* 'hidden' | 'visible' */) { Object.defineProperty(document, 'visibilityState', { value: state, writable: true }); - window.dispatchEvent(new Event('visibilitychange')); + document.dispatchEvent(new Event('visibilitychange')); }