Skip to content

Commit 9d754b8

Browse files
Update E2E tests to validate flag sets support in consumer and partial consumer modes
1 parent 61a385e commit 9d754b8

7 files changed

Lines changed: 63 additions & 25 deletions

File tree

CHANGES.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
0.13.0 (December XX, 2023)
2+
- Added support for Flag Sets in "consumer" and "partial consumer" modes (pluggable storage).
3+
- Updated @splitsoftware/splitio-commons package to version 1.12.0 that includes flag sets support for "consumer" and "partial consumer" modes.
4+
15
0.12.0 (November 3, 2023)
2-
- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
6+
- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
37
- Added new variations of the get treatment methods to support evaluating flags in given flag set/s.
48
- getTreatmentsByFlagSet and getTreatmentsByFlagSets
59
- getTreatmentsWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets
610
- Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
711
- Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
812
- Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.
9-
- Updated @splitsoftware/splitio-commons package to version 1.11.0.
13+
- Updated @splitsoftware/splitio-commons package to version 1.11.0.
1014

1115
0.11.0 (October 31, 2023)
1216
- Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager (Related to issue https://github.com/splitio/javascript-commons/issues/225).

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
@@ -64,7 +64,7 @@
6464
"bugs": "https://github.com/splitio/javascript-browser-client/issues",
6565
"homepage": "https://github.com/splitio/javascript-browser-client#readme",
6666
"dependencies": {
67-
"@splitsoftware/splitio-commons": "1.11.0",
67+
"@splitsoftware/splitio-commons": "1.12.1-rc.0",
6868
"@types/google.analytics": "0.0.40",
6969
"unfetch": "^4.2.0"
7070
},

src/__tests__/consumer/browser_consumer.spec.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType:
1515
const wrapperPrefix = 'PLUGGABLE_STORAGE_UT';
1616
const wrapperInstance = inMemoryWrapperFactory();
1717
const TOTAL_RAW_IMPRESSIONS = 18;
18+
const TOTAL_RAW_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS = 10;
1819
const TOTAL_EVENTS = 5;
1920
const DEDUPED_IMPRESSIONS = 2;
2021
const timeFrame = Date.now();
@@ -63,15 +64,17 @@ tape('Browser Consumer mode with pluggable storage', function (t) {
6364
/** Evaluation, track and manager methods before SDK_READY */
6465

6566
const getTreatmentResult = client.getTreatment('UT_IN_SEGMENT');
67+
const getTreatmentsWithConfigByFlagSetsResult = client.getTreatmentsWithConfigByFlagSets(['set_a']);
6668

6769
const namesResult = manager.names();
6870
const splitResult = manager.split(expectedSplitName);
6971
const splitsResult = manager.splits();
7072

71-
assert.equal(typeof getTreatmentResult.then, 'function', 'GetTreatment calls should always return a promise on Consumer mode.');
72-
assert.equal(await getTreatmentResult, 'control', 'Evaluations using pluggable storage should be control if initiated before SDK_READY.');
7373
assert.equal(client.__getStatus().isReadyFromCache, false, 'SDK in consumer mode is not operational inmediatelly');
7474
assert.equal(client.__getStatus().isReady, false, 'SDK in consumer mode is not operational inmediatelly');
75+
assert.equal(typeof getTreatmentResult.then, 'function', 'GetTreatment calls should always return a promise on Consumer mode.');
76+
assert.equal(await getTreatmentResult, 'control', 'Evaluations using pluggable storage should be control if initiated before SDK_READY.');
77+
assert.deepEqual(await getTreatmentsWithConfigByFlagSetsResult, {}, 'Flag sets evaluations using pluggable storage should be empty if initiated before SDK_READY.');
7578

7679
const trackResult = otherClient.track('user', 'test.event', 18);
7780
assert.equal(typeof trackResult.then, 'function', 'Track calls should always return a promise on Consumer mode.');
@@ -132,13 +135,23 @@ tape('Browser Consumer mode with pluggable storage', function (t) {
132135
assert.true(await client.track('user', 'test.event', 18), 'If the event was succesfully queued the promise will resolve to true');
133136
assert.false(await client.track(), 'If the event was NOT succesfully queued the promise will resolve to false');
134137

138+
// Evaluations with flag sets
139+
assert.deepEqual(await client.getTreatmentsByFlagSet('set_a'), { with_set_a: 'on', with_sets_a_b: 'on' }, 'Evaluations with getTreatmentsByFlagSet should be correct.');
140+
assert.deepEqual(await client.getTreatmentsByFlagSets(['set_a', 'set_b']), { with_set_a: 'on', with_set_b: 'on', with_sets_a_b: 'on' }, 'Evaluations with getTreatmentsByFlagSets should be correct.');
141+
assert.deepEqual(await client.getTreatmentsWithConfigByFlagSet('set_b'), { with_set_b: { treatment: 'on', config: '{}' }, with_sets_a_b: { treatment: 'on', config: null } }, 'Evaluations with getTreatmentsWithConfigByFlagSet should be correct.');
142+
assert.deepEqual(await client.getTreatmentsWithConfigByFlagSets(['set_a', 'set_b']), { with_set_a: { treatment: 'on', config: null }, with_set_b: { treatment: 'on', config: '{}' }, with_sets_a_b: { treatment: 'on', config: null } }, 'Evaluations with getTreatmentsWithConfigByFlagSets should be correct.');
143+
144+
assert.deepEqual(await client.getTreatmentsByFlagSet(), {}, 'Evaluations without flag set should be empty.');
145+
assert.deepEqual(await client.getTreatmentsByFlagSets([]), {}, 'Evaluations without flag sets should be empty.');
146+
assert.deepEqual(await client.getTreatmentsByFlagSets(['non_existent_set']), {}, 'Evaluations with non existent flag sets should be empty.');
147+
135148
// Manager methods
136149
const splitNames = await manager.names();
137-
assert.equal(splitNames.length, 25, 'manager `names` method returns the list of split names asynchronously');
150+
assert.equal(splitNames.length, 28, 'manager `names` method returns the list of split names asynchronously');
138151
assert.equal(splitNames.indexOf(expectedSplitName) > -1, true, 'list of split names should contain expected splits');
139152
assert.deepEqual(await manager.split(expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously');
140153
const splitViews = await manager.splits();
141-
assert.equal(splitViews.length, 25, 'manager `splits` method returns the list of split views asynchronously');
154+
assert.equal(splitViews.length, 28, 'manager `splits` method returns the list of split views asynchronously');
142155
assert.deepEqual(splitViews.find(splitView => splitView.name === expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously');
143156

144157
// New shared client created
@@ -160,7 +173,7 @@ tape('Browser Consumer mode with pluggable storage', function (t) {
160173
// Validate stored impressions and events
161174
const trackedImpressions = await wrapperInstance.popItems('PLUGGABLE_STORAGE_UT.SPLITIO.impressions', await wrapperInstance.getItemsCount('PLUGGABLE_STORAGE_UT.SPLITIO.impressions'));
162175
const trackedEvents = await wrapperInstance.popItems('PLUGGABLE_STORAGE_UT.SPLITIO.events', await wrapperInstance.getItemsCount('PLUGGABLE_STORAGE_UT.SPLITIO.events'));
163-
assert.equal(trackedImpressions.length, TOTAL_RAW_IMPRESSIONS, 'Tracked impressions should be present in the external storage');
176+
assert.equal(trackedImpressions.length, TOTAL_RAW_IMPRESSIONS + TOTAL_RAW_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS, 'Tracked impressions should be present in the external storage');
164177
assert.equal(trackedEvents.length, TOTAL_EVENTS, 'Tracked events should be present in the external storage');
165178

166179
// Validate stored telemetry
@@ -173,7 +186,7 @@ tape('Browser Consumer mode with pluggable storage', function (t) {
173186

174187
// Assert impressionsListener
175188
setTimeout(() => {
176-
assert.equal(impressions.length, TOTAL_RAW_IMPRESSIONS, 'Each evaluation has its corresponting impression');
189+
assert.equal(impressions.length, TOTAL_RAW_IMPRESSIONS + TOTAL_RAW_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS, 'Each evaluation has its corresponting impression');
177190
assert.equal(impressions[0].impression.label, SDK_NOT_READY, 'The first impression is control with label "sdk not ready"');
178191

179192
assert.end();

src/__tests__/consumer/browser_consumer_partial.spec.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType:
1515
const wrapperPrefix = 'PLUGGABLE_STORAGE_UT';
1616
const wrapperInstance = inMemoryWrapperFactory();
1717
const TOTAL_RAW_IMPRESSIONS = 17;
18+
const TOTAL_RAW_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS = 10;
19+
const TOTAL_OPTIMIZED_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS = 3;
1820
const TOTAL_EVENTS = 5;
1921

2022
/** @type SplitIO.IBrowserAsyncSettings */
@@ -51,7 +53,7 @@ tape('Browser Consumer Partial mode with pluggable storage', function (t) {
5153
const resp = JSON.parse(req.body);
5254
assert.equal(resp.reduce((prev, cur) => {
5355
return prev + cur.i.length;
54-
}, 0), TOTAL_RAW_IMPRESSIONS - 1, 'Impressions were deduped');
56+
}, 0), TOTAL_RAW_IMPRESSIONS - 1 + TOTAL_OPTIMIZED_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS, 'Impressions were deduped');
5557
return 200;
5658
});
5759

@@ -89,15 +91,17 @@ tape('Browser Consumer Partial mode with pluggable storage', function (t) {
8991
/** Evaluation, track and manager methods before SDK_READY */
9092

9193
const getTreatmentResult = client.getTreatment('UT_IN_SEGMENT');
94+
const getTreatmentsWithConfigByFlagSetsResult = client.getTreatmentsWithConfigByFlagSets(['set_a']);
9295

9396
const namesResult = manager.names();
9497
const splitResult = manager.split(expectedSplitName);
9598
const splitsResult = manager.splits();
9699

97-
assert.equal(typeof getTreatmentResult.then, 'function', 'GetTreatment calls should always return a promise on Consumer mode.');
98-
assert.equal(await getTreatmentResult, 'control', 'Evaluations using pluggable storage should be control if initiated before SDK_READY.');
99100
assert.equal(client.__getStatus().isReadyFromCache, false, 'SDK in consumer mode is not operational inmediatelly');
100101
assert.equal(client.__getStatus().isReady, false, 'SDK in consumer mode is not operational inmediatelly');
102+
assert.equal(typeof getTreatmentResult.then, 'function', 'GetTreatment calls should always return a promise on Consumer mode.');
103+
assert.equal(await getTreatmentResult, 'control', 'Evaluations using pluggable storage should be control if initiated before SDK_READY.');
104+
assert.deepEqual(await getTreatmentsWithConfigByFlagSetsResult, {}, 'Flag sets evaluations using pluggable storage should be empty if initiated before SDK_READY.');
101105

102106
const trackResult = otherClient.track('user', 'test.event', 18);
103107
assert.equal(typeof trackResult.then, 'function', 'Track calls should always return a promise on Consumer mode.');
@@ -157,13 +161,23 @@ tape('Browser Consumer Partial mode with pluggable storage', function (t) {
157161
assert.true(await client.track('user', 'test.event', 18), 'If the event was succesfully queued the promise will resolve to true');
158162
assert.false(await client.track(), 'If the event was NOT succesfully queued the promise will resolve to false');
159163

164+
// Evaluations with flag sets
165+
assert.deepEqual(await client.getTreatmentsByFlagSet('set_a'), { with_set_a: 'on', with_sets_a_b: 'on' }, 'Evaluations with getTreatmentsByFlagSet should be correct.');
166+
assert.deepEqual(await client.getTreatmentsByFlagSets(['set_a', 'set_b']), { with_set_a: 'on', with_set_b: 'on', with_sets_a_b: 'on' }, 'Evaluations with getTreatmentsByFlagSets should be correct.');
167+
assert.deepEqual(await client.getTreatmentsWithConfigByFlagSet('set_b'), { with_set_b: { treatment: 'on', config: '{}' }, with_sets_a_b: { treatment: 'on', config: null } }, 'Evaluations with getTreatmentsWithConfigByFlagSet should be correct.');
168+
assert.deepEqual(await client.getTreatmentsWithConfigByFlagSets(['set_a', 'set_b']), { with_set_a: { treatment: 'on', config: null }, with_set_b: { treatment: 'on', config: '{}' }, with_sets_a_b: { treatment: 'on', config: null } }, 'Evaluations with getTreatmentsWithConfigByFlagSets should be correct.');
169+
170+
assert.deepEqual(await client.getTreatmentsByFlagSet(), {}, 'Evaluations without flag set should be empty.');
171+
assert.deepEqual(await client.getTreatmentsByFlagSets([]), {}, 'Evaluations without flag sets should be empty.');
172+
assert.deepEqual(await client.getTreatmentsByFlagSets(['non_existent_set']), {}, 'Evaluations with non existent flag sets should be empty.');
173+
160174
// Manager methods
161175
const splitNames = await manager.names();
162-
assert.equal(splitNames.length, 25, 'manager `names` method returns the list of split names asynchronously');
176+
assert.equal(splitNames.length, 28, 'manager `names` method returns the list of split names asynchronously');
163177
assert.equal(splitNames.indexOf(expectedSplitName) > -1, true, 'list of split names should contain expected splits');
164178
assert.deepEqual(await manager.split(expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously');
165179
const splitViews = await manager.splits();
166-
assert.equal(splitViews.length, 25, 'manager `splits` method returns the list of split views asynchronously');
180+
assert.equal(splitViews.length, 28, 'manager `splits` method returns the list of split views asynchronously');
167181
assert.deepEqual(splitViews.find(splitView => splitView.name === expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously');
168182

169183
// New shared client created
@@ -187,7 +201,7 @@ tape('Browser Consumer Partial mode with pluggable storage', function (t) {
187201

188202
// Assert impressionsListener
189203
setTimeout(() => {
190-
assert.equal(impressions.length, TOTAL_RAW_IMPRESSIONS, 'Each evaluation has its corresponting impression');
204+
assert.equal(impressions.length, TOTAL_RAW_IMPRESSIONS + TOTAL_RAW_IMPRESSIONS_IN_EVALUATIONS_WITH_FLAGSETS, 'Each evaluation has its corresponting impression');
191205
assert.equal(impressions[0].impression.label, SDK_NOT_READY, 'The first impression is control with label "sdk not ready"');
192206

193207
assert.end();
@@ -342,6 +356,9 @@ tape('Browser Consumer Partial mode with pluggable storage', function (t) {
342356
});
343357

344358
t.test('Wrapper connection error timeouts the SDK immediately', (assert) => {
359+
fetchMock.postOnce(url(config, '/events/bulk'), 200);
360+
fetchMock.postOnce(url(config, '/testImpressions/bulk'), 200);
361+
345362
// Mock a wrapper connection error
346363
sinon.stub(wrapperInstance, 'connect').callsFake(() => { Promise.reject(); });
347364
const getSpy = sinon.spy(wrapperInstance, 'get');

0 commit comments

Comments
 (0)