Skip to content

Commit 10f2fcc

Browse files
authored
Sameeran/ff 924 update js sdk common with allocation key (#12)
* Rename experimentKey to flagKey and add new keys to event interface * Include allocation key in get assignment internal output and and update post assignment functions to optionally use it * Include allocationKey in logAssignment call * Fix missing allocationKey null check * Update language in test to flagKey * Make getAssignmentVariation function to reduce code repetition * Add isExpectedType method and return null if the the wrong getTypedAssignment method was called * eslint warnings * More eslint * Use eslint prettier to format
1 parent 8d375a4 commit 10f2fcc

File tree

5 files changed

+177
-123
lines changed

5 files changed

+177
-123
lines changed

src/assignment-hooks.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,27 @@ export interface IAssignmentHooks {
88
/**
99
* Invoked before a subject is assigned to an experiment variation.
1010
*
11-
* @param experimentKey key of the experiment being assigned
11+
* @param flagKey key of the feature flag being used for assignment
1212
* @param subject id of subject being assigned
1313
* @returns variation to override for the given subject. If null is returned,
1414
* then the subject will be assigned with the default assignment logic.
1515
* @public
1616
*/
17-
onPreAssignment(experimentKey: string, subject: string): EppoValue | null;
17+
onPreAssignment(flagKey: string, subject: string): EppoValue | null;
1818

1919
/**
2020
* Invoked after a subject is assigned. Useful for any post assignment logic needed which is specific
21-
* to an experiment/flag. Do not use this for logging assignments - use IAssignmentLogger instead.
22-
* @param experimentKey key of the experiment being assigned
21+
* to a flag or allocation. Do not use this for logging assignments - use IAssignmentLogger instead.
22+
* @param flagKey key of the feature flag being used for assignment
2323
* @param subject id of subject being assigned
2424
* @param variation the assigned variation
25+
* @param allocationKey key of the allocation being used for assignment
2526
* @public
2627
*/
27-
onPostAssignment(experimentKey: string, subject: string, variation: EppoValue | null): void;
28+
onPostAssignment(
29+
flagKey: string,
30+
subject: string,
31+
variation: EppoValue | null,
32+
allocationKey?: string | null,
33+
): void;
2834
}

src/assignment-logger.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@
33
* @public
44
*/
55
export interface IAssignmentEvent {
6+
/**
7+
* An Eppo allocation key
8+
*/
9+
allocation: string;
10+
611
/**
712
* An Eppo experiment key
813
*/
914
experiment: string;
1015

16+
/**
17+
* An Eppo feature flag key
18+
*/
19+
featureFlag: string;
20+
1121
/**
1222
* The assigned variation
1323
*/

src/client/eppo-client.spec.ts

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ describe('EppoClient E2E test', () => {
8080
mock.teardown();
8181
});
8282

83-
const experimentName = 'mock-experiment';
83+
const flagKey = 'mock-experiment';
8484

8585
const mockExperimentConfig = {
86-
name: experimentName,
86+
name: flagKey,
8787
enabled: true,
8888
subjectShards: 100,
8989
overrides: {},
@@ -132,14 +132,14 @@ describe('EppoClient E2E test', () => {
132132

133133
describe('setLogger', () => {
134134
beforeAll(() => {
135-
storage.setEntries({ [experimentName]: mockExperimentConfig });
135+
storage.setEntries({ [flagKey]: mockExperimentConfig });
136136
});
137137

138138
it('Invokes logger for queued events', () => {
139139
const mockLogger = td.object<IAssignmentLogger>();
140140

141141
const client = new EppoClient(storage);
142-
client.getAssignment('subject-to-be-logged', experimentName);
142+
client.getAssignment('subject-to-be-logged', flagKey);
143143
client.setLogger(mockLogger);
144144

145145
expect(td.explain(mockLogger.logAssignment).callCount).toEqual(1);
@@ -153,7 +153,7 @@ describe('EppoClient E2E test', () => {
153153

154154
const client = new EppoClient(storage);
155155

156-
client.getAssignment('subject-to-be-logged', experimentName);
156+
client.getAssignment('subject-to-be-logged', flagKey);
157157
client.setLogger(mockLogger);
158158
expect(td.explain(mockLogger.logAssignment).callCount).toEqual(1);
159159

@@ -166,7 +166,7 @@ describe('EppoClient E2E test', () => {
166166

167167
const client = new EppoClient(storage);
168168
for (let i = 0; i < MAX_EVENT_QUEUE_SIZE + 100; i++) {
169-
client.getAssignment(`subject-to-be-logged-${i}`, experimentName);
169+
client.getAssignment(`subject-to-be-logged-${i}`, flagKey);
170170
}
171171
client.setLogger(mockLogger);
172172
expect(td.explain(mockLogger.logAssignment).callCount).toEqual(MAX_EVENT_QUEUE_SIZE);
@@ -218,7 +218,7 @@ describe('EppoClient E2E test', () => {
218218

219219
it('returns subject from overrides when enabled is true', () => {
220220
window.localStorage.setItem(
221-
experimentName,
221+
flagKey,
222222
JSON.stringify({
223223
...mockExperimentConfig,
224224
typedOverrides: {
@@ -227,7 +227,7 @@ describe('EppoClient E2E test', () => {
227227
}),
228228
);
229229
const client = new EppoClient(storage);
230-
const assignment = client.getAssignment('subject-10', experimentName);
230+
const assignment = client.getAssignment('subject-10', flagKey);
231231
expect(assignment).toEqual('control');
232232
});
233233

@@ -240,22 +240,22 @@ describe('EppoClient E2E test', () => {
240240
},
241241
};
242242

243-
storage.setEntries({ [experimentName]: entry });
243+
storage.setEntries({ [flagKey]: entry });
244244

245245
const client = new EppoClient(storage);
246-
const assignment = client.getAssignment('subject-10', experimentName);
246+
const assignment = client.getAssignment('subject-10', flagKey);
247247
expect(assignment).toEqual('control');
248248
});
249249

250250
it('logs variation assignment', () => {
251251
const mockLogger = td.object<IAssignmentLogger>();
252252

253-
storage.setEntries({ [experimentName]: mockExperimentConfig });
253+
storage.setEntries({ [flagKey]: mockExperimentConfig });
254254
const client = new EppoClient(storage);
255255
client.setLogger(mockLogger);
256256

257257
const subjectAttributes = { foo: 3 };
258-
const assignment = client.getAssignment('subject-10', experimentName, subjectAttributes);
258+
const assignment = client.getAssignment('subject-10', flagKey, subjectAttributes);
259259

260260
expect(assignment).toEqual('control');
261261
expect(td.explain(mockLogger.logAssignment).callCount).toEqual(1);
@@ -266,12 +266,12 @@ describe('EppoClient E2E test', () => {
266266
const mockLogger = td.object<IAssignmentLogger>();
267267
td.when(mockLogger.logAssignment(td.matchers.anything())).thenThrow(new Error('logging error'));
268268

269-
storage.setEntries({ [experimentName]: mockExperimentConfig });
269+
storage.setEntries({ [flagKey]: mockExperimentConfig });
270270
const client = new EppoClient(storage);
271271
client.setLogger(mockLogger);
272272

273273
const subjectAttributes = { foo: 3 };
274-
const assignment = client.getAssignment('subject-10', experimentName, subjectAttributes);
274+
const assignment = client.getAssignment('subject-10', flagKey, subjectAttributes);
275275

276276
expect(assignment).toEqual('control');
277277
});
@@ -293,14 +293,14 @@ describe('EppoClient E2E test', () => {
293293
],
294294
};
295295

296-
storage.setEntries({ [experimentName]: entry });
296+
storage.setEntries({ [flagKey]: entry });
297297

298298
const client = new EppoClient(storage);
299-
let assignment = client.getAssignment('subject-10', experimentName, { appVersion: 9 });
299+
let assignment = client.getAssignment('subject-10', flagKey, { appVersion: 9 });
300300
expect(assignment).toEqual(null);
301-
assignment = client.getAssignment('subject-10', experimentName);
301+
assignment = client.getAssignment('subject-10', flagKey);
302302
expect(assignment).toEqual(null);
303-
assignment = client.getAssignment('subject-10', experimentName, { appVersion: 11 });
303+
assignment = client.getAssignment('subject-10', flagKey, { appVersion: 11 });
304304
expect(assignment).toEqual('control');
305305
});
306306

@@ -376,23 +376,23 @@ describe('EppoClient E2E test', () => {
376376
let client: EppoClient;
377377

378378
beforeAll(() => {
379-
storage.setEntries({ [experimentName]: mockExperimentConfig });
379+
storage.setEntries({ [flagKey]: mockExperimentConfig });
380380
client = new EppoClient(storage);
381381
});
382382

383383
describe('onPreAssignment', () => {
384384
it('called with experiment key and subject id', () => {
385385
const mockHooks = td.object<IAssignmentHooks>();
386-
client.getAssignment('subject-identifer', experimentName, {}, mockHooks);
386+
client.getAssignment('subject-identifer', flagKey, {}, mockHooks);
387387
expect(td.explain(mockHooks.onPreAssignment).callCount).toEqual(1);
388-
expect(td.explain(mockHooks.onPreAssignment).calls[0].args[0]).toEqual(experimentName);
388+
expect(td.explain(mockHooks.onPreAssignment).calls[0].args[0]).toEqual(flagKey);
389389
expect(td.explain(mockHooks.onPreAssignment).calls[0].args[1]).toEqual('subject-identifer');
390390
});
391391

392392
it('overrides returned assignment', async () => {
393393
const variation = await client.getAssignment(
394394
'subject-identifer',
395-
experimentName,
395+
flagKey,
396396
{},
397397
{
398398
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -402,9 +402,9 @@ describe('EppoClient E2E test', () => {
402402

403403
// eslint-disable-next-line @typescript-eslint/no-unused-vars
404404
onPostAssignment(
405-
experimentKey: string,
406-
subject: string,
407-
variation: EppoValue | null,
405+
experimentKey: string, // eslint-disable-line @typescript-eslint/no-unused-vars
406+
subject: string, // eslint-disable-line @typescript-eslint/no-unused-vars
407+
variation: EppoValue | null, // eslint-disable-line @typescript-eslint/no-unused-vars
408408
): void {
409409
// no-op
410410
},
@@ -417,19 +417,18 @@ describe('EppoClient E2E test', () => {
417417
it('uses regular assignment logic if onPreAssignment returns null', async () => {
418418
const variation = await client.getAssignment(
419419
'subject-identifer',
420-
experimentName,
420+
flagKey,
421421
{},
422422
{
423423
// eslint-disable-next-line @typescript-eslint/no-unused-vars
424424
onPreAssignment(experimentKey: string, subject: string): EppoValue | null {
425425
return null;
426426
},
427427

428-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
429428
onPostAssignment(
430-
experimentKey: string,
431-
subject: string,
432-
variation: EppoValue | null,
429+
experimentKey: string, // eslint-disable-line @typescript-eslint/no-unused-vars
430+
subject: string, // eslint-disable-line @typescript-eslint/no-unused-vars
431+
variation: EppoValue | null, // eslint-disable-line @typescript-eslint/no-unused-vars
433432
): void {
434433
// no-op
435434
},
@@ -444,10 +443,10 @@ describe('EppoClient E2E test', () => {
444443
it('called with assigned variation after assignment', async () => {
445444
const mockHooks = td.object<IAssignmentHooks>();
446445
const subject = 'subject-identifier';
447-
const variation = client.getAssignment(subject, experimentName, {}, mockHooks);
446+
const variation = client.getAssignment(subject, flagKey, {}, mockHooks);
448447
expect(td.explain(mockHooks.onPostAssignment).callCount).toEqual(1);
449448
expect(td.explain(mockHooks.onPostAssignment).callCount).toEqual(1);
450-
expect(td.explain(mockHooks.onPostAssignment).calls[0].args[0]).toEqual(experimentName);
449+
expect(td.explain(mockHooks.onPostAssignment).calls[0].args[0]).toEqual(flagKey);
451450
expect(td.explain(mockHooks.onPostAssignment).calls[0].args[1]).toEqual(subject);
452451
expect(td.explain(mockHooks.onPostAssignment).calls[0].args[2]).toEqual(
453452
EppoValue.String(variation ?? ''),

0 commit comments

Comments
 (0)