Skip to content

Commit 2ae883b

Browse files
Merge pull request #102 from Flagsmith/release/2.5.1
Release 2.5.1
2 parents 5d9a8e1 + cf8da43 commit 2ae883b

File tree

5 files changed

+97
-28
lines changed

5 files changed

+97
-28
lines changed

package-lock.json

Lines changed: 8 additions & 26 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
@@ -1,6 +1,6 @@
11
{
22
"name": "flagsmith-nodejs",
3-
"version": "2.5.0",
3+
"version": "2.5.1",
44
"description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.",
55
"main": "build/index.js",
66
"repository": {

sdk/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ export class Flagsmith {
173173
* @returns Flags object holding all the flags for the given identity.
174174
*/
175175
async getIdentityFlags(identifier: string, traits?: { [key: string]: any }): Promise<Flags> {
176+
if (!identifier) {
177+
throw new Error("`identifier` argument is missing or invalid.")
178+
}
179+
176180
const cachedItem = !!this.cache && await this.cache.get(`flags-${identifier}`);
177181
if (!!cachedItem) {
178182
return cachedItem;
@@ -203,6 +207,10 @@ export class Flagsmith {
203207
identifier: string,
204208
traits?: { [key: string]: any }
205209
): Promise<SegmentModel[]> {
210+
if (!identifier) {
211+
throw new Error("`identifier` argument is missing or invalid.")
212+
}
213+
206214
traits = traits || {};
207215
if (this.enableLocalEvaluation) {
208216
return new Promise((resolve, reject) => {
@@ -329,7 +337,7 @@ export class Flagsmith {
329337
featureStates: featureStates,
330338
analyticsProcessor: this.analyticsProcessor,
331339
defaultFlagHandler: this.defaultFlagHandler,
332-
identityID: identityModel.djangoID || identityModel.identityUuid
340+
identityID: identityModel.djangoID || identityModel.compositeKey
333341
});
334342

335343
if (!!this.cache) {

tests/engine/unit/utils/utils.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { v4 as uuidv4 } from 'uuid';
2+
import { getHashedPercentateForObjIds } from '../../../../flagsmith-engine/utils/hashing';
3+
4+
describe('getHashedPercentageForObjIds', () => {
5+
it.each([
6+
[[12, 93]],
7+
[[uuidv4(), 99]],
8+
[[99, uuidv4()]],
9+
[[uuidv4(), uuidv4()]]
10+
])('returns x where 0 <= x < 100', (objIds: (string|number)[]) => {
11+
let result = getHashedPercentateForObjIds(objIds);
12+
expect(result).toBeLessThan(100);
13+
expect(result).toBeGreaterThanOrEqual(0);
14+
});
15+
16+
it.each([
17+
[[12, 93]],
18+
[[uuidv4(), 99]],
19+
[[99, uuidv4()]],
20+
[[uuidv4(), uuidv4()]]
21+
])('returns the same value each time', (objIds: (string|number)[]) => {
22+
let resultOne = getHashedPercentateForObjIds(objIds);
23+
let resultTwo = getHashedPercentateForObjIds(objIds);
24+
expect(resultOne).toEqual(resultTwo);
25+
})
26+
27+
it('is unique for different object ids', () => {
28+
let resultOne = getHashedPercentateForObjIds([14, 106]);
29+
let resultTwo = getHashedPercentateForObjIds([53, 200]);
30+
expect(resultOne).not.toEqual(resultTwo);
31+
})
32+
33+
it('is evenly distributed', () => {
34+
// copied from python test here:
35+
// https://github.com/Flagsmith/flagsmith-engine/blob/main/tests/unit/utils/test_utils_hashing.py#L56
36+
const testSample = 500;
37+
const numTestBuckets = 50;
38+
const testBucketSize = Math.floor(testSample / numTestBuckets)
39+
const errorFactor = 0.1
40+
41+
// Given
42+
let objectIdPairs = Array.from(Array(testSample).keys()).flatMap(d => Array.from(Array(testSample).keys()).map(e => [d, e].flat()))
43+
44+
// When
45+
console.log(objectIdPairs);
46+
let values = objectIdPairs.map((objIds) => getHashedPercentateForObjIds(objIds));
47+
48+
// Then
49+
for (let i = 0; i++; i < numTestBuckets) {
50+
let bucketStart = i * testBucketSize;
51+
let bucketEnd = (i + 1) * testBucketSize;
52+
let bucketValueLimit = Math.min(
53+
(i + 1) / numTestBuckets + errorFactor + ((i + 1) / numTestBuckets),
54+
1
55+
)
56+
57+
for (let i = bucketStart; i++; i < bucketEnd) {
58+
expect(values[i]).toBeLessThanOrEqual(bucketValueLimit);
59+
}
60+
}
61+
})
62+
})

tests/sdk/flagsmith.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,23 @@ test('test onEnvironmentChange is called after error', async () => {
227227
expect(callbackSpy).toBeCalled();
228228
});
229229

230+
test('getIdentityFlags throws error if identifier is empty string', async () => {
231+
const flagsmith = new Flagsmith({
232+
environmentKey: 'key',
233+
});
234+
235+
await expect(flagsmith.getIdentityFlags('')).rejects.toThrow('`identifier` argument is missing or invalid.');
236+
})
237+
238+
239+
test('getIdentitySegments throws error if identifier is empty string', () => {
240+
const flagsmith = new Flagsmith({
241+
environmentKey: 'key',
242+
});
243+
244+
expect(() => { flagsmith.getIdentitySegments(''); }).toThrow('`identifier` argument is missing or invalid.');
245+
})
246+
230247

231248

232249
async function wipeFeatureStateUUIDs (enviromentModel: EnvironmentModel) {

0 commit comments

Comments
 (0)