From 3923d91d6ae2da5d6229c50bed47b1dc25c6393b Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 24 Oct 2025 14:13:02 -0300 Subject: [PATCH 01/17] [FME-10568] update js commons and add fallback treatment e2e tests --- CHANGES.txt | 4 + karma/e2e.online.karma.conf.js | 2 +- package-lock.json | 18 +- package.json | 4 +- .../nodeSuites/evaluations-fallback.spec.js | 261 ++++++++++++++++++ src/__tests__/online/node.spec.js | 2 + src/settings/defaults/version.js | 2 +- 7 files changed, 280 insertions(+), 13 deletions(-) create mode 100644 src/__tests__/nodeSuites/evaluations-fallback.spec.js diff --git a/CHANGES.txt b/CHANGES.txt index 61cd21f1c..1b62a0574 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +11.8.0 (October 24, 2025) + - Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs. + - Updated @splitsoftware/splitio-commons package to version 2.8.0. + 11.7.0 (October 7, 2025) - Added support for custom loggers: added `logger` configuration option and `factory.Logger.setLogger` method to allow the SDK to use a custom logger. - Updated @splitsoftware/splitio-commons package to version 2.7.0. diff --git a/karma/e2e.online.karma.conf.js b/karma/e2e.online.karma.conf.js index a81d35a7f..3321b9e3d 100644 --- a/karma/e2e.online.karma.conf.js +++ b/karma/e2e.online.karma.conf.js @@ -1,6 +1,6 @@ const assign = require('lodash/assign'); -module.exports = function(config) { +module.exports = function (config) { 'use strict'; config.set(assign({}, require('./config'), { diff --git a/package-lock.json b/package-lock.json index 23598221e..7552bb236 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.0", + "version": "11.7.9-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio", - "version": "11.7.0", + "version": "11.7.9-rc.0", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio-commons": "2.7.0", + "@splitsoftware/splitio-commons": "2.7.9-rc.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -351,9 +351,9 @@ "dev": true }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.0.tgz", - "integrity": "sha512-w2aemu5HNVQXX/tbmSuFjpWa/AjS+EBiH6ltHMqfg2MZMWayTFJbfjjQcudAVLR+vLjDw2DuCTp/xj3kKlcf5g==", + "version": "2.7.9-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.0.tgz", + "integrity": "sha512-qP/kXBPXVwcGjvYE5980SXOxLbooHz8hvIcgPQFKITiMiewbjZMuNa+LUxbwRC6SC2rmVcXHjxWmvMymDA4Gow==", "license": "Apache-2.0", "dependencies": { "@types/ioredis": "^4.28.0", @@ -7740,9 +7740,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.0.tgz", - "integrity": "sha512-w2aemu5HNVQXX/tbmSuFjpWa/AjS+EBiH6ltHMqfg2MZMWayTFJbfjjQcudAVLR+vLjDw2DuCTp/xj3kKlcf5g==", + "version": "2.7.9-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.0.tgz", + "integrity": "sha512-qP/kXBPXVwcGjvYE5980SXOxLbooHz8hvIcgPQFKITiMiewbjZMuNa+LUxbwRC6SC2rmVcXHjxWmvMymDA4Gow==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index 8a88d9769..c489eefe5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.0", + "version": "11.7.9-rc.0", "description": "Split SDK", "files": [ "README.md", @@ -38,7 +38,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@splitsoftware/splitio-commons": "2.7.0", + "@splitsoftware/splitio-commons": "2.7.9-rc.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js new file mode 100644 index 000000000..6b26ee19d --- /dev/null +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -0,0 +1,261 @@ +import sinon from 'sinon'; +import { SplitFactory } from '../../'; + +const listener = { + logImpression: sinon.stub() +}; + +const baseConfig = { + core: { + authorizationKey: '' + }, + sync: { + impressionsMode: 'DEBUG' + }, + streamingEnabled: false +}; + +export default async function (fetchMock, assert) { + + assert.test('FallbackTreatment / Split factory with no fallbackTreatment defined', async t => { + + const splitio = SplitFactory(baseConfig); + const client = splitio.client(); + + await client.ready(); + + t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag_2'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); + + await client.destroy(); + t.end(); + + }); + + assert.test('FallbackTreatment / Split factory with global fallbackTreatment defined', async t => { + + const config = Object.assign({}, baseConfig); + config.fallbackTreatments = { + global: 'FALLBACK_TREATMENT' + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + + t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag_2'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); + + await client.destroy(); + t.end(); + + }); + + assert.test('FallbackTreatment / Split factory with specific fallbackTreatment defined', async t => { + + const config = Object.assign({}, baseConfig); + config.fallbackTreatments = { + byFlag: { + 'non_existent_flag': 'FALLBACK_TREATMENT', + } + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag_2'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); + + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag_2'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); + + await client.destroy(); + t.end(); + + }); + + + assert.test('FallbackTreatment / flag override beats global fallbackTreatment', async t => { + + const config = Object.assign({}, baseConfig); + config.fallbackTreatments = { + global: 'OFF_FALLBACK', + byFlag: { + 'my_flag': 'ON_FALLBACK', + } + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.equal(client.getTreatment('emi@harness.io', 'my_flag'), 'ON_FALLBACK', 'The evaluation will return `ON_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag_2'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); + + t.equal(client.getTreatment('emma@harness.io', 'my_flag'), 'ON_FALLBACK', 'The evaluation will return `ON_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag_2'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); + + await client.destroy(); + t.end(); + + }); + + assert.test('FallbackTreatment / override applies only when original is control', async t => { + + const config = Object.assign({}, baseConfig); + config.fallbackTreatments = { + global: 'OFF_FALLBACK' + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'off', 'The evaluation will return the treatment defined in the flag if it exists'); + t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); + + await client.destroy(); + t.end(); + + }); + + assert.test('FallbackTreatment / Impressions correctness with fallback when client is not ready', async t => { + + const config = Object.assign({}, baseConfig); + config.urls = { + events: 'https://events.fallbacktreatment/api' + }; + config.fallbackTreatments = { + byFlag: { + 'any_flag': 'OFF_FALLBACK' + } + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + t.equal(client.getTreatment('emi@harness.io', 'any_flag'), 'OFF_FALLBACK', 'The evaluation will return the fallbackTreatment if the client is not ready yet'); + t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'control', 'The evaluation will return the fallbackTreatment if the client is not ready yet'); + + await client.ready(); + + fetchMock.postOnce(config.urls.events + '/testImpressions/bulk', (_, opts) => { + + const payload = JSON.parse(opts.body); + + function validateImpressionData(featureFlagName, expectedLabel) { + const impressions = payload.find(e => e.f === featureFlagName).i; + + t.equal(impressions[0].r, expectedLabel, `${featureFlagName} impression with label ${expectedLabel}`); + } + + validateImpressionData('any_flag', 'fallback - not ready'); + validateImpressionData('user_account_in_whitelist', 'not ready'); + t.end(); + + return 200; + }); + + await client.destroy(); + + }); + + assert.test('FallbackTreatment / Fallback dynamic config propagation', async t => { + + const config = Object.assign({}, baseConfig); + config.fallbackTreatments = { + global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } + } + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'my_flag'), { treatment: 'ON_FALLBACK', config: '{"flag": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); + t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'non_existent_flag'), { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); + + await client.destroy(); + t.end(); + + }); + + assert.test('FallbackTreatment / Evaluations non existing flags with fallback do not generate impressions', async t => { + + const config = Object.assign({}, baseConfig); + config.urls = { + events: 'https://events.fallbacktreatment/api' + }; + config.fallbackTreatments = { + global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } + } + }; + config.impressionListener = listener; + + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'my_flag'), { treatment: 'ON_FALLBACK', config: '{"flag": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); + t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'non_existent_flag'), { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); + + let POSTED_IMPRESSIONS_COUNT = 0; + + fetchMock.postOnce(config.urls.events + '/testImpressions/bulk', (_, opts) => { + + const payload = JSON.parse(opts.body); + t.equal(payload.length, 1, 'We should have just one impression for the two evaluated flags'); + + function validateImpressionData(featureFlagName, expectedLength) { + + const impressions = payload.find(e => e.f === featureFlagName).i; + t.equal(impressions.length, expectedLength, `${featureFlagName} has ${expectedLength} impressions`); + } + + validateImpressionData('my_flag', 1); + validateImpressionData('non_existent_flag', 0); + POSTED_IMPRESSIONS_COUNT = payload.reduce((acc, curr) => acc + curr.i.length, 0); + t.equal(POSTED_IMPRESSIONS_COUNT, 1, 'We should have just one impression in total.'); + + return 200; + }); + + setTimeout(() => { + t.equal(listener.logImpression.callCount, POSTED_IMPRESSIONS_COUNT, 'Impression listener should be called once per each impression generated.'); + + t.end(); + }, 0); + await client.destroy(); + + + }); + + assert.test('FallbackTreatment / LocalhostMode', async t => { + + const config = Object.assign({}, baseConfig); + config.core.authorizationKey = 'localhost'; + config.fallbackTreatments = { + global: 'OFF_FALLBACK' + }; + const splitio = SplitFactory(config); + const client = splitio.client(); + + await client.ready(); + + t.deepEqual(client.getTreatment('emma@harness.io', 'workspaces_v1'), 'on', 'The evaluation should return the treatment defined in localhost mode'); + t.deepEqual(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist'); + + await client.destroy(); + + t.end(); + }); + + + assert.end(); +} diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index c0f64b939..a48cbb309 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -8,6 +8,7 @@ import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json'; import evaluationsSuite from '../nodeSuites/evaluations.spec'; import evaluationsSemverSuite from '../nodeSuites/evaluations-semver.spec'; +import evaluationsFallbackSuite from '../nodeSuites/evaluations-fallback.spec'; import eventsSuite from '../nodeSuites/events.spec'; import impressionsSuite from '../nodeSuites/impressions.spec'; import impressionsSuiteDebug from '../nodeSuites/impressions.debug.spec'; @@ -59,6 +60,7 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, config, key)); assert.test('E2E / In Memory - Semver', evaluationsSemverSuite.bind(null, fetchMock)); + assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); /* Check impressions */ assert.test('E2E / Impressions', impressionsSuite.bind(null, key, fetchMock)); diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index d51e26fdc..5e675a540 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '11.7.0'; +export const packageVersion = '11.7.9-rc.0'; From cb8214a23ba917c937e1b6c926076acdd6983811 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 24 Oct 2025 15:11:34 -0300 Subject: [PATCH 02/17] fix version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7552bb236..8a168d2f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.9-rc.0", + "version": "11.7.2-rc.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio", - "version": "11.7.9-rc.0", + "version": "11.7.2-rc.2", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio-commons": "2.7.9-rc.0", diff --git a/package.json b/package.json index c489eefe5..95dceaf9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.9-rc.0", + "version": "11.7.2-rc.2", "description": "Split SDK", "files": [ "README.md", From 3fe6120ee22fdce2fee61ace62cd697f992a2fcf Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 24 Oct 2025 15:54:22 -0300 Subject: [PATCH 03/17] fix version test --- src/settings/defaults/version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 5e675a540..24979a7c0 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '11.7.9-rc.0'; +export const packageVersion = '11.7.2-rc.2'; From b28c3f472ffece90fcaaf9b91b2eaf8c3d847af2 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 24 Oct 2025 18:25:38 -0300 Subject: [PATCH 04/17] remove timeout --- src/__tests__/nodeSuites/evaluations-fallback.spec.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index 6b26ee19d..c0c7f73ce 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -152,12 +152,12 @@ export default async function (fetchMock, assert) { validateImpressionData('any_flag', 'fallback - not ready'); validateImpressionData('user_account_in_whitelist', 'not ready'); - t.end(); return 200; }); await client.destroy(); + t.end(); }); @@ -225,15 +225,10 @@ export default async function (fetchMock, assert) { return 200; }); - - setTimeout(() => { - t.equal(listener.logImpression.callCount, POSTED_IMPRESSIONS_COUNT, 'Impression listener should be called once per each impression generated.'); - - t.end(); - }, 0); + t.equal(listener.logImpression.callCount, POSTED_IMPRESSIONS_COUNT, 'Impression listener should be called once per each impression generated.'); await client.destroy(); - + t.end(); }); assert.test('FallbackTreatment / LocalhostMode', async t => { From 5857e2d7be2c5e0e87d39e39fb1bb2adc8580de5 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 16:02:14 -0300 Subject: [PATCH 05/17] Move test to the end --- src/__tests__/nodeSuites/evaluations-fallback.spec.js | 1 - src/__tests__/online/node.spec.js | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index c0c7f73ce..2d99a8e4f 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -251,6 +251,5 @@ export default async function (fetchMock, assert) { t.end(); }); - assert.end(); } diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index a48cbb309..b4644d718 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -60,7 +60,6 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, config, key)); assert.test('E2E / In Memory - Semver', evaluationsSemverSuite.bind(null, fetchMock)); - assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); /* Check impressions */ assert.test('E2E / Impressions', impressionsSuite.bind(null, key, fetchMock)); @@ -102,5 +101,8 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { // @TODO remove when dropping support for Split Proxy v5.10.0 or below assert.test('E2E / Proxy fallback', proxyFallbackSuite.bind(null, fetchMock)); + /* Check evaluations fallback */ + assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); + assert.end(); }); From ea6bff700fc7aa25682f83858e3b88c150cbecd8 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 16:14:43 -0300 Subject: [PATCH 06/17] Move tests to the top --- src/__tests__/online/node.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index b4644d718..cc999cd7d 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -57,6 +57,9 @@ fetchMock.post(url(settings, '/v1/metrics/config'), 200); fetchMock.post(url(settings, '/v1/metrics/usage'), 200); tape('## Node.js - E2E CI Tests ##', async function (assert) { + /* Check evaluations fallback */ + assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); + /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, config, key)); assert.test('E2E / In Memory - Semver', evaluationsSemverSuite.bind(null, fetchMock)); @@ -101,8 +104,5 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { // @TODO remove when dropping support for Split Proxy v5.10.0 or below assert.test('E2E / Proxy fallback', proxyFallbackSuite.bind(null, fetchMock)); - /* Check evaluations fallback */ - assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); - assert.end(); }); From 23521c447f8605b4fe70b1666ceee05f1ac05e10 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 16:20:00 -0300 Subject: [PATCH 07/17] Move test --- src/__tests__/online/node.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index cc999cd7d..aae279c1d 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -57,8 +57,6 @@ fetchMock.post(url(settings, '/v1/metrics/config'), 200); fetchMock.post(url(settings, '/v1/metrics/usage'), 200); tape('## Node.js - E2E CI Tests ##', async function (assert) { - /* Check evaluations fallback */ - assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, config, key)); @@ -92,6 +90,9 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { /* Validate readiness with ready promises */ assert.test('E2E / Ready promise', readyPromiseSuite.bind(null, key, fetchMock)); + /* Check evaluations fallback */ + assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); + /* Validate fetching specific splits */ assert.test('E2E / Fetch specific splits', fetchSpecificSplits.bind(null, fetchMock)); assert.test('E2E / Fetch specific splits for flag sets', fetchSpecificSplitsForFlagSets.bind(null, fetchMock)); From 2b26ceddfbc7565b2cb95625869b30d47c2a325e Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 16:33:55 -0300 Subject: [PATCH 08/17] Fix test --- src/__tests__/nodeSuites/evaluations-fallback.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index 2d99a8e4f..f649fb727 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -113,7 +113,7 @@ export default async function (fetchMock, assert) { await client.ready(); - t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'off', 'The evaluation will return the treatment defined in the flag if it exists'); + t.equal(client.getTreatment('emma@harness.io', 'real_split'), 'on', 'The evaluation will return the treatment defined in the flag if it exists'); t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); await client.destroy(); From d842d6c75dccadcd0574997620e7e00baac8e171 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 16:49:35 -0300 Subject: [PATCH 09/17] Move telemery tests to bottom --- src/__tests__/nodeSuites/evaluations-fallback.spec.js | 2 +- src/__tests__/online/node.spec.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index f649fb727..2d99a8e4f 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -113,7 +113,7 @@ export default async function (fetchMock, assert) { await client.ready(); - t.equal(client.getTreatment('emma@harness.io', 'real_split'), 'on', 'The evaluation will return the treatment defined in the flag if it exists'); + t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'off', 'The evaluation will return the treatment defined in the flag if it exists'); t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); await client.destroy(); diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index aae279c1d..4ba9279a3 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -61,6 +61,7 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { /* Check client evaluations. */ assert.test('E2E / In Memory', evaluationsSuite.bind(null, config, key)); assert.test('E2E / In Memory - Semver', evaluationsSemverSuite.bind(null, fetchMock)); + assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); /* Check impressions */ assert.test('E2E / Impressions', impressionsSuite.bind(null, key, fetchMock)); @@ -68,8 +69,6 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { assert.test('E2E / Impressions None Mode', impressionsSuiteNone.bind(null, key, fetchMock)); assert.test('E2E / Impressions listener', impressionsListenerSuite); - /* Check telemetry */ - assert.test('E2E / Telemetry', telemetrySuite.bind(null, key, fetchMock)); /* Check events in memory */ assert.test('E2E / Events', eventsSuite.bind(null, fetchMock)); @@ -90,9 +89,6 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { /* Validate readiness with ready promises */ assert.test('E2E / Ready promise', readyPromiseSuite.bind(null, key, fetchMock)); - /* Check evaluations fallback */ - assert.test('E2E / In Memory - Fallback treatment', evaluationsFallbackSuite.bind(null, fetchMock)); - /* Validate fetching specific splits */ assert.test('E2E / Fetch specific splits', fetchSpecificSplits.bind(null, fetchMock)); assert.test('E2E / Fetch specific splits for flag sets', fetchSpecificSplitsForFlagSets.bind(null, fetchMock)); @@ -105,5 +101,9 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { // @TODO remove when dropping support for Split Proxy v5.10.0 or below assert.test('E2E / Proxy fallback', proxyFallbackSuite.bind(null, fetchMock)); + + /* Check telemetry */ + assert.test('E2E / Telemetry', telemetrySuite.bind(null, key, fetchMock)); + assert.end(); }); From 2acd976dbba1542052a99643206f9bdd39088149 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 27 Oct 2025 17:20:55 -0300 Subject: [PATCH 10/17] Move telemetry test --- src/__tests__/online/node.spec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index 4ba9279a3..04413bb14 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -69,6 +69,8 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { assert.test('E2E / Impressions None Mode', impressionsSuiteNone.bind(null, key, fetchMock)); assert.test('E2E / Impressions listener', impressionsListenerSuite); + // /* Check telemetry */ + assert.test('E2E / Telemetry', telemetrySuite.bind(null, key, fetchMock)); /* Check events in memory */ assert.test('E2E / Events', eventsSuite.bind(null, fetchMock)); @@ -101,9 +103,5 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { // @TODO remove when dropping support for Split Proxy v5.10.0 or below assert.test('E2E / Proxy fallback', proxyFallbackSuite.bind(null, fetchMock)); - - /* Check telemetry */ - assert.test('E2E / Telemetry', telemetrySuite.bind(null, key, fetchMock)); - assert.end(); }); From 1d63122abaddc1f699e5e52958ecb16d125e7e20 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 27 Oct 2025 17:26:31 -0300 Subject: [PATCH 11/17] Fix fallback treatment localhost test --- src/__tests__/nodeSuites/evaluations-fallback.spec.js | 5 +++-- src/__tests__/online/node.spec.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index 2d99a8e4f..53c226fea 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -1,3 +1,4 @@ +import path from 'path'; import sinon from 'sinon'; import { SplitFactory } from '../../'; @@ -238,12 +239,13 @@ export default async function (fetchMock, assert) { config.fallbackTreatments = { global: 'OFF_FALLBACK' }; + config.features = path.join(__dirname, '../offline/split.yaml'); const splitio = SplitFactory(config); const client = splitio.client(); await client.ready(); - t.deepEqual(client.getTreatment('emma@harness.io', 'workspaces_v1'), 'on', 'The evaluation should return the treatment defined in localhost mode'); + t.deepEqual(client.getTreatment('emma@harness.io', 'testing_split_on'), 'on', 'The evaluation should return the treatment defined in localhost mode'); t.deepEqual(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist'); await client.destroy(); @@ -251,5 +253,4 @@ export default async function (fetchMock, assert) { t.end(); }); - assert.end(); } diff --git a/src/__tests__/online/node.spec.js b/src/__tests__/online/node.spec.js index 04413bb14..35d87a3c3 100644 --- a/src/__tests__/online/node.spec.js +++ b/src/__tests__/online/node.spec.js @@ -69,7 +69,7 @@ tape('## Node.js - E2E CI Tests ##', async function (assert) { assert.test('E2E / Impressions None Mode', impressionsSuiteNone.bind(null, key, fetchMock)); assert.test('E2E / Impressions listener', impressionsListenerSuite); - // /* Check telemetry */ + /* Check telemetry */ assert.test('E2E / Telemetry', telemetrySuite.bind(null, key, fetchMock)); /* Check events in memory */ From 8fb634eb5ae5fbec7a8ccc37d9894ee1af971c87 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 27 Oct 2025 21:59:14 -0300 Subject: [PATCH 12/17] rc --- package-lock.json | 4 ++-- package.json | 2 +- src/settings/defaults/version.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e174c2f15..538bfbfc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.2", + "version": "11.7.2-rc.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.2", + "version": "11.7.2-rc.3", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio-commons": "2.7.9-rc.1", diff --git a/package.json b/package.json index d342a6d0b..b1981d99c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.2", + "version": "11.7.2-rc.3", "description": "Split SDK", "files": [ "README.md", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 24979a7c0..645b9899d 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '11.7.2-rc.2'; +export const packageVersion = '11.7.2-rc.3'; From 910e0ca265f4d2e1f161eae15b786f7a14063da2 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 27 Oct 2025 22:41:44 -0300 Subject: [PATCH 13/17] Test update --- src/__tests__/nodeSuites/ready-promise.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/nodeSuites/ready-promise.spec.js b/src/__tests__/nodeSuites/ready-promise.spec.js index b6b76c93e..6e2ee9c91 100644 --- a/src/__tests__/nodeSuites/ready-promise.spec.js +++ b/src/__tests__/nodeSuites/ready-promise.spec.js @@ -484,7 +484,7 @@ export default function readyPromiseAssertions(key, fetchMock, assert) { client.off(client.Event.SDK_READY, onReadyCallback); const manager = splitio.manager(); - client.whenReadyFromCache().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject')); + manager.whenReadyFromCache().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject')); manager.on(manager.Event.SDK_READY, onReadyCallback); manager.off(manager.Event.SDK_READY, onReadyCallback); From 39c9d8a57b959aad92141294aff7102dd2ead8fa Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Oct 2025 16:13:33 -0300 Subject: [PATCH 14/17] Use getStatus --- .github/workflows/ci-cd.yml | 4 +-- CHANGES.txt | 1 + package-lock.json | 18 +++++------ package.json | 4 +-- .../ready-from-cache-async-wrapper.spec.js | 12 ++++---- .../browserSuites/ready-from-cache.spec.js | 30 +++++++++++-------- src/__tests__/errorCatching/browser.spec.js | 6 ++-- src/__tests__/nodeSuites/lazy-init.spec.js | 12 ++++---- src/__tests__/nodeSuites/readiness.spec.js | 2 +- src/__tests__/offline/browser.spec.js | 2 +- src/settings/defaults/version.js | 2 +- 11 files changed, 49 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f94fb108b..692ee45f3 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -57,7 +57,7 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") npm run build - name: Store assets - if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/development' || github.ref == 'refs/heads/main') }} + if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/fme-10568' || github.ref == 'refs/heads/main') }} uses: actions/upload-artifact@v4 with: name: assets @@ -68,7 +68,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/fme-10568' }} strategy: matrix: environment: diff --git a/CHANGES.txt b/CHANGES.txt index fb1ee4a83..b1a126457 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 11.8.0 (October 28, 2025) - Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs. + - Added `client.getStatus()` method to retrieve the client readiness status properties (`isReady`, `isReadyFromCache`, etc). - Added `client.whenReady()` and `client.whenReadyFromCache()` methods to replace the deprecated `client.ready()` method, which has an issue causing the returned promise to hang when using async/await syntax if it was rejected. - Updated the SDK_READY_FROM_CACHE event to be emitted alongside the SDK_READY event if it hasn’t already been emitted. - Updated @splitsoftware/splitio-commons package to version 2.8.0. diff --git a/package-lock.json b/package-lock.json index 538bfbfc3..4bc186fd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.3", + "version": "11.7.2-rc.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.3", + "version": "11.7.2-rc.4", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio-commons": "2.7.9-rc.1", + "@splitsoftware/splitio-commons": "2.7.9-rc.2", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -351,9 +351,9 @@ "dev": true }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.7.9-rc.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.1.tgz", - "integrity": "sha512-hmcekZebItAc67+AF3xGgKXIvnLybQhpaEtQKsqU3WbyRittUI9hN9HqA6qUiaLxFPwrsCxioihTYsnxxej/Rg==", + "version": "2.7.9-rc.2", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.2.tgz", + "integrity": "sha512-t8YVwDe4UBvD95w+mvKq7Z2khozZXDrIuOWt3ixxtmyeyoZp5L0L9x9E3DWOcQ0EVxfpQv+tAErHG3bw3LkbNg==", "license": "Apache-2.0", "dependencies": { "@types/ioredis": "^4.28.0", @@ -7740,9 +7740,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "2.7.9-rc.1", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.1.tgz", - "integrity": "sha512-hmcekZebItAc67+AF3xGgKXIvnLybQhpaEtQKsqU3WbyRittUI9hN9HqA6qUiaLxFPwrsCxioihTYsnxxej/Rg==", + "version": "2.7.9-rc.2", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.2.tgz", + "integrity": "sha512-t8YVwDe4UBvD95w+mvKq7Z2khozZXDrIuOWt3ixxtmyeyoZp5L0L9x9E3DWOcQ0EVxfpQv+tAErHG3bw3LkbNg==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index b1981d99c..01a530f39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "11.7.2-rc.3", + "version": "11.7.2-rc.4", "description": "Split SDK", "files": [ "README.md", @@ -38,7 +38,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@splitsoftware/splitio-commons": "2.7.9-rc.1", + "@splitsoftware/splitio-commons": "2.7.9-rc.2", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", diff --git a/src/__tests__/browserSuites/ready-from-cache-async-wrapper.spec.js b/src/__tests__/browserSuites/ready-from-cache-async-wrapper.spec.js index d4f37eed5..d66b2993b 100644 --- a/src/__tests__/browserSuites/ready-from-cache-async-wrapper.spec.js +++ b/src/__tests__/browserSuites/ready-from-cache-async-wrapper.spec.js @@ -70,17 +70,17 @@ export default function (fetchMock, assert) { t.end(); }); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.on(client.Event.SDK_READY, () => { - t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache'); + t.true(client.getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache'); }); client2.on(client.Event.SDK_READY, () => { - t.true(client2.__getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); + t.true(client2.getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); }); client3.on(client.Event.SDK_READY, () => { - t.true(client2.__getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); + t.true(client2.getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); }); }); @@ -356,7 +356,7 @@ export default function (fetchMock, assert) { let manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); }); await client.whenReady(); @@ -400,7 +400,7 @@ export default function (fetchMock, assert) { manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); }); await new Promise(res => client.once(client.Event.SDK_READY, res)); diff --git a/src/__tests__/browserSuites/ready-from-cache.spec.js b/src/__tests__/browserSuites/ready-from-cache.spec.js index 2ff9cc183..4650af9b0 100644 --- a/src/__tests__/browserSuites/ready-from-cache.spec.js +++ b/src/__tests__/browserSuites/ready-from-cache.spec.js @@ -142,17 +142,17 @@ export default function (fetchMock, assert) { t.end(); }); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.on(client.Event.SDK_READY, () => { - t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache'); + t.true(client.getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache'); }); client2.on(client.Event.SDK_READY, () => { - t.true(client2.__getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); + t.true(client2.getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); }); client3.on(client.Event.SDK_READY, () => { - t.true(client2.__getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); + t.true(client2.getStatus().isReadyFromCache, 'Non-default client should emit SDK_READY and it should be ready from cache'); }); }); @@ -331,7 +331,7 @@ export default function (fetchMock, assert) { client.on(client.Event.SDK_READY_FROM_CACHE, () => { t.true(Date.now() - startTime < 400, 'It should emit SDK_READY_FROM_CACHE on every client if there was data in the cache and we subscribe on time. Should be considerably faster than actual readiness from the cloud.'); - t.false(client.__getStatus().isReady, 'It should not be ready yet'); + t.false(client.getStatus().isReady, 'It should not be ready yet'); t.equal(client.getTreatment('always_on'), 'off', 'It should evaluate treatments with data from cache instead of control due to Input Validation'); @@ -515,7 +515,7 @@ export default function (fetchMock, assert) { }); }); - assert.test(t => { // Testing when we start with initial rollout plan data and sync storage type (is ready from cache immediately) + assert.test(async t => { // Testing when we start with initial rollout plan data and sync storage type (is ready from cache immediately) const testUrls = { sdk: 'https://sdk.baseurl/readyFromCacheWithInitialRolloutPlan', events: 'https://events.baseurl/readyFromCacheWithInitialRolloutPlan' @@ -552,7 +552,7 @@ export default function (fetchMock, assert) { const client = splitio.client(); const client2 = splitio.client('emi@split.io'); - t.equal(client.__getStatus().isReadyFromCache, true, 'Client is ready from cache'); + t.equal(client.getStatus().isReadyFromCache, true, 'Client is ready from cache'); t.equal(client.getTreatment('always_on'), 'off', 'It should evaluate treatments with data from cache. Key without memberships'); t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with data from cache. Key with memberships'); @@ -577,6 +577,10 @@ export default function (fetchMock, assert) { t.end(); }); }); + + const startTime = Date.now(); + await client.whenReadyFromCache(); + t.true(nearlyEqual(Date.now() - startTime, 0), 'whenReadyFromCache should be resolved immediately'); }); /** Fetch specific splits **/ @@ -613,7 +617,7 @@ export default function (fetchMock, assert) { const manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.once(client.Event.SDK_READY, () => { @@ -657,7 +661,7 @@ export default function (fetchMock, assert) { const manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.once(client.Event.SDK_READY, () => { @@ -758,7 +762,7 @@ export default function (fetchMock, assert) { const manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.once(client.Event.SDK_READY, () => { @@ -819,7 +823,7 @@ export default function (fetchMock, assert) { const manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY'); }); client.once(client.Event.SDK_READY, () => { @@ -919,7 +923,7 @@ export default function (fetchMock, assert) { let manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); }); await client.whenReady(); @@ -959,7 +963,7 @@ export default function (fetchMock, assert) { manager = splitio.manager(); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); + t.true(client.getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true'); }); await new Promise(res => client.once(client.Event.SDK_READY, res)); diff --git a/src/__tests__/errorCatching/browser.spec.js b/src/__tests__/errorCatching/browser.spec.js index 4e422dc10..ef8d7ffdd 100644 --- a/src/__tests__/errorCatching/browser.spec.js +++ b/src/__tests__/errorCatching/browser.spec.js @@ -91,13 +91,13 @@ tape('Error catching on callbacks - Browsers', assert => { } client.on(client.Event.SDK_READY_TIMED_OUT, () => { - assert.true(client.__getStatus().hasTimedout); // SDK status should be already updated + assert.true(client.getStatus().hasTimedout); // SDK status should be already updated attachErrorHandlerIfApplicable(); null.willThrowForTimedOut(); }); client.once(client.Event.SDK_READY, () => { - assert.true(client.__getStatus().isReady); // SDK status should be already updated + assert.true(client.getStatus().isReady); // SDK status should be already updated attachErrorHandlerIfApplicable(); null.willThrowForReady(); }); @@ -108,7 +108,7 @@ tape('Error catching on callbacks - Browsers', assert => { }); client.once(client.Event.SDK_READY_FROM_CACHE, () => { - assert.true(client.__getStatus().isReadyFromCache); // SDK status should be already updated + assert.true(client.getStatus().isReadyFromCache); // SDK status should be already updated attachErrorHandlerIfApplicable(); null.willThrowForReadyFromCache(); }); diff --git a/src/__tests__/nodeSuites/lazy-init.spec.js b/src/__tests__/nodeSuites/lazy-init.spec.js index 44bfacaa6..7194ebb7a 100644 --- a/src/__tests__/nodeSuites/lazy-init.spec.js +++ b/src/__tests__/nodeSuites/lazy-init.spec.js @@ -41,14 +41,14 @@ export default function (settings, fetchMock, t) { splitio.init(); await splitio.client().ready(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); await splitio.destroy(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); splitio.init(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); await splitio.destroy(); @@ -99,14 +99,14 @@ export default function (settings, fetchMock, t) { splitio.init(); await splitio.client().ready(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); await splitio.destroy(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); splitio.init(); - assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + assert.deepEqual(splitio.client().getStatus(), { isReady: true, isReadyFromCache: true, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().getStatus().lastUpdate }, 'Status'); await splitio.destroy(); diff --git a/src/__tests__/nodeSuites/readiness.spec.js b/src/__tests__/nodeSuites/readiness.spec.js index ebce11039..531cb0ad0 100644 --- a/src/__tests__/nodeSuites/readiness.spec.js +++ b/src/__tests__/nodeSuites/readiness.spec.js @@ -89,7 +89,7 @@ export default function (fetchMock, assert) { const client = splitio.client(); - t.equal(client.__getStatus().isReadyFromCache, true, 'Client is ready from cache'); + t.equal(client.getStatus().isReadyFromCache, true, 'Client is ready from cache'); t.equal(client.getTreatment('nicolas@split.io', 'always_on'), 'off', 'It should evaluate treatments with data from cache. Key not in segment'); t.equal(client.getTreatment('emi@split.io', 'always_on'), 'on', 'It should evaluate treatments with data from cache. Key in segment'); diff --git a/src/__tests__/offline/browser.spec.js b/src/__tests__/offline/browser.spec.js index f2cb8dac0..8edd7d50c 100644 --- a/src/__tests__/offline/browser.spec.js +++ b/src/__tests__/offline/browser.spec.js @@ -114,7 +114,7 @@ tape('Browser offline mode', function (assert) { const sdkReadyFromCache = (client) => () => { assert.equal(factory.settings.storage.type, 'MEMORY', 'In localhost mode, storage must fallback to memory storage'); - const clientStatus = client.__getStatus(); + const clientStatus = client.getStatus(); assert.equal(clientStatus.isReadyFromCache, true, 'If ready from cache, READY_FROM_CACHE status must be true'); assert.equal(clientStatus.isReady, configs[i].storage && configs[i].storage.type === 'LOCALSTORAGE' ? false : true, 'When not using LOCALSTORAGE, READY status is set together with READY_FROM_CACHE'); if (!clientStatus.isReady) readyFromCacheCount++; diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 645b9899d..500d24409 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '11.7.2-rc.3'; +export const packageVersion = '11.7.2-rc.4'; From 18235b71a75d19439eecbae564b23bd937753885 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 28 Oct 2025 16:22:33 -0300 Subject: [PATCH 15/17] fix test --- src/__tests__/browserSuites/ready-from-cache.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/browserSuites/ready-from-cache.spec.js b/src/__tests__/browserSuites/ready-from-cache.spec.js index 4650af9b0..419728fca 100644 --- a/src/__tests__/browserSuites/ready-from-cache.spec.js +++ b/src/__tests__/browserSuites/ready-from-cache.spec.js @@ -521,7 +521,7 @@ export default function (fetchMock, assert) { events: 'https://events.baseurl/readyFromCacheWithInitialRolloutPlan' }; - t.plan(5); + t.plan(6); fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.3&since=25&rbSince=-1', { status: 200, body: { ff: { ...splitChangesMock1.ff, s: 25 } } }); fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: membershipsNicolas }); From c1bdce1002c0e9c48907e69ea8cfa1ed9d272364 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 29 Oct 2025 11:51:13 -0300 Subject: [PATCH 16/17] Update ts-test --- .github/workflows/ci-cd.yml | 4 ++-- ts-tests/index.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 692ee45f3..f94fb108b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -57,7 +57,7 @@ jobs: run: BUILD_BRANCH=$(echo "${GITHUB_REF#refs/heads/}") npm run build - name: Store assets - if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/fme-10568' || github.ref == 'refs/heads/main') }} + if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/development' || github.ref == 'refs/heads/main') }} uses: actions/upload-artifact@v4 with: name: assets @@ -68,7 +68,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/fme-10568' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} strategy: matrix: environment: diff --git a/ts-tests/index.ts b/ts-tests/index.ts index 271a437ea..bd764176a 100644 --- a/ts-tests/index.ts +++ b/ts-tests/index.ts @@ -258,10 +258,24 @@ let nodeEventEmitter: NodeJS.EventEmitter = client; // Ready, destroy and flush let promise: Promise = client.ready(); +promise = client.whenReady(); promise = client.destroy(); promise = SDK.destroy(); // @TODO not public yet // promise = client.flush(); +const promiseWhenReadyFromCache: Promise = client.whenReadyFromCache(); + +// Get readiness status +let status: SplitIO.ReadinessStatus = client.getStatus(); +status = { + isReady: false, + isReadyFromCache: false, + isTimedout: false, + isDestroyed: false, + isOperational: false, + hasTimedout: false, + lastUpdate: 0 +} // We can call getTreatment with or without a key. treatment = client.getTreatment(splitKey, 'mySplit'); From d40d0817d8d791bc12606d47f2095d54af3fb267 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Wed, 29 Oct 2025 13:38:56 -0300 Subject: [PATCH 17/17] add ts-tests, update commons to 2.7.9-rc.3 --- package-lock.json | 14 +- package.json | 2 +- .../nodeSuites/evaluations-fallback.spec.js | 121 ++++++++++-------- ts-tests/index.ts | 23 +++- 4 files changed, 100 insertions(+), 60 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bc186fd3..0faf40dec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.7.2-rc.4", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio-commons": "2.7.9-rc.2", + "@splitsoftware/splitio-commons": "2.7.9-rc.3", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -351,9 +351,9 @@ "dev": true }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.7.9-rc.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.2.tgz", - "integrity": "sha512-t8YVwDe4UBvD95w+mvKq7Z2khozZXDrIuOWt3ixxtmyeyoZp5L0L9x9E3DWOcQ0EVxfpQv+tAErHG3bw3LkbNg==", + "version": "2.7.9-rc.3", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.3.tgz", + "integrity": "sha512-momlpLuBt0yQXzo7blDWbNIs+H0fIPcxWukZVXMIKHiLiZtfu608diLT8EB/PNtA245OUMIRzachk5If4BBOWw==", "license": "Apache-2.0", "dependencies": { "@types/ioredis": "^4.28.0", @@ -7740,9 +7740,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "2.7.9-rc.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.2.tgz", - "integrity": "sha512-t8YVwDe4UBvD95w+mvKq7Z2khozZXDrIuOWt3ixxtmyeyoZp5L0L9x9E3DWOcQ0EVxfpQv+tAErHG3bw3LkbNg==", + "version": "2.7.9-rc.3", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.7.9-rc.3.tgz", + "integrity": "sha512-momlpLuBt0yQXzo7blDWbNIs+H0fIPcxWukZVXMIKHiLiZtfu608diLT8EB/PNtA245OUMIRzachk5If4BBOWw==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index 01a530f39..67633080f 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@splitsoftware/splitio-commons": "2.7.9-rc.2", + "@splitsoftware/splitio-commons": "2.7.9-rc.3", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", diff --git a/src/__tests__/nodeSuites/evaluations-fallback.spec.js b/src/__tests__/nodeSuites/evaluations-fallback.spec.js index 53c226fea..610d646eb 100644 --- a/src/__tests__/nodeSuites/evaluations-fallback.spec.js +++ b/src/__tests__/nodeSuites/evaluations-fallback.spec.js @@ -23,7 +23,7 @@ export default async function (fetchMock, assert) { const splitio = SplitFactory(baseConfig); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag_2'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); @@ -35,14 +35,16 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / Split factory with global fallbackTreatment defined', async t => { - const config = Object.assign({}, baseConfig); - config.fallbackTreatments = { - global: 'FALLBACK_TREATMENT' + const config = { + ...baseConfig, + fallbackTreatments: { + global: 'FALLBACK_TREATMENT' + } }; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); @@ -55,16 +57,18 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / Split factory with specific fallbackTreatment defined', async t => { - const config = Object.assign({}, baseConfig); - config.fallbackTreatments = { - byFlag: { - 'non_existent_flag': 'FALLBACK_TREATMENT', + const config = { + ...baseConfig, + fallbackTreatments: { + byFlag: { + 'non_existent_flag': 'FALLBACK_TREATMENT', + } } }; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag'), 'FALLBACK_TREATMENT', 'The evaluation will return `FALLBACK_TREATMENT` if the flag does not exist and no fallbackTreatment is defined'); t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag_2'), 'control', 'The evaluation will return `control` if the flag does not exist and no fallbackTreatment is defined'); @@ -80,17 +84,19 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / flag override beats global fallbackTreatment', async t => { - const config = Object.assign({}, baseConfig); - config.fallbackTreatments = { - global: 'OFF_FALLBACK', - byFlag: { - 'my_flag': 'ON_FALLBACK', + const config = { + ...baseConfig, + fallbackTreatments: { + global: 'OFF_FALLBACK', + byFlag: { + 'my_flag': 'ON_FALLBACK', + } } }; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.equal(client.getTreatment('emi@harness.io', 'my_flag'), 'ON_FALLBACK', 'The evaluation will return `ON_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); t.equal(client.getTreatment('emi@harness.io', 'non_existent_flag_2'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); @@ -105,14 +111,16 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / override applies only when original is control', async t => { - const config = Object.assign({}, baseConfig); - config.fallbackTreatments = { - global: 'OFF_FALLBACK' + const config = { + ...baseConfig, + fallbackTreatments: { + global: 'OFF_FALLBACK' + } }; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'off', 'The evaluation will return the treatment defined in the flag if it exists'); t.equal(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist and no fallbackTreatment is defined'); @@ -124,13 +132,15 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / Impressions correctness with fallback when client is not ready', async t => { - const config = Object.assign({}, baseConfig); - config.urls = { - events: 'https://events.fallbacktreatment/api' - }; - config.fallbackTreatments = { - byFlag: { - 'any_flag': 'OFF_FALLBACK' + const config = { + ...baseConfig, + urls: { + events: 'https://events.fallbacktreatment/api' + }, + fallbackTreatments: { + byFlag: { + 'any_flag': 'OFF_FALLBACK' + } } }; const splitio = SplitFactory(config); @@ -139,7 +149,7 @@ export default async function (fetchMock, assert) { t.equal(client.getTreatment('emi@harness.io', 'any_flag'), 'OFF_FALLBACK', 'The evaluation will return the fallbackTreatment if the client is not ready yet'); t.equal(client.getTreatment('emma@harness.io', 'user_account_in_whitelist'), 'control', 'The evaluation will return the fallbackTreatment if the client is not ready yet'); - await client.ready(); + await client.whenReady(); fetchMock.postOnce(config.urls.events + '/testImpressions/bulk', (_, opts) => { @@ -164,17 +174,19 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / Fallback dynamic config propagation', async t => { - const config = Object.assign({}, baseConfig); - config.fallbackTreatments = { - global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, - byFlag: { - 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } + const config = { + ...baseConfig, + fallbackTreatments: { + global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } + } } }; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'my_flag'), { treatment: 'ON_FALLBACK', config: '{"flag": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'non_existent_flag'), { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); @@ -186,22 +198,24 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / Evaluations non existing flags with fallback do not generate impressions', async t => { - const config = Object.assign({}, baseConfig); - config.urls = { - events: 'https://events.fallbacktreatment/api' - }; - config.fallbackTreatments = { - global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, - byFlag: { - 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } - } + const config = { + ...baseConfig, + urls: { + events: 'https://events.fallbacktreatment/api' + }, + fallbackTreatments: { + global: { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'ON_FALLBACK', config: '{"flag": true}' } + } + }, + impressionListener: listener }; - config.impressionListener = listener; const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'my_flag'), { treatment: 'ON_FALLBACK', config: '{"flag": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); t.deepEqual(client.getTreatmentWithConfig('emma@harness.io', 'non_existent_flag'), { treatment: 'OFF_FALLBACK', config: '{"global": true}' }, 'The evaluation will propagate the config along with the treatment from the fallbackTreatment'); @@ -234,16 +248,21 @@ export default async function (fetchMock, assert) { assert.test('FallbackTreatment / LocalhostMode', async t => { - const config = Object.assign({}, baseConfig); - config.core.authorizationKey = 'localhost'; - config.fallbackTreatments = { - global: 'OFF_FALLBACK' + const config = { + ...baseConfig, + core: { + ...baseConfig.core, + authorizationKey: 'localhost' + }, + fallbackTreatments: { + global: 'OFF_FALLBACK' + }, + features: path.join(__dirname, '../offline/split.yaml') }; - config.features = path.join(__dirname, '../offline/split.yaml'); const splitio = SplitFactory(config); const client = splitio.client(); - await client.ready(); + await client.whenReady(); t.deepEqual(client.getTreatment('emma@harness.io', 'testing_split_on'), 'on', 'The evaluation should return the treatment defined in localhost mode'); t.deepEqual(client.getTreatment('emma@harness.io', 'non_existent_flag'), 'OFF_FALLBACK', 'The evaluation will return `OFF_FALLBACK` if the flag does not exist'); diff --git a/ts-tests/index.ts b/ts-tests/index.ts index bd764176a..c1cf06960 100644 --- a/ts-tests/index.ts +++ b/ts-tests/index.ts @@ -598,7 +598,14 @@ let fullBrowserSettings: SplitIO.IBrowserSettings = { getHeaderOverrides(context) { return { ...context.headers, 'header': 'value' } }, } }, - userConsent: 'GRANTED' + userConsent: 'GRANTED', + fallbackTreatments: { + global: { treatment: 'global-treatment', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'flag-treatment', config: '{"flag": true}' }, + 'my_other_flag': 'other-flag-treatment' + } + } }; fullBrowserSettings.storage.type = 'MEMORY'; fullBrowserSettings.userConsent = 'DECLINED'; @@ -658,6 +665,13 @@ let fullNodeSettings: SplitIO.INodeSettings = { getHeaderOverrides(context) { return { ...context.headers, 'header': 'value' } }, agent: new (require('https')).Agent(), } + }, + fallbackTreatments: { + global: { treatment: 'global-treatment', config: '{"global": true}' }, + byFlag: { + 'my_flag': { treatment: 'flag-treatment', config: '{"flag": true}' }, + 'my_other_flag': 'other-flag-treatment' + } } }; fullNodeSettings.storage.type = 'MEMORY'; @@ -706,6 +720,13 @@ let fullAsyncSettings: SplitIO.INodeAsyncSettings = { sync: { splitFilters: splitFilters, impressionsMode: 'DEBUG', + }, + fallbackTreatments: { + global: 'global-treatment', + byFlag: { + 'my_flag': { treatment: 'flag-treatment', config: '{"flag": true}' }, + 'my_other_flag': 'other-flag-treatment' + } } };