From c31dc1d4b60b42d8299e0e68ddb7441e6eee5799 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 6 Jun 2022 18:51:42 -0300 Subject: [PATCH 01/25] e2e test for GaToSplit integration auto-require --- .github/workflows/ci-cd.yml | 4 +- package-lock.json | 12 +-- package.json | 4 +- .../gaIntegration/ga-to-split.spec.js | 83 ++++++++++++++++++- src/__tests__/gaIntegration/gaTestUtils.js | 9 +- src/settings/defaults/version.js | 2 +- 6 files changed, 99 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 7164bcf99..fa828f595 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,14 +51,14 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/package-lock.json b/package-lock.json index 7891466df..12cb3b367 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.0", + "version": "10.19.1-rc1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -437,9 +437,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.0.tgz", - "integrity": "sha512-i/gXbtzUMKotva66mkPpa8g49v+gR4AbA/ZTKBGFi4CN+blwFO/10YQQWro8Gm9YJIB1mTXdplem6XkeBUzISA==", + "version": "1.4.1-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.1-rc.0.tgz", + "integrity": "sha512-pKYyDAfpvu66rDDXN2EIu3hWqwiScwjfIaysc7g845c0YI9YMoDZxtcDYObM9tTM8C4eLG+wgXRg8K6OIRVcwg==", "requires": { "tslib": "^2.3.1" } @@ -4040,7 +4040,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", @@ -4056,7 +4056,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 8e16d9430..b0672017e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.0", + "version": "10.19.1-rc1", "description": "Split SDK", "files": [ "README.md", @@ -32,7 +32,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.4.0", + "@splitsoftware/splitio-commons": "1.4.1-rc.0", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/__tests__/gaIntegration/ga-to-split.spec.js b/src/__tests__/gaIntegration/ga-to-split.spec.js index 350d6627b..febda61dc 100644 --- a/src/__tests__/gaIntegration/ga-to-split.spec.js +++ b/src/__tests__/gaIntegration/ga-to-split.spec.js @@ -3,6 +3,7 @@ import { SplitFactory } from '../../'; import { settingsFactory } from '../../settings'; import { gaSpy, gaTag, addGaTag, removeGaTag } from './gaTestUtils'; import { url } from '../testUtils'; +import { autoRequireScript } from '@splitsoftware/splitio-commons/src/integrations/ga/GaToSplit'; const config = { @@ -412,4 +413,84 @@ export default function (fetchMock, assert) { }); -} \ No newline at end of file + // test 'autoRequire' script placed manually after GA script tag. + // The behavior is the same if it is placed before GA script tag, and + // also applies for Universal Analytics configured with GTM and gtag.js tags + assert.test(t => { + fetchMock.postOnce(url(settings, '/events/bulk'), (url, opts) => { + const resp = JSON.parse(opts.body); + const sentHitsTracker1 = window.gaSpy.getHits('tracker1'); + const sentHitsTracker2 = window.gaSpy.getHits('tracker2'); + + t.equal(resp.length, sentHitsTracker1.length + sentHitsTracker2.length, 'All hits of all trackers are captured as Split events'); + + setTimeout(() => { + client.destroy(); + t.end(); + }); + return 200; + }); + + gaTag(); + autoRequireScript(); + + window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); + + gaSpy(['tracker1']); + + window.ga('tracker1.send', 'event', 'mycategory', 'myaction1'); // Captured + + const factory = SplitFactory({ + ...config, + integrations: [{ + type: 'GOOGLE_ANALYTICS_TO_SPLIT' + }], + }); + + window.ga('tracker1.send', 'event', 'mycategory', 'myaction2'); // Captured + window.ga('create', 'UA-00000001-1', 'auto', 'tracker2', { siteSpeedSampleRate: 0 }); // New tracker + gaSpy(['tracker2'], false); + window.ga('tracker2.send', 'event', 'mycategory', 'myaction3'); // Captured + + client = factory.client(); + + }); + + // test 'autoRequire' flag. The SDK runs the 'autoRequire' script after the GA script tag and before analytics.js executes + assert.test(t => { + fetchMock.postOnce(url(settings, '/events/bulk'), (url, opts) => { + const resp = JSON.parse(opts.body); + const sentHitsTracker2 = window.gaSpy.getHits('tracker2'); + t.equal(resp.length, sentHitsTracker2.length, 'Only tracker2 hits are captured as Split events'); + + setTimeout(() => { + client.destroy(); + t.end(); + }); + return 200; + }); + + gaTag(); + + // SDK autoRequire is not able to capture hits from trackers which 'create' command is queued before SplitFactory is executed + window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); + window.ga('tracker1.send', 'event', 'mycategory', 'myaction1'); // No captured + + const factory = SplitFactory({ + ...config, + integrations: [{ + type: 'GOOGLE_ANALYTICS_TO_SPLIT', + autoRequire: true, + }], + }); + + window.ga('tracker1.send', 'event', 'mycategory', 'myaction2'); // No captured + window.ga('create', 'UA-00000001-1', 'auto', 'tracker2', { siteSpeedSampleRate: 0 }); // New tracker + gaSpy(['tracker2']); + window.ga('tracker2.send', 'event', 'mycategory', 'myaction3'); // Captured + + client = factory.client(); + + }); + +} diff --git a/src/__tests__/gaIntegration/gaTestUtils.js b/src/__tests__/gaIntegration/gaTestUtils.js index 2f607034c..90b0a9aed 100644 --- a/src/__tests__/gaIntegration/gaTestUtils.js +++ b/src/__tests__/gaIntegration/gaTestUtils.js @@ -2,6 +2,9 @@ export const DEFAULT_TRACKER = 't0'; const HIT_FIELDS = ['hitType', 'nonInteraction']; const EVENT_FIELDS = ['eventCategory', 'eventAction', 'eventLabel', 'eventValue']; +const FIELDS = [...HIT_FIELDS, ...EVENT_FIELDS]; + +let hits = {}; /** * Spy ga hits per tracker. @@ -12,9 +15,9 @@ const EVENT_FIELDS = ['eventCategory', 'eventAction', 'eventLabel', 'eventValue' * * @see {@link https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference} */ -export function gaSpy(trackerNames = [DEFAULT_TRACKER], fieldNames = [...HIT_FIELDS, ...EVENT_FIELDS]) { +export function gaSpy(trackerNames = [DEFAULT_TRACKER], resetSpy = true) { - const hits = {}; + if (resetSpy) hits = {}; // access ga via its gaAlias, accounting for the possibility that the global command queue // has been renamed or not yet defined (analytics.js mutates window[gaAlias] reference) @@ -31,7 +34,7 @@ export function gaSpy(trackerNames = [DEFAULT_TRACKER], fieldNames = [...HIT_FIE trackerToSniff.set('sendHitTask', function (model) { originalSendHitTask(model); const hit = {}; - fieldNames.forEach(fieldName => { + FIELDS.forEach(fieldName => { hit[fieldName] = model.get(fieldName); }); hits[trackerName].push(hit); diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 87675e575..be31d1dba 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.19.0'; +export const packageVersion = '10.19.1-rc1'; From 6a6baa7cd8c6f8bf5ec7eb545315bb8b17f7b0d7 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 15 Jun 2022 17:53:46 -0300 Subject: [PATCH 02/25] prepare rc --- package-lock.json | 8 +-- package.json | 4 +- .../gaIntegration/ga-to-split.spec.js | 50 +++---------------- src/settings/defaults/version.js | 2 +- ts-tests/index.ts | 1 + types/splitio.d.ts | 11 ++++ 6 files changed, 26 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index c94de0955..45b732325 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.1", + "version": "10.19.2-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -437,9 +437,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.1.tgz", - "integrity": "sha512-ukgiyi8Ga3wW0jiwVLMadgcShmqWO/IiQFDkoKIBkUF3H7ri9/deShJWHBMVldpLD+uLbgmzOPXwO8okwQqyKA==", + "version": "1.4.2-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.4.2-rc.0.tgz", + "integrity": "sha512-zUz6MLOD+Mgtm+iT6en9ltdGv4smS3fniMqmKloqR0/M7GO29x8lU6rQL/SzJtcM3c7nY3xip+NCxoRYxjT5EQ==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index 3db45b5bf..cfb55b753 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.1", + "version": "10.19.2-rc.0", "description": "Split SDK", "files": [ "README.md", @@ -32,7 +32,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.4.1", + "@splitsoftware/splitio-commons": "1.4.2-rc.0", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/__tests__/gaIntegration/ga-to-split.spec.js b/src/__tests__/gaIntegration/ga-to-split.spec.js index febda61dc..e71de5109 100644 --- a/src/__tests__/gaIntegration/ga-to-split.spec.js +++ b/src/__tests__/gaIntegration/ga-to-split.spec.js @@ -3,7 +3,7 @@ import { SplitFactory } from '../../'; import { settingsFactory } from '../../settings'; import { gaSpy, gaTag, addGaTag, removeGaTag } from './gaTestUtils'; import { url } from '../testUtils'; -import { autoRequireScript } from '@splitsoftware/splitio-commons/src/integrations/ga/GaToSplit'; +import { autoRequire } from '@splitsoftware/splitio-commons/src/integrations/ga/autoRequire'; const config = { @@ -413,9 +413,9 @@ export default function (fetchMock, assert) { }); - // test 'autoRequire' script placed manually after GA script tag. - // The behavior is the same if it is placed before GA script tag, and - // also applies for Universal Analytics configured with GTM and gtag.js tags + // test 'autoRequire' script placed right after GA script tag. + // We get same result if it is placed right before, and also applies for Universal Analytics configured with GTM and gtag.js tags. + // If it is executed asynchronously, trackers creation might be missed. assert.test(t => { fetchMock.postOnce(url(settings, '/events/bulk'), (url, opts) => { const resp = JSON.parse(opts.body); @@ -432,7 +432,7 @@ export default function (fetchMock, assert) { }); gaTag(); - autoRequireScript(); + autoRequire(); window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); @@ -443,7 +443,8 @@ export default function (fetchMock, assert) { const factory = SplitFactory({ ...config, integrations: [{ - type: 'GOOGLE_ANALYTICS_TO_SPLIT' + type: 'GOOGLE_ANALYTICS_TO_SPLIT', + autoRequire: true }], }); @@ -456,41 +457,4 @@ export default function (fetchMock, assert) { }); - // test 'autoRequire' flag. The SDK runs the 'autoRequire' script after the GA script tag and before analytics.js executes - assert.test(t => { - fetchMock.postOnce(url(settings, '/events/bulk'), (url, opts) => { - const resp = JSON.parse(opts.body); - const sentHitsTracker2 = window.gaSpy.getHits('tracker2'); - t.equal(resp.length, sentHitsTracker2.length, 'Only tracker2 hits are captured as Split events'); - - setTimeout(() => { - client.destroy(); - t.end(); - }); - return 200; - }); - - gaTag(); - - // SDK autoRequire is not able to capture hits from trackers which 'create' command is queued before SplitFactory is executed - window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); - window.ga('tracker1.send', 'event', 'mycategory', 'myaction1'); // No captured - - const factory = SplitFactory({ - ...config, - integrations: [{ - type: 'GOOGLE_ANALYTICS_TO_SPLIT', - autoRequire: true, - }], - }); - - window.ga('tracker1.send', 'event', 'mycategory', 'myaction2'); // No captured - window.ga('create', 'UA-00000001-1', 'auto', 'tracker2', { siteSpeedSampleRate: 0 }); // New tracker - gaSpy(['tracker2']); - window.ga('tracker2.send', 'event', 'mycategory', 'myaction3'); // Captured - - client = factory.client(); - - }); - } diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index c04241d9a..26f4b9c18 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.19.1'; +export const packageVersion = '10.19.2-rc.0'; diff --git a/ts-tests/index.ts b/ts-tests/index.ts index 27926f4fc..31d3416c7 100644 --- a/ts-tests/index.ts +++ b/ts-tests/index.ts @@ -456,6 +456,7 @@ let customGoogleAnalyticsToSplitConfig: SplitIO.IGoogleAnalyticsToSplitConfig = mapper: function (model: UniversalAnalytics.Model, defaultMapping: SplitIO.EventData): SplitIO.EventData { return eventDataSample; }, prefix: 'PREFIX', identities: [{ key: 'key1', trafficType: 'tt1' }, { key: 'key2', trafficType: 'tt2' }], + autoRequire: true }; let customSplitToGoogleAnalyticsConfig: SplitIO.ISplitToGoogleAnalyticsConfig = { type: 'SPLIT_TO_GOOGLE_ANALYTICS', diff --git a/types/splitio.d.ts b/types/splitio.d.ts index 7a3a44398..5ad98b12a 100644 --- a/types/splitio.d.ts +++ b/types/splitio.d.ts @@ -758,6 +758,17 @@ declare namespace SplitIO { * If not provided, events are sent using the key and traffic type provided at SDK config */ identities?: Identity[], + /** + * Optional flag to log an error if the `auto-require` script is not detected. + * The auto-require script automatically requires the `splitTracker` plugin for created trackers, + * and should be placed right after your Google Analytics, GTM or gtag.js script tag. + * + * @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-tag-manager} + * + * @property {boolean} autoRequire + * @default false + */ + autoRequire?: boolean, } /** * Object representing the data sent by Split (events and impressions). From 3b372d77de74d1625a8d84879607f9338edf88d8 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 11:50:11 -0300 Subject: [PATCH 03/25] build script --- .github/workflows/ci-cd.yml | 3 +++ package.json | 4 +++- src/__tests__/gaIntegration/ga-to-split.spec.js | 6 ++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 4c5823a52..3dfa9435c 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -50,6 +50,9 @@ jobs: - name: npm Build run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build + - name: npm Build GaToSplit auto-require script + run: npm run build:gaToSplitAutoRequire + - name: Configure AWS credentials (development) if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} uses: aws-actions/configure-aws-credentials@v1 diff --git a/package.json b/package.json index cfb55b753..dc5ee6ec3 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "lib", "types", "es", - "src" + "src", + "scripts/GaToSplitAutoRequire" ], "repository": "splitio/javascript-client", "homepage": "https://github.com/splitio/javascript-client#readme", @@ -83,6 +84,7 @@ "postbuild-cjs": "cross-env NODE_ENV=cjs node scripts/copy.packages.json.js && ./scripts/build_cjs_replace_imports.sh", "build-umd": "webpack --config webpack.dev.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && webpack --config webpack.prod.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && ./scripts/clean_umd_build.sh", "build:npm": "rimraf lib es && npm run build-cjs && npm run build-esm", + "build:gaToSplitAutoRequire": "terser ./node_modules/@splitsoftware/splitio-commons/src/integrations/ga/autoRequire.js --output ./scripts/GaToSplitAutoRequire/index.js && cp ./scripts/GaToSplitAutoRequire/index.js umd/GaToSplitAutoRequire.js", "build": "rimraf lib umd es && npm run build-cjs && npm run build-esm && npm run build-umd", "check": "npm run check:lint && npm run check:version", "check:lint": "eslint src", diff --git a/src/__tests__/gaIntegration/ga-to-split.spec.js b/src/__tests__/gaIntegration/ga-to-split.spec.js index e71de5109..b759ed1be 100644 --- a/src/__tests__/gaIntegration/ga-to-split.spec.js +++ b/src/__tests__/gaIntegration/ga-to-split.spec.js @@ -3,7 +3,6 @@ import { SplitFactory } from '../../'; import { settingsFactory } from '../../settings'; import { gaSpy, gaTag, addGaTag, removeGaTag } from './gaTestUtils'; import { url } from '../testUtils'; -import { autoRequire } from '@splitsoftware/splitio-commons/src/integrations/ga/autoRequire'; const config = { @@ -432,7 +431,10 @@ export default function (fetchMock, assert) { }); gaTag(); - autoRequire(); + + // Run autoRequire iife: + // require('@splitsoftware/splitio-commons/src/integrations/ga/autoRequire'); + require('../../../scripts/GaToSplitAutoRequire'); window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); From 5ca86a9b8998fad70b1737af31be4fbafefd4b7a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 11:52:02 -0300 Subject: [PATCH 04/25] 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 bbc29e56538084f9263ec3838770827edf65ee11 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 11:54:57 -0300 Subject: [PATCH 05/25] autoRequire script --- scripts/GaToSplitAutoRequire/index.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 scripts/GaToSplitAutoRequire/index.js diff --git a/scripts/GaToSplitAutoRequire/index.js b/scripts/GaToSplitAutoRequire/index.js new file mode 100644 index 000000000..ac220f535 --- /dev/null +++ b/scripts/GaToSplitAutoRequire/index.js @@ -0,0 +1 @@ +(function(i,r,s){i[s]=i[s]||r;i[r]=i[r]||function(){i[r].q.push(arguments)};i[r].q=i[r].q||[];var ts={};function n(arg){return typeof arg==="object"&&typeof arg.name==="string"&&arg.name}function p(v){if(v&&v[0]==="create"){var t=n(v[1])||n(v[2])||n(v[3])||(typeof v[3]==="string"?v[3]:undefined);if(!ts[t]){ts[t]=true;i[r]((t?t+".":"")+"require","splitTracker")}}}i[r].q.forEach((function(v){p(v)}));var o=i[r].q.push;i[r].q.push=function(v){var result=o.apply(this,arguments);p(v);return result}})(window,"ga","GoogleAnalyticsObject"); \ No newline at end of file From 2f45882e884355a1da71d174fdf7c4bf69e03eb8 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 11:56:15 -0300 Subject: [PATCH 06/25] prepare rc --- package-lock.json | 2 +- package.json | 2 +- src/settings/defaults/version.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a93c5d6c9..bda07275c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.2-rc.2", + "version": "10.19.2-rc.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3c5f2bc6f..ce7370d31 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.2-rc.2", + "version": "10.19.2-rc.3", "description": "Split SDK", "files": [ "README.md", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 3d1f3dd7d..bdee3772a 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.19.2-rc.2'; +export const packageVersion = '10.19.2-rc.3'; From 4ad1d174c6b536e9c4e1726610786fba4d655ce7 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 14:39:36 -0300 Subject: [PATCH 07/25] prepare rc --- .github/workflows/ci-cd.yml | 2 +- package-lock.json | 2 +- package.json | 6 +++--- .../index.js => ga-to-split-autorequire.js} | 0 src/settings/defaults/version.js | 2 +- types/splitio.d.ts | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) rename scripts/{GaToSplitAutoRequire/index.js => ga-to-split-autorequire.js} (100%) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 3dfa9435c..03b9406e2 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,7 +51,7 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: npm Build GaToSplit auto-require script - run: npm run build:gaToSplitAutoRequire + run: npm run build:ga-to-split-autorequire - name: Configure AWS credentials (development) if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} diff --git a/package-lock.json b/package-lock.json index bda07275c..08a0aca8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.2-rc.3", + "version": "10.19.2-rc.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ce7370d31..a9bfbaaf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.19.2-rc.3", + "version": "10.19.2-rc.4", "description": "Split SDK", "files": [ "README.md", @@ -11,7 +11,7 @@ "types", "es", "src", - "scripts/GaToSplitAutoRequire" + "scripts/ga-to-split-autorequire.js" ], "repository": "splitio/javascript-client", "homepage": "https://github.com/splitio/javascript-client#readme", @@ -84,7 +84,7 @@ "postbuild-cjs": "cross-env NODE_ENV=cjs node scripts/copy.packages.json.js && ./scripts/build_cjs_replace_imports.sh", "build-umd": "webpack --config webpack.dev.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && webpack --config webpack.prod.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && ./scripts/clean_umd_build.sh", "build:npm": "rimraf lib es && npm run build-cjs && npm run build-esm", - "build:gaToSplitAutoRequire": "terser ./node_modules/@splitsoftware/splitio-commons/src/integrations/ga/autoRequire.js --output ./scripts/GaToSplitAutoRequire/index.js && cp ./scripts/GaToSplitAutoRequire/index.js umd/GaToSplitAutoRequire.js", + "build:ga-to-split-autorequire": "terser ./node_modules/@splitsoftware/splitio-commons/src/integrations/ga/autoRequire.js --output ./scripts/ga-to-split-autorequire.js && cp ./scripts/ga-to-split-autorequire.js umd/ga-to-split-autorequire.js", "build": "rimraf lib umd es && npm run build-cjs && npm run build-esm && npm run build-umd", "check": "npm run check:lint && npm run check:version", "check:lint": "eslint src", diff --git a/scripts/GaToSplitAutoRequire/index.js b/scripts/ga-to-split-autorequire.js similarity index 100% rename from scripts/GaToSplitAutoRequire/index.js rename to scripts/ga-to-split-autorequire.js diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index bdee3772a..333a2b265 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.19.2-rc.3'; +export const packageVersion = '10.19.2-rc.4'; diff --git a/types/splitio.d.ts b/types/splitio.d.ts index 1885d111f..b18c238fc 100644 --- a/types/splitio.d.ts +++ b/types/splitio.d.ts @@ -761,9 +761,9 @@ declare namespace SplitIO { /** * Optional flag to log an error if the `auto-require` script is not detected. * The auto-require script automatically requires the `splitTracker` plugin for created trackers, - * and should be placed right after your Google Analytics, GTM or gtag.js script tag. + * and should be placed right after your Google Analytics, Google Tag Manager or gtag.js script tag. * - * @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-tag-manager} + * @see {@link https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js} * * @property {boolean} autoRequire * @default false From 1db9f6374aa8131641fb9d088da144b9f9e43845 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 15:40:24 -0300 Subject: [PATCH 08/25] fix e2e test --- src/__tests__/gaIntegration/ga-to-split.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/gaIntegration/ga-to-split.spec.js b/src/__tests__/gaIntegration/ga-to-split.spec.js index b759ed1be..747f80642 100644 --- a/src/__tests__/gaIntegration/ga-to-split.spec.js +++ b/src/__tests__/gaIntegration/ga-to-split.spec.js @@ -434,7 +434,7 @@ export default function (fetchMock, assert) { // Run autoRequire iife: // require('@splitsoftware/splitio-commons/src/integrations/ga/autoRequire'); - require('../../../scripts/GaToSplitAutoRequire'); + require('../../../scripts/ga-to-split-autorequire'); window.ga('create', 'UA-00000000-1', { name: 'tracker1', cookieDomain: 'auto', siteSpeedSampleRate: 0 }); From 7c4c31d9f36125d0c71ec3860b57e0e9aa93e05a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Jun 2022 17:27:46 -0300 Subject: [PATCH 09/25] polishing --- package.json | 2 +- scripts/ga-to-split-autorequire.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a9bfbaaf7..3b317ce73 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "postbuild-cjs": "cross-env NODE_ENV=cjs node scripts/copy.packages.json.js && ./scripts/build_cjs_replace_imports.sh", "build-umd": "webpack --config webpack.dev.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && webpack --config webpack.prod.js --env branch=$BUILD_BRANCH --env commit_hash=$BUILD_COMMIT && ./scripts/clean_umd_build.sh", "build:npm": "rimraf lib es && npm run build-cjs && npm run build-esm", - "build:ga-to-split-autorequire": "terser ./node_modules/@splitsoftware/splitio-commons/src/integrations/ga/autoRequire.js --output ./scripts/ga-to-split-autorequire.js && cp ./scripts/ga-to-split-autorequire.js umd/ga-to-split-autorequire.js", + "build:ga-to-split-autorequire": "terser ./node_modules/@splitsoftware/splitio-commons/src/integrations/ga/autoRequire.js --mangle --output ./scripts/ga-to-split-autorequire.js && cp ./scripts/ga-to-split-autorequire.js umd/ga-to-split-autorequire.js", "build": "rimraf lib umd es && npm run build-cjs && npm run build-esm && npm run build-umd", "check": "npm run check:lint && npm run check:version", "check:lint": "eslint src", diff --git a/scripts/ga-to-split-autorequire.js b/scripts/ga-to-split-autorequire.js index ac220f535..7f8b88597 100644 --- a/scripts/ga-to-split-autorequire.js +++ b/scripts/ga-to-split-autorequire.js @@ -1 +1 @@ -(function(i,r,s){i[s]=i[s]||r;i[r]=i[r]||function(){i[r].q.push(arguments)};i[r].q=i[r].q||[];var ts={};function n(arg){return typeof arg==="object"&&typeof arg.name==="string"&&arg.name}function p(v){if(v&&v[0]==="create"){var t=n(v[1])||n(v[2])||n(v[3])||(typeof v[3]==="string"?v[3]:undefined);if(!ts[t]){ts[t]=true;i[r]((t?t+".":"")+"require","splitTracker")}}}i[r].q.forEach((function(v){p(v)}));var o=i[r].q.push;i[r].q.push=function(v){var result=o.apply(this,arguments);p(v);return result}})(window,"ga","GoogleAnalyticsObject"); \ No newline at end of file +(function(n,t,e){n[e]=n[e]||t;n[t]=n[t]||function(){n[t].q.push(arguments)};n[t].q=n[t].q||[];var r={};function i(n){return typeof n==="object"&&typeof n.name==="string"&&n.name}function o(e){if(e&&e[0]==="create"){var o=i(e[1])||i(e[2])||i(e[3])||(typeof e[3]==="string"?e[3]:undefined);if(!r[o]){r[o]=true;n[t]((o?o+".":"")+"require","splitTracker")}}}n[t].q.forEach(o);var u=n[t].q.push;n[t].q.push=function(n){var t=u.apply(this,arguments);o(n);return t}})(window,"ga","GoogleAnalyticsObject"); \ 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 10/25] 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 11/25] 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')); } From 9b46d4d7bd6248950cf74cdc1c5d9034137eb7b6 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 5 Jul 2022 18:29:30 -0300 Subject: [PATCH 12/25] rc --- .github/workflows/ci-cd.yml | 4 ++-- package-lock.json | 2 +- package.json | 2 +- src/settings/defaults/version.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 7b5cb50ea..03b9406e2 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -54,14 +54,14 @@ jobs: run: npm run build:ga-to-split-autorequire - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/package-lock.json b/package-lock.json index b82e8de45..19d887392 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.0", + "version": "10.20.1-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index df6c1d2e7..79e50e66d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.0", + "version": "10.20.1-rc.0", "description": "Split SDK", "files": [ "README.md", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index ac6e8280b..7908298c8 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.20.0'; +export const packageVersion = '10.20.1-rc.0'; From 57a84a87523d868ff51323fc778b66aeeb5ba8ef Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 8 Jul 2022 14:19:55 -0300 Subject: [PATCH 13/25] update tests --- .../browserSuites/push-synchronization-retries.spec.js | 7 +++---- .../nodeSuites/push-synchronization-retries.spec.js | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/__tests__/browserSuites/push-synchronization-retries.spec.js b/src/__tests__/browserSuites/push-synchronization-retries.spec.js index 5839264e3..5daff1bd3 100644 --- a/src/__tests__/browserSuites/push-synchronization-retries.spec.js +++ b/src/__tests__/browserSuites/push-synchronization-retries.spec.js @@ -76,9 +76,8 @@ const MILLIS_THIRD_RETRY_FOR_SPLIT_KILL_EVENT = 2000; * (we destroy the client here, to assert that all scheduled tasks are clean) */ export function testSynchronizationRetries(fetchMock, assert) { - // we update the backoff default base, to reduce the time of the test - const ORIGINAL_DEFAULT_BASE_MILLIS = Backoff.DEFAULT_BASE_MILLIS; - Backoff.DEFAULT_BASE_MILLIS = 100; + // we force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce the time of the test + Backoff.__TEST__BASE_MILLIS = 100; assert.plan(17); fetchMock.reset(); @@ -196,7 +195,7 @@ export function testSynchronizationRetries(fetchMock, assert) { setTimeout(() => { Promise.all([otherClientSync.destroy(), client.destroy()]).then(() => { assert.equal(client.getTreatment('whitelist'), 'control', 'evaluation returns control if client is destroyed'); - Backoff.DEFAULT_BASE_MILLIS = ORIGINAL_DEFAULT_BASE_MILLIS; + Backoff.__TEST__BASE_MILLIS = undefined; assert.end(); }); }); diff --git a/src/__tests__/nodeSuites/push-synchronization-retries.spec.js b/src/__tests__/nodeSuites/push-synchronization-retries.spec.js index fce201003..3920d913b 100644 --- a/src/__tests__/nodeSuites/push-synchronization-retries.spec.js +++ b/src/__tests__/nodeSuites/push-synchronization-retries.spec.js @@ -70,9 +70,8 @@ const MILLIS_THIRD_RETRY_FOR_SPLIT_KILL_EVENT = 2000; * (we destroy the client here, to assert that all scheduled tasks are clean) */ export function testSynchronizationRetries(fetchMock, assert) { - // we update the backoff default base, to reduce the time of the test - const ORIGINAL_DEFAULT_BASE_MILLIS = Backoff.DEFAULT_BASE_MILLIS; - Backoff.DEFAULT_BASE_MILLIS = 100; + // we force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce the time of the test + Backoff.__TEST__BASE_MILLIS = 100; assert.plan(19); fetchMock.reset(); @@ -201,7 +200,7 @@ export function testSynchronizationRetries(fetchMock, assert) { setTimeout(() => { client.destroy().then(() => { assert.equal(client.getTreatment(key, 'whitelist'), 'control', 'evaluation returns control if client is destroyed'); - Backoff.DEFAULT_BASE_MILLIS = ORIGINAL_DEFAULT_BASE_MILLIS; + Backoff.__TEST__BASE_MILLIS = undefined; assert.end(); }); }); From df3ce44c507de69109682ef87c4ad2458d0c7249 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Sun, 17 Jul 2022 00:15:08 -0300 Subject: [PATCH 14/25] update tests after fixing syncTask in JS-commons --- src/__tests__/browserSuites/impressions.debug.spec.js | 10 +++++----- src/__tests__/browserSuites/impressions.spec.js | 7 +++---- .../browserSuites/push-synchronization-retries.spec.js | 2 +- src/__tests__/nodeSuites/impressions.debug.spec.js | 5 ++--- src/__tests__/nodeSuites/impressions.spec.js | 1 - .../nodeSuites/push-synchronization-retries.spec.js | 2 +- src/__tests__/nodeSuites/push-synchronization.spec.js | 2 +- 7 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/__tests__/browserSuites/impressions.debug.spec.js b/src/__tests__/browserSuites/impressions.debug.spec.js index a4b182dce..bbccfc9db 100644 --- a/src/__tests__/browserSuites/impressions.debug.spec.js +++ b/src/__tests__/browserSuites/impressions.debug.spec.js @@ -7,8 +7,8 @@ import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants'; import { url } from '../testUtils'; const baseUrls = { - sdk: 'https://sdk.baseurl/impressionsSuite', - events: 'https://events.baseurl/impressionsSuite' + sdk: 'https://sdk.baseurl/impressionsDebugSuite', + events: 'https://events.baseurl/impressionsDebugSuite' }; const settings = settingsFactory({ @@ -83,12 +83,12 @@ export default function (fetchMock, assert) { assert.equal(req.headers.SplitSDKImpressionsMode, DEBUG); assertPayload(req); - client.destroy(); - assert.end(); + client.destroy().then(() => { + assert.end(); + }); return 200; }); - fetchMock.postOnce(url(settings, '/testImpressions/bulk'), 200); client.ready().then(() => { client.getTreatment('split_with_config'); diff --git a/src/__tests__/browserSuites/impressions.spec.js b/src/__tests__/browserSuites/impressions.spec.js index e5ebb5092..8e73c5df2 100644 --- a/src/__tests__/browserSuites/impressions.spec.js +++ b/src/__tests__/browserSuites/impressions.spec.js @@ -84,12 +84,12 @@ export default function (fetchMock, assert) { assert.comment('We do one retry, so after a failed impressions post we will try once more.'); assertPayload(req); - client.destroy(); - assert.end(); + client.destroy().then(() => { + assert.end(); + }); return 200; }); - fetchMock.postOnce(url(settings, '/testImpressions/bulk'), 200); fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { const data = JSON.parse(opts.body); @@ -109,7 +109,6 @@ export default function (fetchMock, assert) { return 200; }); - fetchMock.postOnce(url(settings, '/testImpressions/count'), 200); client.ready().then(() => { truncatedTimeFrame = truncateTimeFrame(Date.now()); diff --git a/src/__tests__/browserSuites/push-synchronization-retries.spec.js b/src/__tests__/browserSuites/push-synchronization-retries.spec.js index 5daff1bd3..03c79554f 100644 --- a/src/__tests__/browserSuites/push-synchronization-retries.spec.js +++ b/src/__tests__/browserSuites/push-synchronization-retries.spec.js @@ -76,7 +76,7 @@ const MILLIS_THIRD_RETRY_FOR_SPLIT_KILL_EVENT = 2000; * (we destroy the client here, to assert that all scheduled tasks are clean) */ export function testSynchronizationRetries(fetchMock, assert) { - // we force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce the time of the test + // Force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce test time Backoff.__TEST__BASE_MILLIS = 100; assert.plan(17); diff --git a/src/__tests__/nodeSuites/impressions.debug.spec.js b/src/__tests__/nodeSuites/impressions.debug.spec.js index 2005d96c4..5c10f8065 100644 --- a/src/__tests__/nodeSuites/impressions.debug.spec.js +++ b/src/__tests__/nodeSuites/impressions.debug.spec.js @@ -6,8 +6,8 @@ import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants'; import { url } from '../testUtils'; const baseUrls = { - sdk: 'https://sdk.baseurl/impressionsSuite', - events: 'https://events.baseurl/impressionsSuite' + sdk: 'https://sdk.baseurl/impressionsDebugSuite', + events: 'https://events.baseurl/impressionsDebugSuite' }; const settings = settingsFactory({ @@ -88,7 +88,6 @@ export default async function (key, fetchMock, assert) { return 200; }); - fetchMock.postOnce(url(settings, '/testImpressions/bulk'), 200); splitio.Logger.enable(); evaluationsStart = Date.now(); diff --git a/src/__tests__/nodeSuites/impressions.spec.js b/src/__tests__/nodeSuites/impressions.spec.js index 21324b560..098aefdf2 100644 --- a/src/__tests__/nodeSuites/impressions.spec.js +++ b/src/__tests__/nodeSuites/impressions.spec.js @@ -101,7 +101,6 @@ export default async function(key, fetchMock, assert) { return 200; }); - fetchMock.postOnce(url(settings, '/testImpressions/bulk'), 200); fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { const data = JSON.parse(opts.body); diff --git a/src/__tests__/nodeSuites/push-synchronization-retries.spec.js b/src/__tests__/nodeSuites/push-synchronization-retries.spec.js index 3920d913b..3e71548d6 100644 --- a/src/__tests__/nodeSuites/push-synchronization-retries.spec.js +++ b/src/__tests__/nodeSuites/push-synchronization-retries.spec.js @@ -70,7 +70,7 @@ const MILLIS_THIRD_RETRY_FOR_SPLIT_KILL_EVENT = 2000; * (we destroy the client here, to assert that all scheduled tasks are clean) */ export function testSynchronizationRetries(fetchMock, assert) { - // we force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce the time of the test + // Force the backoff base of UpdateWorkers, from 10 secs to 100 ms, to reduce test time Backoff.__TEST__BASE_MILLIS = 100; assert.plan(19); diff --git a/src/__tests__/nodeSuites/push-synchronization.spec.js b/src/__tests__/nodeSuites/push-synchronization.spec.js index d4857c8f8..e3e078237 100644 --- a/src/__tests__/nodeSuites/push-synchronization.spec.js +++ b/src/__tests__/nodeSuites/push-synchronization.spec.js @@ -128,7 +128,7 @@ export function testSynchronization(fetchMock, assert) { assert.equal(sdkUpdateCount, 5, 'SDK_UPDATE should be emitted 5 times'); assert.end(); }); - }, MILLIS_DESTROY); // destroy client after 0.6 seconds + }, MILLIS_DESTROY); // destroy client after 0.7 seconds }); // initial auth From 524e65b74b67c5121a15596c4447321d9146b7af Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 18 Jul 2022 13:09:46 -0300 Subject: [PATCH 15/25] rc --- .github/workflows/ci-cd.yml | 4 ++-- package-lock.json | 8 ++++---- package.json | 4 ++-- src/settings/defaults/version.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f6fd86ccb..571adc817 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,14 +51,14 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cdn_bypass_tests' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cdn_bypass_tests' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/package-lock.json b/package-lock.json index b82e8de45..4d76631aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.0", + "version": "10.20.1-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -437,9 +437,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "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==", + "version": "1.5.1-rc.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.1-rc.1.tgz", + "integrity": "sha512-NeVreo+igjYrlcWPq0gMEyE6QTxSv906S96X1XmibP/vcJFS90E9Vbr4GAAZKxrV0qh2FC5nMoGtYD7T4nhlhQ==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index 7d7cf2bfa..0ef414091 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.0", + "version": "10.20.1-rc.0", "description": "Split SDK", "files": [ "README.md", @@ -32,7 +32,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.5.1-rc.0", + "@splitsoftware/splitio-commons": "1.5.1-rc.1", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index ac6e8280b..7908298c8 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.20.0'; +export const packageVersion = '10.20.1-rc.0'; From ec391451aaf9547a9a5a9c156edcff4a6a9f3f5f Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 18 Jul 2022 14:06:53 -0300 Subject: [PATCH 16/25] rc --- package-lock.json | 2 +- package.json | 2 +- src/settings/defaults/version.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d76631aa..3d7a25286 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.0", + "version": "10.20.1-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0ef414091..3498b0307 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.0", + "version": "10.20.1-rc.1", "description": "Split SDK", "files": [ "README.md", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 7908298c8..a6018f44e 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.20.1-rc.0'; +export const packageVersion = '10.20.1-rc.1'; From 70c696183ba718607f3314ac564cb560012aa83c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 18 Jul 2022 18:26:05 -0300 Subject: [PATCH 17/25] Added changelog entry --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 9b549227d..2f7707f34 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +10.20.1 (July XX, 2022) +- Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in mobile and modern Web browsers (See https://developer.chrome.com/blog/page-lifecycle-api/#legacy-lifecycle-apis-to-avoid). +- Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced. + 10.20.0 (June 29, 2022) - Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used. - Updated telemetry logic to track the anonymous config for user consent flag set to declined or unknown. From be5610ae995857df4976407e571fcda6f3d712bd Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 19 Jul 2022 17:15:42 -0300 Subject: [PATCH 18/25] reduce tests flakiness due to telemetry sample rate --- package-lock.json | 28 ++++++++++----------- src/__tests__/browser.spec.js | 8 +++--- src/__tests__/destroy/browser.spec.js | 2 +- src/__tests__/gaIntegration/browser.spec.js | 3 ++- src/__tests__/push/browser.spec.js | 1 + 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d7a25286..3e2369204 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1911,7 +1911,7 @@ "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "date-format": { @@ -1992,7 +1992,7 @@ "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "diff": { @@ -2032,7 +2032,7 @@ "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "requires": { "custom-event": "~1.0.0", @@ -2071,7 +2071,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true }, "electron-to-chromium": { @@ -2106,7 +2106,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true }, "end-of-stream": { @@ -2183,7 +2183,7 @@ "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "envinfo": { @@ -2260,7 +2260,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true }, "escape-string-regexp": { @@ -4146,7 +4146,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true }, "merge-descriptors": { @@ -4524,7 +4524,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, "object-inspect": { @@ -5230,7 +5230,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "resolve": { @@ -6234,7 +6234,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true }, "untildify": { @@ -6299,7 +6299,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true }, "v8-compile-cache": { @@ -6317,7 +6317,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, "vm-browserify": { @@ -6329,7 +6329,7 @@ "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true }, "watchpack": { diff --git a/src/__tests__/browser.spec.js b/src/__tests__/browser.spec.js index 73a2b2a32..2c396b437 100644 --- a/src/__tests__/browser.spec.js +++ b/src/__tests__/browser.spec.js @@ -8,10 +8,7 @@ import telemetrySuite from './browserSuites/telemetry.spec'; import impressionsListenerSuite from './browserSuites/impressions-listener.spec'; import readinessSuite from './browserSuites/readiness.spec'; import readyFromCache from './browserSuites/ready-from-cache.spec'; -import { - withoutBindingTT, - bindingTT -} from './browserSuites/events.spec'; +import { withoutBindingTT, bindingTT } from './browserSuites/events.spec'; import sharedInstantiationSuite from './browserSuites/shared-instantiation.spec'; import managerSuite from './browserSuites/manager.spec'; import ignoreIpAddressesSettingSuite from './browserSuites/ignore-ip-addresses-setting.spec'; @@ -84,7 +81,7 @@ const configInLocalStorage = { streamingEnabled: false }; -tape('## E2E CI Tests ##', function(assert) { +tape('## E2E CI Tests ##', function (assert) { //If we change the mocks, we need to clear localstorage. Cleaning up after testing ensures "fresh data". localStorage.clear(); @@ -96,6 +93,7 @@ tape('## E2E CI Tests ##', function(assert) { fetchMock.get(url(settings, '/mySegments/emmanuel%40split.io'), { status: 200, body: mySegmentsEmmanuel }); fetchMock.post(url(settings, '/testImpressions/bulk'), 200); fetchMock.post(url(settings, '/testImpressions/count'), 200); + Math.random = () => 0.5; // SDKs without telemetry /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, configInMemory, fetchMock)); diff --git a/src/__tests__/destroy/browser.spec.js b/src/__tests__/destroy/browser.spec.js index e61e9aaf0..167ca78fc 100644 --- a/src/__tests__/destroy/browser.spec.js +++ b/src/__tests__/destroy/browser.spec.js @@ -20,10 +20,10 @@ const settings = settingsFactory({ fetchMock.getOnce(url(settings, '/splitChanges?since=-1'), { status: 200, body: splitChangesMock1 }); fetchMock.getOnce(url(settings, '/splitChanges?since=-1500492097547'), { status: 200, body: splitChangesMock2 }); - fetchMock.getOnce(url(settings, '/mySegments/ut1'), { status: 200, body: mySegmentsMock }); fetchMock.getOnce(url(settings, '/mySegments/ut2'), { status: 200, body: mySegmentsMock }); fetchMock.getOnce(url(settings, '/mySegments/ut3'), { status: 200, body: mySegmentsMock }); +fetchMock.postOnce(url(settings, '/v1/metrics/config'), 200); // 0.1% sample rate tape('SDK destroy for BrowserJS', async function (assert) { const config = { diff --git a/src/__tests__/gaIntegration/browser.spec.js b/src/__tests__/gaIntegration/browser.spec.js index 02d96ae94..6d61aea16 100644 --- a/src/__tests__/gaIntegration/browser.spec.js +++ b/src/__tests__/gaIntegration/browser.spec.js @@ -16,10 +16,11 @@ const settings = settingsFactory({ } }); -tape('## E2E CI Tests ##', function(assert) { +tape('## E2E CI Tests ##', function (assert) { fetchMock.get(url(settings, '/splitChanges?since=-1'), { status: 200, body: splitChangesMock1 }); fetchMock.get(url(settings, '/mySegments/facundo%40split.io'), { status: 200, body: mySegmentsFacundo }); + fetchMock.post(/\/v1\/metrics/, 200); // 0.1% sample rate /* Validate GA integration */ assert.test('E2E / GA-to-Split', gaToSplitSuite.bind(null, fetchMock)); diff --git a/src/__tests__/push/browser.spec.js b/src/__tests__/push/browser.spec.js index d06c014e7..ecef8596c 100644 --- a/src/__tests__/push/browser.spec.js +++ b/src/__tests__/push/browser.spec.js @@ -9,6 +9,7 @@ import { testRefreshToken } from '../browserSuites/push-refresh-token.spec'; import { testSplitKillOnReadyFromCache } from '../browserSuites/push-corner-cases.spec'; fetchMock.config.overwriteRoutes = false; +Math.random = () => 0.5; // SDKs without telemetry tape('## Browser JS - E2E CI Tests for PUSH ##', function (assert) { From 0d14fb572c49883a8c5350d28d9993b867fb24bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 01:34:07 +0000 Subject: [PATCH 19/25] Bump terser from 5.9.0 to 5.14.2 Bumps [terser](https://github.com/terser/terser) from 5.9.0 to 5.14.2. - [Release notes](https://github.com/terser/terser/releases) - [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md) - [Commits](https://github.com/terser/terser/commits) --- updated-dependencies: - dependency-name: terser dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 102 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index b82e8de45..a8854dfb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -389,6 +389,55 @@ "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@mdn/browser-compat-data": { "version": "3.3.14", "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", @@ -5522,6 +5571,24 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5892,40 +5959,15 @@ } }, "terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - }, - "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - } } }, "terser-webpack-plugin": { From 37916175fdbd2a36865446ae519120d916265c99 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 20 Jul 2022 16:46:08 -0300 Subject: [PATCH 20/25] rollback ci-cd --- .github/workflows/ci-cd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 571adc817..f6fd86ccb 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,14 +51,14 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cdn_bypass_tests' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cdn_bypass_tests' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage From 04ecd9a1ce47ee1b6289b951dd1f67ce4c8d8629 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 20 Jul 2022 17:31:05 -0300 Subject: [PATCH 21/25] added js-yaml dep and LocalhostFromFile module --- .github/workflows/ci-cd.yml | 4 +- CHANGES.txt | 1 + package-lock.json | 8 +- package.json | 6 +- src/settings/defaults/version.js | 2 +- src/settings/node.js | 2 +- src/sync/offline/LocalhostFromFile.js | 11 ++ src/sync/offline/splitsParserFromFile.js | 172 +++++++++++++++++++++++ 8 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 src/sync/offline/LocalhostFromFile.js create mode 100644 src/sync/offline/splitsParserFromFile.js diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f6fd86ccb..d396a49cb 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,14 +51,14 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/refactor_localhostfromfile' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/refactor_localhostfromfile' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/CHANGES.txt b/CHANGES.txt index 2f7707f34..f2d04e412 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,7 @@ 10.20.1 (July XX, 2022) - Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in mobile and modern Web browsers (See https://developer.chrome.com/blog/page-lifecycle-api/#legacy-lifecycle-apis-to-avoid). - Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced. +- Bugfixing - Moved js-yaml dependency from @splitsoftware/splitio-commons to avoid issues in Node v14 when installing third-party dependencies that also uses js-yaml as a transitive dependency (Related to issue https://github.com/splitio/javascript-client/issues/662) 10.20.0 (June 29, 2022) - Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used. diff --git a/package-lock.json b/package-lock.json index f66c48ec7..048740d4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.1", + "version": "10.20.1-rc.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -486,9 +486,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.5.1-rc.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.1-rc.1.tgz", - "integrity": "sha512-NeVreo+igjYrlcWPq0gMEyE6QTxSv906S96X1XmibP/vcJFS90E9Vbr4GAAZKxrV0qh2FC5nMoGtYD7T4nhlhQ==", + "version": "1.5.1-rc.2", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.1-rc.2.tgz", + "integrity": "sha512-0A+SDFhrtjQvFB4nVxVJiil2jKxv2bLLJDiHAtIU8SQA6M98LMQlF59heO6BKoe9C7fKwp466SzyFgpNn2n1RQ==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index 3498b0307..9b574aef3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.1", + "version": "10.20.1-rc.2", "description": "Split SDK", "files": [ "README.md", @@ -32,11 +32,11 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.5.1-rc.1", + "@splitsoftware/splitio-commons": "1.5.1-rc.2", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", - "js-yaml": "3.13.1", + "js-yaml": "^3.13.1", "node-fetch": "^2.6.7", "unfetch": "^4.2.0" }, diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index a6018f44e..454125bbb 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.20.1-rc.1'; +export const packageVersion = '10.20.1-rc.2'; diff --git a/src/settings/node.js b/src/settings/node.js index 00a9a6d45..2dc97cb73 100644 --- a/src/settings/node.js +++ b/src/settings/node.js @@ -1,6 +1,6 @@ import { settingsValidation } from '@splitsoftware/splitio-commons/src/utils/settingsValidation'; import { validateLogger } from '@splitsoftware/splitio-commons/src/utils/settingsValidation/logger/builtinLogger'; -import { LocalhostFromFile } from '@splitsoftware/splitio-commons/src/sync/offline/LocalhostFromFile'; +import { LocalhostFromFile } from '../sync/offline/LocalhostFromFile'; import { defaults } from './defaults/node'; import { validateStorage } from './storage/node'; diff --git a/src/sync/offline/LocalhostFromFile.js b/src/sync/offline/LocalhostFromFile.js new file mode 100644 index 000000000..f5568c327 --- /dev/null +++ b/src/sync/offline/LocalhostFromFile.js @@ -0,0 +1,11 @@ +import { splitsParserFromFileFactory } from './splitsParserFromFile'; +import { syncManagerOfflineFactory } from '@splitsoftware/splitio-commons/src/sync/offline/syncManagerOffline'; + +// Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile) +// Requires Node 'fs' and 'path' APIs. +const localhostFromFile = syncManagerOfflineFactory(splitsParserFromFileFactory); +localhostFromFile.type = 'LocalhostFromFile'; + +export function LocalhostFromFile() { + return localhostFromFile; +} diff --git a/src/sync/offline/splitsParserFromFile.js b/src/sync/offline/splitsParserFromFile.js new file mode 100644 index 000000000..ef25e8e14 --- /dev/null +++ b/src/sync/offline/splitsParserFromFile.js @@ -0,0 +1,172 @@ +import fs from 'fs'; +import path from 'path'; +import yaml from 'js-yaml'; +import { isString, endsWith, find, forOwn, uniq, } from '@splitsoftware/splitio-commons/src/utils/lang'; +import { parseCondition } from '@splitsoftware/splitio-commons/src/sync/offline/splitsParser/parseCondition'; + +const logPrefix = 'sync:offline:splits-fetcher: '; + +const DEFAULT_FILENAME = '.split'; + +function configFilesPath(configFilePath) { + if (configFilePath === DEFAULT_FILENAME || !isString(configFilePath)) { + let root = process.env.HOME; + + if (process.env.SPLIT_CONFIG_ROOT) root = process.env.SPLIT_CONFIG_ROOT; + + if (!root) throw new Error('Missing split mock configuration root.'); + + configFilePath = path.join(root, DEFAULT_FILENAME); + } + + // Validate the extensions + if (!(endsWith(configFilePath, '.yaml', true) || endsWith(configFilePath, '.yml', true) || endsWith(configFilePath, '.split', true))) + throw new Error(`Invalid extension specified for Splits mock file. Accepted extensions are ".yml" and ".yaml". Your specified file is ${configFilePath}`); + + if (!fs.existsSync(configFilePath)) + throw new Error(`Split configuration not found in ${configFilePath} - Please review your Split file location.`); + + return configFilePath; +} + +// This function is not pure nor meant to be. Here we apply modifications to cover +// for behaviour that's ensured by the BE. +function arrangeConditions(mocksData) { + // Iterate through each Split data + forOwn(mocksData, data => { + const conditions = data.conditions; + + // On the manager, as the split jsons come with all treatments on the partitions prop, + // we'll add all the treatments to the first condition. + const firstRolloutCondition = find(conditions, cond => cond.conditionType === 'ROLLOUT'); + // Malformed mocks may have + const treatments = uniq(data.treatments); + // If they're only specifying a whitelist we add the treatments there. + const allTreatmentsCondition = firstRolloutCondition ? firstRolloutCondition : conditions[0]; + + const fullyAllocatedTreatment = allTreatmentsCondition.partitions[0].treatment; + + treatments.forEach(treatment => { + if (treatment !== fullyAllocatedTreatment) { + allTreatmentsCondition.partitions.push({ + treatment, size: 0 + }); + } + }); + + // Don't need these anymore + delete data.treatments; + }); +} + +export function splitsParserFromFileFactory() { + + let previousMock = 'NO_MOCK_LOADED'; + + // Parse `.split` configuration file and return a map of "Split Objects" + function readSplitConfigFile(log, filePath) { + const SPLIT_POSITION = 0; + const TREATMENT_POSITION = 1; + let data; + + try { + data = fs.readFileSync(filePath, 'utf-8'); + } catch (e) { + log.error(e && e.message); + + return {}; + } + + if (data === previousMock) return false; + previousMock = data; + + const splitObjects = data.split(/\r?\n/).reduce((accum, line, index) => { + let tuple = line.trim(); + + if (tuple === '' || tuple.charAt(0) === '#') { + log.debug(logPrefix + `Ignoring empty line or comment at #${index}`); + } else { + tuple = tuple.split(/\s+/); + + if (tuple.length !== 2) { + log.debug(logPrefix + `Ignoring line since it does not have exactly two columns #${index}`); + } else { + const splitName = tuple[SPLIT_POSITION]; + const condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] }); + accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' }; + } + } + + return accum; + }, {}); + + return splitObjects; + } + + // Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects" + function readYAMLConfigFile(log, filePath) { + let data = ''; + let yamldoc = null; + + try { + data = fs.readFileSync(filePath, 'utf8'); + + if (data === previousMock) return false; + previousMock = data; + + yamldoc = yaml.safeLoad(data); + } catch (e) { + log.error(e); + + return {}; + } + + // Each entry will be mapped to a condition, but we'll also keep the configurations map. + const mocksData = (yamldoc).reduce((accum, splitEntry) => { + const splitName = Object.keys(splitEntry)[0]; + + if (!splitName || !isString(splitEntry[splitName].treatment)) + log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.'); + + const mockData = splitEntry[splitName]; + + // "Template" for each split accumulated data + if (!accum[splitName]) { + accum[splitName] = { + configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost' + }; + } + + // Assign the config if there is one on the mock + if (mockData.config) accum[splitName].configurations[mockData.treatment] = mockData.config; + // Parse the condition from the entry. + const condition = parseCondition(mockData); + accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition); + // Also keep track of the treatments, will be useful for manager functionality. + accum[splitName].treatments.push(mockData.treatment); + + return accum; + }, {}); + + arrangeConditions(mocksData); + + return mocksData; + } + + // Load the content of a configuration file into an Object + return function splitsParserFromFile({ features, log }) { + const filePath = configFilesPath(features); + let mockData; + + // If we have a filePath, it means the extension is correct, choose the parser. + if (endsWith(filePath, '.split')) { + log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.'); + mockData = readSplitConfigFile(log, filePath); + } else { + mockData = readYAMLConfigFile(log, filePath); + } + + return mockData; + }; + +} From 7895ee6f6f0d06b382238d902024f07931b5f410 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 20 Jul 2022 18:04:54 -0300 Subject: [PATCH 22/25] restore ci-cd --- .github/workflows/ci-cd.yml | 4 ++-- src/sync/offline/LocalhostFromFile.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index d396a49cb..f6fd86ccb 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -51,14 +51,14 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") BUILD_COMMIT=${{ github.sha }} npm run build - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/refactor_localhostfromfile' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/refactor_localhostfromfile' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/src/sync/offline/LocalhostFromFile.js b/src/sync/offline/LocalhostFromFile.js index f5568c327..3f63173ac 100644 --- a/src/sync/offline/LocalhostFromFile.js +++ b/src/sync/offline/LocalhostFromFile.js @@ -2,7 +2,7 @@ import { splitsParserFromFileFactory } from './splitsParserFromFile'; import { syncManagerOfflineFactory } from '@splitsoftware/splitio-commons/src/sync/offline/syncManagerOffline'; // Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile) -// Requires Node 'fs' and 'path' APIs. +// It uses NodeJS APIs. const localhostFromFile = syncManagerOfflineFactory(splitsParserFromFileFactory); localhostFromFile.type = 'LocalhostFromFile'; From 006d164adcc4d2eea839d36154d62eaa8f466f7e Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 21 Jul 2022 18:36:32 -0300 Subject: [PATCH 23/25] stable release version --- .github/workflows/ci-cd.yml | 4 ++-- CHANGES.txt | 8 +++++--- package-lock.json | 8 ++++---- package.json | 4 ++-- src/settings/defaults/version.js | 2 +- types/splitio.d.ts | 4 ++-- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 03b9406e2..7b5cb50ea 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -54,14 +54,14 @@ jobs: run: npm run build:ga-to-split-autorequire - name: Configure AWS credentials (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: arn:aws:iam::079419646996:role/public-assets aws-region: us-east-1 - name: Upload to S3 (development) - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/ga_auto_require' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} run: aws s3 sync $SOURCE_DIR s3://$BUCKET/$DEST_DIR $ARGS env: BUCKET: split-public-stage diff --git a/CHANGES.txt b/CHANGES.txt index f2d04e412..be70992fd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,7 +1,9 @@ -10.20.1 (July XX, 2022) -- Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in mobile and modern Web browsers (See https://developer.chrome.com/blog/page-lifecycle-api/#legacy-lifecycle-apis-to-avoid). +10.21.0 (July 21, 2022) +- Added `autoRequire` configuration option to the Google Analytics to Split integration, which takes care of requiring the splitTracker plugin on trackers dynamically created by Google tag managers (See https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js). +- Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in modern mobile and desktop Web browsers. - Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced. -- Bugfixing - Moved js-yaml dependency from @splitsoftware/splitio-commons to avoid issues in Node v14 when installing third-party dependencies that also uses js-yaml as a transitive dependency (Related to issue https://github.com/splitio/javascript-client/issues/662) +- Updated some dependencies for vulnerability fixes. +- Bugfixing - Moved js-yaml dependency from @splitsoftware/splitio-commons to avoid resolution to an incompatible version on certain npm versions when installing third-party dependencies that also define js-yaml as transitive dependency (Related to issue https://github.com/splitio/javascript-client/issues/662). 10.20.0 (June 29, 2022) - Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used. diff --git a/package-lock.json b/package-lock.json index 048740d4f..9259240c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.2", + "version": "10.21.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -486,9 +486,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.5.1-rc.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.5.1-rc.2.tgz", - "integrity": "sha512-0A+SDFhrtjQvFB4nVxVJiil2jKxv2bLLJDiHAtIU8SQA6M98LMQlF59heO6BKoe9C7fKwp466SzyFgpNn2n1RQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.6.0.tgz", + "integrity": "sha512-Y6BIOsk9mLnZC1EMweWaikLRtjoAnwnmuW89vfBO3P5wpe2AkC0CCR+Sk6mf67Fa60+vclCrF7o8XpePIbltsw==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index fcf01a911..600a54167 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "10.20.1-rc.2", + "version": "10.21.0", "description": "Split SDK", "files": [ "README.md", @@ -33,7 +33,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.5.1-rc.2", + "@splitsoftware/splitio-commons": "1.6.0", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 454125bbb..bfb2bd5ce 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '10.20.1-rc.2'; +export const packageVersion = '10.21.0'; diff --git a/types/splitio.d.ts b/types/splitio.d.ts index b18c238fc..eff7d5850 100644 --- a/types/splitio.d.ts +++ b/types/splitio.d.ts @@ -716,7 +716,7 @@ declare namespace SplitIO { /** * Enable 'Google Analytics to Split' integration, to track Google Analytics hits as Split events. * - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#integrations} + * @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-analytics-to-split} */ interface IGoogleAnalyticsToSplitConfig { type: 'GOOGLE_ANALYTICS_TO_SPLIT', @@ -780,7 +780,7 @@ declare namespace SplitIO { /** * Enable 'Split to Google Analytics' integration, to track Split impressions and events as Google Analytics hits. * - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#integrations} + * @see {@link https://help.split.io/hc/en-us/articles/360040838752#split-to-google-analytics} */ interface ISplitToGoogleAnalyticsConfig { type: 'SPLIT_TO_GOOGLE_ANALYTICS', From 6a91d91a8caa13c59d5fc51292f56be96c25e3e9 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 21 Jul 2022 20:16:52 -0300 Subject: [PATCH 24/25] update changelog entry --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index be70992fd..e8c60d6c6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -10.21.0 (July 21, 2022) +10.21.0 (July 22, 2022) - Added `autoRequire` configuration option to the Google Analytics to Split integration, which takes care of requiring the splitTracker plugin on trackers dynamically created by Google tag managers (See https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js). - Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in modern mobile and desktop Web browsers. - Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced. From 97b4b704252ec215248fe56d90a81ac9e03555b0 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 22 Jul 2022 11:56:24 -0300 Subject: [PATCH 25/25] upgrade js-commons --- package-lock.json | 6 +++--- package.json | 2 +- src/__tests__/gaIntegration/gaTestUtils.js | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9259240c0..2e16e0cb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -486,9 +486,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.6.0.tgz", - "integrity": "sha512-Y6BIOsk9mLnZC1EMweWaikLRtjoAnwnmuW89vfBO3P5wpe2AkC0CCR+Sk6mf67Fa60+vclCrF7o8XpePIbltsw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-1.6.1.tgz", + "integrity": "sha512-lijSMpX5a7HiphPnzr7fKlicGSd5TeBWX5URLPWfL87SPlO+8iF7S7PNFPg8GMu+44CdRrp4REHPJo97ht6ePQ==", "requires": { "tslib": "^2.3.1" } diff --git a/package.json b/package.json index 600a54167..fbe315e14 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "node": ">=6" }, "dependencies": { - "@splitsoftware/splitio-commons": "1.6.0", + "@splitsoftware/splitio-commons": "1.6.1", "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.28.0", "ioredis": "^4.28.0", diff --git a/src/__tests__/gaIntegration/gaTestUtils.js b/src/__tests__/gaIntegration/gaTestUtils.js index 90b0a9aed..dd8ba5ac0 100644 --- a/src/__tests__/gaIntegration/gaTestUtils.js +++ b/src/__tests__/gaIntegration/gaTestUtils.js @@ -2,7 +2,7 @@ export const DEFAULT_TRACKER = 't0'; const HIT_FIELDS = ['hitType', 'nonInteraction']; const EVENT_FIELDS = ['eventCategory', 'eventAction', 'eventLabel', 'eventValue']; -const FIELDS = [...HIT_FIELDS, ...EVENT_FIELDS]; +const FIELDS = [...HIT_FIELDS, ...EVENT_FIELDS]; // List of hit fields to spy, which are the ones set by the default SplitToGa mapper. let hits = {}; @@ -10,8 +10,7 @@ let hits = {}; * Spy ga hits per tracker. * * @param {string[]} trackerNames names of the trackers to spy. If not provided, it spies the default tracker. i.e., `gaSpy()` is equivalent to `gaSpy(['t0'])`. - * @param {string[]} fieldNames names of the hit fields to spy. If not provided, it spies hit and event related fields. i.e., 'hitType', 'nonInteraction', - * 'eventCategory', 'eventAction', 'eventLabel', and 'eventValue', which are the ones set by default SplitToGa mapper. + * @param {boolean} resetSpy true to reset the list of captured hits. * * @see {@link https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference} */