Skip to content

Commit 79622bd

Browse files
Update readiness tests
1 parent 580b5b6 commit 79622bd

File tree

6 files changed

+64
-72
lines changed

6 files changed

+64
-72
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
1.6.0 (October XX, 2025)
2+
- 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.
3+
- Updated the SDK_READY_FROM_CACHE event to be emitted alongside the SDK_READY event if it hasn’t already been emitted.
4+
- Updated @splitsoftware/splitio-commons package to version 2.8.0.
5+
16
1.5.1 (October 8, 2025)
27
- Bugfix - Updated @splitsoftware/splitio-commons package to version 2.7.1, which fixes the `debug` option to support log levels when the `logger` option is used.
38

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"bugs": "https://github.com/splitio/javascript-browser-client/issues",
6060
"homepage": "https://github.com/splitio/javascript-browser-client#readme",
6161
"dependencies": {
62-
"@splitsoftware/splitio-commons": "2.7.1",
62+
"@splitsoftware/splitio-commons": "2.7.9-rc.1",
6363
"tslib": "^2.3.1",
6464
"unfetch": "^4.2.0"
6565
},

src/__tests__/browserSuites/ready-promise.spec.js

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function assertGetTreatmentWhenReady(assert, client) {
3131
function assertGetTreatmentControlNotReady(assert, client) {
3232
consoleSpy.log.resetHistory();
3333
assert.equal(client.getTreatment('hierarchical_splits_test'), 'control', 'We should get control if client is not ready.');
34-
assert.true(consoleSpy.log.calledWithExactly('[WARN] splitio => getTreatment: the SDK is not ready, results may be incorrect for feature flag hierarchical_splits_test. Make sure to wait for SDK readiness before using this method.'), 'Telling us that calling getTreatment would return CONTROL since SDK is not ready at this point.');
34+
assert.true(consoleSpy.log.calledWithExactly('[WARN] splitio => getTreatment: the SDK is not ready to evaluate. Results may be incorrect for feature flag hierarchical_splits_test. Make sure to wait for SDK readiness before using this method.'), 'Telling us that calling getTreatment would return CONTROL since SDK is not ready at this point.');
3535
}
3636

3737
function assertGetTreatmentControlNotReadyOnDestroy(assert, client) {
@@ -68,7 +68,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
6868
const splitio = SplitFactory(config);
6969
const client = splitio.client();
7070

71-
client.ready()
71+
client.whenReady()
7272
.then(() => {
7373
t.fail('### SDK IS READY - not TIMED OUT when it should.');
7474
})
@@ -77,7 +77,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
7777
assertGetTreatmentControlNotReady(t, client);
7878

7979
client.destroy().then(() => {
80-
client.ready()
80+
client.whenReady()
8181
.then(() => {
8282
t.fail('### SDK IS READY - It should not in this scenario.');
8383
t.end();
@@ -118,13 +118,13 @@ export default function readyPromiseAssertions(fetchMock, assert) {
118118
// In this case, we use the manager instead of the client to get the ready promise
119119
const manager = splitio.manager();
120120

121-
manager.ready()
121+
manager.whenReady()
122122
.then(() => {
123123
t.pass('### SDK IS READY - the retry request is under the limits.');
124124
assertGetTreatmentWhenReady(t, client);
125125

126126
client.destroy().then(() => {
127-
client.ready()
127+
client.whenReady()
128128
.then(() => {
129129
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
130130
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -166,7 +166,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
166166
const splitio = SplitFactory(config);
167167
const client = splitio.client();
168168

169-
client.ready()
169+
client.whenReady()
170170
.then(() => {
171171
t.fail('### SDK IS READY - not TIMED OUT when it should.');
172172
})
@@ -175,13 +175,13 @@ export default function readyPromiseAssertions(fetchMock, assert) {
175175
assertGetTreatmentControlNotReady(t, client);
176176

177177
setTimeout(() => {
178-
client.ready()
178+
client.whenReady()
179179
.then(() => {
180180
t.pass('### SDK IS READY - retry attempt finishes before the requestTimeoutBeforeReady limit');
181181
assertGetTreatmentWhenReady(t, client);
182182

183183
client.destroy().then(() => {
184-
client.ready()
184+
client.whenReady()
185185
.then(() => {
186186
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
187187
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -244,7 +244,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
244244
const client = splitio.client();
245245
const nicolasClient = splitio.client('nicolas@split.io');
246246

247-
client.ready()
247+
client.whenReady()
248248
.then(() => {
249249
t.fail('### SDK IS READY - not TIMED OUT when it should.');
250250
})
@@ -253,25 +253,25 @@ export default function readyPromiseAssertions(fetchMock, assert) {
253253
assertGetTreatmentControlNotReady(t, client);
254254

255255
client.on(client.Event.SDK_READY, () => {
256-
client.ready().then(() => {
256+
client.whenReady().then(() => {
257257
t.pass('### SDK IS READY - the scheduled refresh changes the client state into "ready"');
258258
assertGetTreatmentWhenReady(t, client);
259259

260260
const tStart = Date.now();
261-
nicolasClient.ready().then(() => {
261+
nicolasClient.whenReady().then(() => {
262262
const delta = Date.now() - tStart;
263263
t.true(nearlyEqual(delta, 0), 'shared client is ready as soon as main client is ready (i.e., splits have arrived)');
264264

265265
const timeoutClient = splitio.client('emiliano@split.io');
266-
timeoutClient.ready().then(undefined, () => { // setting onRejected handler via `then` method
266+
timeoutClient.whenReady().then(undefined, () => { // setting onRejected handler via `then` method
267267
t.pass('### Shared client TIMED OUT - promise rejected since memberships fetch took more time than readyTimeout');
268-
timeoutClient.ready().catch(() => { // setting onRejected handler via `catch` method
268+
timeoutClient.whenReady().catch(() => { // setting onRejected handler via `catch` method
269269
t.pass('### Shared client TIMED OUT - promise keeps being rejected');
270270
timeoutClient.on(timeoutClient.Event.SDK_READY, () => {
271-
timeoutClient.ready().then(() => {
271+
timeoutClient.whenReady().then(() => {
272272
t.pass('### Shared client READY - `ready` returns a new resolved promise');
273273
Promise.all([timeoutClient.destroy(), nicolasClient.destroy(), client.destroy()]).then(() => {
274-
client.ready()
274+
client.whenReady()
275275
.then(() => {
276276
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
277277
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -318,7 +318,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
318318
const splitio = SplitFactory(config);
319319
const client = splitio.client();
320320

321-
client.ready()
321+
client.whenReady()
322322
.then(() => {
323323
t.fail('### SDK IS READY - not TIMED OUT when it should.');
324324
client.destroy().then(() => { t.end(); });
@@ -330,7 +330,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
330330
.catch((error) => {
331331
t.equal(error, 'error', '### Handled thrown exception on onRejected callback.');
332332
client.destroy().then(() => {
333-
client.ready()
333+
client.whenReady()
334334
.then(() => {
335335
t.fail('### SDK IS READY - It should not in this scenario.');
336336
t.end();
@@ -368,7 +368,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
368368
const splitio = SplitFactory(config);
369369
const client = splitio.client();
370370

371-
client.ready()
371+
client.whenReady()
372372
.then(() => {
373373
t.pass('### SDK IS READY as it should, request is under the limits.');
374374
assertGetTreatmentWhenReady(t, client);
@@ -377,7 +377,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
377377
.catch((error) => {
378378
t.equal(error, 'error', '### Handled thrown exception on onRejected callback.');
379379
client.destroy().then(() => {
380-
client.ready()
380+
client.whenReady()
381381
.then(() => {
382382
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
383383
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -421,7 +421,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
421421
// `ready` is called immediately. Thus, the 'reject' callback is expected to be called in 0.15 seconds aprox.
422422
setTimeout(() => {
423423
const tStart = Date.now();
424-
client.ready()
424+
client.whenReady()
425425
.then(() => {
426426
t.fail('### SDK IS READY - not TIMED OUT when it should.');
427427
})
@@ -436,7 +436,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
436436
// `ready` is called in 0.15 seconds, when the promise is just rejected. Thus, the 'reject' callback is expected to be called immediately (0 seconds aprox).
437437
setTimeout(() => {
438438
const tStart = Date.now();
439-
manager.ready()
439+
manager.whenReady()
440440
.then(() => {
441441
t.fail('### SDK IS READY - not TIMED OUT when it should.');
442442
})
@@ -451,7 +451,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
451451
// `ready` is called in 0.25 seconds, right after the promise is resolved (0.2 secs). Thus, the 'resolve' callback is expected to be called immediately (0 seconds aprox).
452452
setTimeout(() => {
453453
const tStart = Date.now();
454-
manager.ready()
454+
manager.whenReady()
455455
.then(() => {
456456
t.pass('### SDK IS READY - retry attempt finishes before the requestTimeoutBeforeReady limit');
457457
assertGetTreatmentWhenReady(t, client);
@@ -465,7 +465,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
465465
})
466466
.then(() => {
467467
client.destroy().then(() => {
468-
client.ready()
468+
client.whenReady()
469469
.then(() => {
470470
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
471471
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -506,26 +506,24 @@ export default function readyPromiseAssertions(fetchMock, assert) {
506506

507507
const splitio = SplitFactory(config);
508508

509-
const onReadycallback = function () { };
509+
const onReadyCallback = function () { };
510510

511511
// We invoke the ready method and also add and remove SDK_READY event listeners using the client and manager instances
512512
const client = splitio.client();
513-
client.ready();
514-
client.on(client.Event.SDK_READY, onReadycallback);
515-
client.off(client.Event.SDK_READY, onReadycallback);
513+
client.whenReady().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject'));
514+
client.on(client.Event.SDK_READY, onReadyCallback);
515+
client.off(client.Event.SDK_READY, onReadyCallback);
516516

517517
const manager = splitio.manager();
518-
manager.ready();
519-
manager.on(manager.Event.SDK_READY, onReadycallback);
520-
manager.off(manager.Event.SDK_READY, onReadycallback);
518+
manager.whenReadyFromCache().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject'));
519+
manager.on(manager.Event.SDK_READY, onReadyCallback);
520+
manager.off(manager.Event.SDK_READY, onReadyCallback);
521521

522522
consoleSpy.log.resetHistory();
523523
setTimeout(() => {
524-
client.ready();
524+
client.whenReadyFromCache().then((isReady) => t.true(isReady, 'SDK IS READY (& READY FROM CACHE) - Should resolve')).catch(() => t.fail('SDK TIMED OUT - Should not reject'));
525525

526526
assertGetTreatmentWhenReady(t, client);
527-
t.true(consoleSpy.log.calledWithExactly('[WARN] splitio => No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'),
528-
'Warning that there are not listeners for SDK_READY event');
529527

530528
// assert error messages when adding event listeners after SDK has already triggered them
531529
consoleSpy.log.resetHistory();
@@ -540,15 +538,15 @@ export default function readyPromiseAssertions(fetchMock, assert) {
540538
consoleSpy.log.resetHistory();
541539
const sharedClientWithCb = splitio.client('nicolas@split.io');
542540
sharedClientWithCb.on(client.Event.SDK_READY, () => {
543-
t.false(consoleSpy.log.calledWithExactly('[WARN] splitio => No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'),
541+
t.false(consoleSpy.log.calledWithExactly('[WARN] splitio => No listeners for SDK_READY event detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet synchronized with the backend.'),
544542
'No warning logged');
545543

546544
const sharedClientWithoutCb = splitio.client('emiliano@split.io');
547545
setTimeout(() => {
548-
t.true(consoleSpy.log.calledWithExactly('[WARN] splitio => No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'),
546+
t.true(consoleSpy.log.calledWithExactly('[WARN] splitio => No listeners for SDK_READY event detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet synchronized with the backend.'),
549547
'Warning logged');
550548
Promise.all([sharedClientWithoutCb.destroy(), client.destroy()]).then(() => {
551-
client.ready()
549+
client.whenReady()
552550
.then(() => {
553551
t.pass('### SDK IS READY - the promise remains resolved after client destruction.');
554552
assertGetTreatmentControlNotReadyOnDestroy(t, client);
@@ -594,18 +592,12 @@ export default function readyPromiseAssertions(fetchMock, assert) {
594592
// Assert getTreatment return CONTROL and trigger warning when SDK is not ready yet
595593
assertGetTreatmentControlNotReady(t, client);
596594

597-
client.ready()
598-
.then(() => {
599-
t.fail('### SDK IS READY - not TIMED OUT when it should.');
600-
});
601-
otherClient.ready()
602-
.then(() => {
603-
t.fail('### SDK IS READY - not TIMED OUT when it should.');
604-
});
595+
client.whenReady().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject'));
596+
otherClient.whenReady().then(() => t.fail('SDK TIMED OUT - Should not resolve')).catch(() => t.pass('SDK TIMED OUT - Should reject'));
605597

606598
setTimeout(() => {
607599
Promise.all([client.destroy(), otherClient.destroy()]).then(() => {
608-
client.ready()
600+
client.whenReady()
609601
.then(() => {
610602
t.fail('### SDK IS READY - It should not in this scenario.');
611603
t.end();

src/__tests__/browserSuites/telemetry.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ export default async function telemetryBrowserSuite(fetchMock, assert) {
100100
const data = JSON.parse(opts.body);
101101

102102
assert.true(data.tR > 0, 'timeUntilReady is larger than 0');
103-
delete data.tR; // delete to validate other properties
103+
assert.true(data.tC > 0, 'timeUntilReadyFromCache is larger than 0');
104104

105105
assert.deepEqual(data, {
106106
oM: 0, st: 'memory', aF: 1, rF: 0, sE: false,
107107
rR: { sp: 99999, ms: 60, im: 300, ev: 60, te: 1 } /* override featuresRefreshRate */,
108108
uO: { s: true, e: true, a: false, st: false, t: true } /* override sdk, events and telemetry URLs */,
109109
iQ: 30000, eQ: 500, iM: 0, iL: false, hP: false, nR: 1 /* 1 non ready usage */, t: [], i: [], uC: 2 /* Default GRANTED */,
110-
fsT: 0, fsI: 0 /* Flag sets */
110+
fsT: 0, fsI: 0 /* Flag sets */, tR: data.tR, tC: data.tC
111111
}, 'metrics/config JSON payload should be the expected');
112112

113113
finish.next();

0 commit comments

Comments
 (0)