Skip to content

Commit 9ebbab6

Browse files
Fix tests
1 parent 2a326b5 commit 9ebbab6

File tree

2 files changed

+50
-53
lines changed

2 files changed

+50
-53
lines changed

CHANGES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
- Added two new configuration options for the SDK's `InLocalStorage` module to control the behavior of the persisted rollout plan cache in the browser:
33
- `expirationDays` to specify the validity period of the rollout plan cache in days.
44
- `clearOnInit` to clear the rollout plan cache on SDK initialization.
5-
- Updated SDK_READY_FROM_CACHE event when using the `LOCALSTORAGE` storage type to be emitted alongside the SDK_READY event if it has not already been emitted.
5+
- Updated SDK_READY_FROM_CACHE event when using `InLocalStorage` to be emitted alongside the SDK_READY event if it has not already been emitted.
66
- Updated @splitsoftware/splitio-commons package to version 2.2.0.
77

88
1.1.0 (January 17, 2025)

src/__tests__/browserSuites/ready-from-cache.spec.js

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export default function (fetchMock, assert) {
9494
events: 'https://events.baseurl/readyFromCacheEmpty'
9595
};
9696
localStorage.clear();
97-
t.plan(3);
97+
t.plan(4);
9898

9999
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: splitChangesMock1 });
100100
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
@@ -122,18 +122,17 @@ export default function (fetchMock, assert) {
122122
t.end();
123123
});
124124
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
125-
t.fail('It should not emit SDK_READY_FROM_CACHE if there is no cache.');
126-
t.end();
125+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
127126
});
128127

129128
client.on(client.Event.SDK_READY, () => {
130-
t.pass('It should emit SDK_READY alone, since there was no cache.');
129+
t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
131130
});
132131
client2.on(client.Event.SDK_READY, () => {
133-
t.pass('It should emit SDK_READY alone, since there was no cache.');
132+
t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
134133
});
135134
client3.on(client.Event.SDK_READY, () => {
136-
t.pass('It should emit SDK_READY alone, since there was no cache.');
135+
t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
137136
});
138137

139138
});
@@ -146,17 +145,17 @@ export default function (fetchMock, assert) {
146145
localStorage.clear();
147146
t.plan(12 * 2 + 3);
148147

149-
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', function () {
148+
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', () => {
150149
return new Promise(res => { setTimeout(() => res({ status: 200, body: { ...splitChangesMock1, since: 25 }, headers: {} }), 200); }); // 400ms is how long it'll take to reply with Splits, no SDK_READY should be emitted before that.
151150
});
152151
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
153-
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
152+
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
154153
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
155154
});
156-
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
155+
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
157156
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
158157
});
159-
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
158+
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
160159
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
161160
});
162161
fetchMock.postOnce(testUrls.events + '/testImpressions/bulk', 200);
@@ -252,18 +251,18 @@ export default function (fetchMock, assert) {
252251
localStorage.clear();
253252
t.plan(12 * 2 + 5);
254253

255-
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', function () {
254+
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', () => {
256255
t.equal(localStorage.getItem('readyFromCache_3.SPLITIO.split.always_on'), alwaysOnSplitInverted, 'feature flags must not be cleaned from cache');
257256
return new Promise(res => { setTimeout(() => res({ status: 200, body: { ...splitChangesMock1, since: 25 }, headers: {} }), 200); }); // 400ms is how long it'll take to reply with Splits, no SDK_READY should be emitted before that.
258257
});
259258
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
260-
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
259+
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
261260
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
262261
});
263-
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
262+
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
264263
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
265264
});
266-
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
265+
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
267266
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
268267
});
269268
fetchMock.get(testUrls.sdk + '/memberships/nicolas4%40split.io', { 'ms': {} });
@@ -361,28 +360,30 @@ export default function (fetchMock, assert) {
361360
});
362361

363362
assert.test(t => { // Testing when we start with cached data but expired (lastUpdate timestamp lower than custom (1) expirationDays ago)
363+
const CLIENT_READY_MS = 400, CLIENT2_READY_MS = 700, CLIENT3_READY_MS = 1000;
364+
364365
const testUrls = {
365366
sdk: 'https://sdk.baseurl/readyFromCacheWithData4',
366367
events: 'https://events.baseurl/readyFromCacheWithData4'
367368
};
368369
localStorage.clear();
369370

370-
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', function () {
371+
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', () => {
371372
t.equal(localStorage.getItem('some_user_item'), 'user_item', 'user items at localStorage must not be changed');
372373
t.equal(localStorage.getItem('readyFromCache_4.SPLITIO.hash'), expectedHashNullFilter, 'storage hash must not be changed');
373374
t.true(nearlyEqual(parseInt(localStorage.getItem('readyFromCache_4.SPLITIO.lastClear'), 10), Date.now()), 'storage lastClear timestamp must be updated');
374375
t.equal(localStorage.length, 3, 'feature flags cache data must be cleaned from localStorage');
375376
return { status: 200, body: splitChangesMock1 };
376377
});
377378
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
378-
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
379-
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
379+
fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
380+
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), CLIENT_READY_MS); }); // First client gets segments before splits. No segment cache loading (yet)
380381
});
381-
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
382-
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
382+
fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
383+
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), CLIENT2_READY_MS); }); // Second client gets segments after 700ms
383384
});
384-
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
385-
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
385+
fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
386+
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), CLIENT3_READY_MS); }); // Third client memberships will come after 1s
386387
});
387388
fetchMock.postOnce(testUrls.events + '/testImpressions/bulk', 200);
388389
fetchMock.postOnce(testUrls.events + '/testImpressions/count', 200);
@@ -418,37 +419,34 @@ export default function (fetchMock, assert) {
418419
});
419420

420421
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
421-
t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
422-
t.end();
422+
t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
423423
});
424424
client2.once(client2.Event.SDK_READY_FROM_CACHE, () => {
425-
t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
426-
t.end();
425+
t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
427426
});
428427
client3.once(client3.Event.SDK_READY_FROM_CACHE, () => {
429-
t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
430-
t.end();
428+
t.true(nearlyEqual(Date.now() - startTime, CLIENT3_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
431429
});
432430

433431
client.on(client.Event.SDK_READY, () => {
434-
t.true(Date.now() - startTime >= 400, 'It should emit SDK_READY after syncing with the cloud.');
432+
t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should emit SDK_READY after syncing with the cloud.');
435433
t.equal(client.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
436434
});
437435
client.ready().then(() => {
438-
t.true(Date.now() - startTime >= 400, 'It should resolve ready promise after syncing with the cloud.');
436+
t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
439437
t.equal(client.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
440438
});
441439
client2.on(client2.Event.SDK_READY, () => {
442-
t.true(Date.now() - startTime >= 700, 'It should emit SDK_READY after syncing with the cloud.');
440+
t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should emit SDK_READY after syncing with the cloud.');
443441
t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
444442
});
445443
client2.ready().then(() => {
446-
t.true(Date.now() - startTime >= 700, 'It should resolve ready promise after syncing with the cloud.');
444+
t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
447445
t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
448446
});
449447
client3.on(client3.Event.SDK_READY, () => {
450448
client3.ready().then(() => {
451-
t.true(Date.now() - startTime >= 1000, 'It should resolve ready promise after syncing with the cloud.');
449+
t.true(nearlyEqual(Date.now() - startTime, CLIENT3_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
452450
t.equal(client3.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
453451

454452
// Last cb: destroy clients and check that localstorage has the expected items
@@ -481,7 +479,7 @@ export default function (fetchMock, assert) {
481479
events: 'https://events.baseurl/readyFromCache_5'
482480
};
483481
localStorage.clear();
484-
t.plan(7);
482+
t.plan(8);
485483

486484
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=p1__split,p2__split', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
487485
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -506,8 +504,7 @@ export default function (fetchMock, assert) {
506504
const manager = splitio.manager();
507505

508506
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
509-
t.fail('It should not emit SDK_READY_FROM_CACHE because localStorage is cleaned and there isn\'t cached feature flags');
510-
t.end();
507+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
511508
});
512509

513510
client.once(client.Event.SDK_READY, () => {
@@ -531,7 +528,7 @@ export default function (fetchMock, assert) {
531528
events: 'https://events.baseurl/readyFromCache_5B'
532529
};
533530
localStorage.clear();
534-
t.plan(5);
531+
t.plan(6);
535532

536533
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=p1__split,p2__split', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
537534
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -550,8 +547,7 @@ export default function (fetchMock, assert) {
550547
const manager = splitio.manager();
551548

552549
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
553-
t.fail('It should not emit SDK_READY_FROM_CACHE if cache is empty.');
554-
t.end();
550+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
555551
});
556552

557553
client.once(client.Event.SDK_READY, () => {
@@ -622,7 +618,7 @@ export default function (fetchMock, assert) {
622618
events: 'https://events.baseurl/readyFromCache_7'
623619
};
624620
localStorage.clear();
625-
t.plan(6);
621+
t.plan(7);
626622

627623
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&prefixes=p1,p2', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
628624
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -650,8 +646,7 @@ export default function (fetchMock, assert) {
650646
const manager = splitio.manager();
651647

652648
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
653-
t.fail('It should not emit SDK_READY_FROM_CACHE if cache has expired.');
654-
t.end();
649+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
655650
});
656651

657652
client.once(client.Event.SDK_READY, () => {
@@ -687,7 +682,7 @@ export default function (fetchMock, assert) {
687682
events: 'https://events.baseurl/readyFromCache_8'
688683
};
689684
localStorage.clear();
690-
t.plan(7);
685+
t.plan(8);
691686

692687
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split, splitDeclarations.p3__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
693688
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -711,8 +706,7 @@ export default function (fetchMock, assert) {
711706
const manager = splitio.manager();
712707

713708
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
714-
t.fail('It should not emit SDK_READY_FROM_CACHE because all feature flags were removed from cache since the filter query changed.');
715-
t.end();
709+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
716710
});
717711

718712
client.once(client.Event.SDK_READY, () => {
@@ -739,7 +733,7 @@ export default function (fetchMock, assert) {
739733
events: 'https://events.baseurl/readyFromCache_9'
740734
};
741735
localStorage.clear();
742-
t.plan(6);
736+
t.plan(7);
743737

744738
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=no%20exist%20trim,no_exist,p3__split&prefixes=no%20exist%20trim,p2', { status: 200, body: { splits: [splitDeclarations.p2__split, splitDeclarations.p3__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
745739
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -764,8 +758,7 @@ export default function (fetchMock, assert) {
764758
const manager = splitio.manager();
765759

766760
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
767-
t.fail('It should not emit SDK_READY_FROM_CACHE because all feature flags were removed from cache since the filter query changed.');
768-
t.end();
761+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
769762
});
770763

771764
client.once(client.Event.SDK_READY, () => {
@@ -817,10 +810,12 @@ export default function (fetchMock, assert) {
817810

818811
t.true(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
819812

820-
client.once(client.Event.SDK_READY_FROM_CACHE, () => t.fail('It should not emit SDK_READY_FROM_CACHE because clearOnInit is true.'));
813+
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
814+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true');
815+
});
821816

822817
await client.ready();
823-
t.equal(manager.names().sort().length, 32, 'active splits should be present for evaluation');
818+
t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
824819

825820
await splitio.destroy();
826821
t.equal(localStorage.getItem('readyFromCache_10.SPLITIO.splits.till'), '1457552620999', 'splits.till must correspond to the till of the last successfully fetched Splits');
@@ -837,7 +832,7 @@ export default function (fetchMock, assert) {
837832

838833
await new Promise(res => client.once(client.Event.SDK_READY_FROM_CACHE, res));
839834

840-
t.equal(manager.names().sort().length, 32, 'active splits should be present for evaluation');
835+
t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
841836
t.false(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
842837

843838
await splitio.destroy();
@@ -852,11 +847,13 @@ export default function (fetchMock, assert) {
852847
client = splitio.client();
853848
manager = splitio.manager();
854849

855-
client.once(client.Event.SDK_READY_FROM_CACHE, () => t.fail('It should not emit SDK_READY_FROM_CACHE because clearOnInit is true.'));
850+
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
851+
t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true');
852+
});
856853

857854
await new Promise(res => client.once(client.Event.SDK_READY, res));
858855

859-
t.equal(manager.names().sort().length, 32, 'active splits should be present for evaluation');
856+
t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
860857
t.true(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
861858

862859
await splitio.destroy();

0 commit comments

Comments
 (0)