flagsmith-nodejs 6.0.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.github/workflows/conventional-commit.yml +29 -0
  2. package/.github/workflows/pull_request.yaml +1 -1
  3. package/.github/workflows/release-please.yml +18 -0
  4. package/.gitmodules +1 -0
  5. package/.husky/pre-commit +0 -0
  6. package/.prettierignore +2 -1
  7. package/.prettierrc.cjs +9 -1
  8. package/.release-please-manifest.json +1 -0
  9. package/CHANGELOG.md +552 -0
  10. package/CODEOWNERS +1 -0
  11. package/README.md +2 -3
  12. package/build/cjs/flagsmith-engine/features/util.js +3 -3
  13. package/build/cjs/flagsmith-engine/index.d.ts +1 -1
  14. package/build/cjs/flagsmith-engine/index.js +2 -1
  15. package/build/cjs/flagsmith-engine/segments/models.js +7 -7
  16. package/build/cjs/flagsmith-engine/utils/hashing/index.js +1 -1
  17. package/build/cjs/index.d.ts +4 -4
  18. package/build/cjs/index.js +3 -1
  19. package/build/cjs/sdk/analytics.d.ts +1 -1
  20. package/build/cjs/sdk/analytics.js +3 -1
  21. package/build/cjs/sdk/index.d.ts +5 -5
  22. package/build/cjs/sdk/index.js +48 -10
  23. package/build/cjs/sdk/models.d.ts +25 -0
  24. package/build/cjs/sdk/models.js +25 -0
  25. package/build/cjs/sdk/types.d.ts +14 -4
  26. package/build/cjs/sdk/utils.d.ts +5 -4
  27. package/build/cjs/sdk/utils.js +16 -3
  28. package/build/esm/flagsmith-engine/features/models.js +1 -1
  29. package/build/esm/flagsmith-engine/features/util.js +3 -3
  30. package/build/esm/flagsmith-engine/index.d.ts +1 -1
  31. package/build/esm/flagsmith-engine/index.js +1 -1
  32. package/build/esm/flagsmith-engine/segments/models.js +7 -7
  33. package/build/esm/flagsmith-engine/utils/hashing/index.js +2 -2
  34. package/build/esm/flagsmith-engine/utils/index.js +1 -1
  35. package/build/esm/index.d.ts +4 -4
  36. package/build/esm/index.js +3 -3
  37. package/build/esm/sdk/analytics.d.ts +1 -1
  38. package/build/esm/sdk/analytics.js +3 -1
  39. package/build/esm/sdk/index.d.ts +5 -5
  40. package/build/esm/sdk/index.js +48 -11
  41. package/build/esm/sdk/models.d.ts +25 -0
  42. package/build/esm/sdk/models.js +25 -0
  43. package/build/esm/sdk/types.d.ts +14 -4
  44. package/build/esm/sdk/utils.d.ts +5 -4
  45. package/build/esm/sdk/utils.js +14 -2
  46. package/flagsmith-engine/environments/util.ts +2 -2
  47. package/flagsmith-engine/features/models.ts +1 -1
  48. package/flagsmith-engine/features/util.ts +14 -14
  49. package/flagsmith-engine/identities/models.ts +1 -1
  50. package/flagsmith-engine/index.ts +1 -1
  51. package/flagsmith-engine/segments/evaluators.ts +2 -3
  52. package/flagsmith-engine/segments/models.ts +25 -15
  53. package/flagsmith-engine/utils/hashing/index.ts +3 -3
  54. package/flagsmith-engine/utils/index.ts +4 -2
  55. package/index.ts +19 -22
  56. package/package.json +1 -1
  57. package/release-please-config.json +62 -0
  58. package/sdk/analytics.ts +10 -6
  59. package/sdk/index.ts +91 -28
  60. package/sdk/models.ts +25 -0
  61. package/sdk/offline_handlers.ts +1 -1
  62. package/sdk/types.ts +17 -8
  63. package/sdk/utils.ts +21 -8
  64. package/tests/engine/e2e/engine.test.ts +2 -4
  65. package/tests/engine/unit/engine.test.ts +1 -6
  66. package/tests/engine/unit/features/models.test.ts +2 -2
  67. package/tests/engine/unit/identities/identities_builders.test.ts +1 -1
  68. package/tests/engine/unit/segments/segment_evaluators.test.ts +52 -23
  69. package/tests/engine/unit/segments/segments_model.test.ts +35 -37
  70. package/tests/engine/unit/utils/utils.test.ts +28 -30
  71. package/tests/sdk/analytics.test.ts +30 -26
  72. package/tests/sdk/flagsmith-cache.test.ts +84 -76
  73. package/tests/sdk/flagsmith-environment-flags.test.ts +121 -93
  74. package/tests/sdk/flagsmith-identity-flags.test.ts +155 -149
  75. package/tests/sdk/flagsmith.test.ts +202 -43
  76. package/tests/sdk/offline-handlers.test.ts +32 -32
  77. package/tests/sdk/polling.test.ts +0 -1
  78. package/tests/sdk/utils.ts +26 -18
  79. package/vitest.config.ts +10 -15
@@ -9,7 +9,7 @@ import {
9
9
  badFetch
10
10
  } from './utils.js';
11
11
  import { DefaultFlag, Flags } from '../../sdk/models.js';
12
- import { delay } from '../../sdk/utils.js';
12
+ import { delay, getUserAgent } from '../../sdk/utils.js';
13
13
  import { EnvironmentModel } from '../../flagsmith-engine/environments/models.js';
14
14
  import { BaseOfflineHandler } from '../../sdk/offline_handlers.js';
15
15
  import { Agent } from 'undici';
@@ -29,26 +29,180 @@ test('test_flagsmith_local_evaluation_key_required', () => {
29
29
  environmentKey: 'bad.key',
30
30
  enableLocalEvaluation: true
31
31
  });
32
- }).toThrow('Using local evaluation requires a server-side environment key')
32
+ }).toThrow('Using local evaluation requires a server-side environment key');
33
33
  });
34
34
 
35
35
  test('test_update_environment_sets_environment', async () => {
36
36
  const flg = flagsmith({
37
- environmentKey: 'ser.key',
37
+ environmentKey: 'ser.key'
38
38
  });
39
39
  const model = environmentModel(JSON.parse(environmentJSON));
40
40
  expect(await flg.getEnvironment()).toStrictEqual(model);
41
41
  });
42
42
 
43
+ test('test_update_environment_handles_paginated_document', async () => {
44
+ type EnvDocumentMockResponse = {
45
+ responseHeader: string | null;
46
+ page: any;
47
+ };
48
+
49
+ const createMockFetch = (pages: EnvDocumentMockResponse[]) => {
50
+ let callCount = 0;
51
+ return vi.fn((url: string, options?: RequestInit) => {
52
+ if (url.includes('/environment-document')) {
53
+ const document = envDocumentMockResponse[callCount];
54
+ if (document) {
55
+ callCount++;
56
+
57
+ const responseHeaders: Record<string, string> = {};
58
+
59
+ if (document.responseHeader) {
60
+ responseHeaders['Link'] = `<${document.responseHeader}>; rel="next"`;
61
+ }
62
+
63
+ return Promise.resolve(
64
+ new Response(JSON.stringify(document.page), {
65
+ status: 200,
66
+ headers: responseHeaders
67
+ })
68
+ );
69
+ }
70
+ }
71
+ return Promise.resolve(new Response('unknown url ' + url, { status: 404 }));
72
+ });
73
+ };
74
+
75
+ const envDocumentMockResponse: EnvDocumentMockResponse[] = [
76
+ {
77
+ responseHeader: '/api/v1/environment-document?page=2',
78
+ page: {
79
+ id: 1,
80
+ api_key: 'test-key',
81
+ project: {
82
+ id: 1,
83
+ name: 'test',
84
+ organisation: {
85
+ id: 1,
86
+ name: 'Test Org',
87
+ feature_analytics: false,
88
+ persist_trait_data: true,
89
+ stop_serving_flags: false
90
+ },
91
+ hide_disabled_flags: false,
92
+ segments: []
93
+ },
94
+ feature_states: [
95
+ {
96
+ feature_state_value: 'first_page_feature_state',
97
+ multivariate_feature_state_values: [],
98
+ django_id: 81027,
99
+ feature: {
100
+ id: 15058,
101
+ type: 'STANDARD',
102
+ name: 'string_feature'
103
+ },
104
+ enabled: false
105
+ },
106
+ {
107
+ feature_state_value: 'second_page_feature_state',
108
+ multivariate_feature_state_values: [],
109
+ django_id: 81027,
110
+ feature: {
111
+ id: 15058,
112
+ type: 'STANDARD',
113
+ name: 'string_feature'
114
+ },
115
+ enabled: false
116
+ },
117
+ {
118
+ feature_state_value: 'third_page_feature_state',
119
+ multivariate_feature_state_values: [],
120
+ django_id: 81027,
121
+ feature: {
122
+ id: 15058,
123
+ type: 'STANDARD',
124
+ name: 'string_feature'
125
+ },
126
+ enabled: false
127
+ }
128
+ ],
129
+ identity_overrides: [{ id: 1, identifier: 'user1' }]
130
+ }
131
+ },
132
+ {
133
+ responseHeader: '/api/v1/environment-document?page=3',
134
+ page: {
135
+ api_key: 'test-key',
136
+ project: {
137
+ id: 1,
138
+ name: 'test',
139
+ organisation: {
140
+ id: 1,
141
+ name: 'Test Org',
142
+ feature_analytics: false,
143
+ persist_trait_data: true,
144
+ stop_serving_flags: false
145
+ },
146
+ hide_disabled_flags: false,
147
+ segments: []
148
+ },
149
+ feature_states: [],
150
+ identity_overrides: [{ id: 2, identifier: 'user2' }]
151
+ }
152
+ },
153
+ {
154
+ responseHeader: null,
155
+ page: {
156
+ api_key: 'test-key',
157
+ project: {
158
+ id: 1,
159
+ name: 'test',
160
+ organisation: {
161
+ id: 1,
162
+ name: 'Test Org',
163
+ feature_analytics: false,
164
+ persist_trait_data: true,
165
+ stop_serving_flags: false
166
+ },
167
+ hide_disabled_flags: false,
168
+ segments: []
169
+ },
170
+ feature_states: [],
171
+ identity_overrides: [{ id: 2, identifier: 'user3' }]
172
+ }
173
+ }
174
+ ];
175
+
176
+ const flg = new Flagsmith({
177
+ environmentKey: 'ser.key',
178
+ enableLocalEvaluation: true,
179
+ fetch: createMockFetch(envDocumentMockResponse)
180
+ });
181
+
182
+ const environment = await flg.getEnvironment();
183
+
184
+ expect(environment.identityOverrides).toHaveLength(3);
185
+ expect(environment.identityOverrides[0].identifier).toBe('user1');
186
+ expect(environment.identityOverrides[1].identifier).toBe('user2');
187
+ expect(environment.identityOverrides[2].identifier).toBe('user3');
188
+ expect(environment.featureStates).toHaveLength(3);
189
+ expect(environment.featureStates[0].getValue()).toBe('first_page_feature_state');
190
+ expect(environment.featureStates[1].getValue()).toBe('second_page_feature_state');
191
+ expect(environment.featureStates[2].getValue()).toBe('third_page_feature_state');
192
+ expect(environment.project.name).toBe('test');
193
+ expect(environment.project.organisation.name).toBe('Test Org');
194
+ expect(environment.project.organisation.id).toBe(1);
195
+ });
196
+
43
197
  test('test_set_agent_options', async () => {
44
- const agent = new Agent({})
198
+ const agent = new Agent({});
45
199
 
46
200
  fetch.mockImplementationOnce((url, options) => {
47
201
  //@ts-ignore I give up
48
202
  if (options.dispatcher !== agent) {
49
- throw new Error("Agent has not been set on retry fetch")
203
+ throw new Error('Agent has not been set on retry fetch');
50
204
  }
51
- return Promise.resolve(new Response(environmentJSON))
205
+ return Promise.resolve(new Response(environmentJSON));
52
206
  });
53
207
 
54
208
  const flg = flagsmith({
@@ -69,7 +223,6 @@ test('test_get_identity_segments', async () => {
69
223
  expect(segments2.length).toEqual(0);
70
224
  });
71
225
 
72
-
73
226
  test('test_get_identity_segments_empty_without_local_eval', async () => {
74
227
  const flg = new Flagsmith({
75
228
  environmentKey: 'ser.key',
@@ -82,7 +235,7 @@ test('test_get_identity_segments_empty_without_local_eval', async () => {
82
235
  test('test_update_environment_uses_req_when_inited', async () => {
83
236
  const flg = flagsmith({
84
237
  environmentKey: 'ser.key',
85
- enableLocalEvaluation: true,
238
+ enableLocalEvaluation: true
86
239
  });
87
240
 
88
241
  delay(400);
@@ -100,7 +253,7 @@ test('test_isFeatureEnabled_environment', async () => {
100
253
  const flg = new Flagsmith({
101
254
  environmentKey: 'key',
102
255
  defaultFlagHandler: defaultFlagHandler,
103
- enableAnalytics: true,
256
+ enableAnalytics: true
104
257
  });
105
258
 
106
259
  const flags = await flg.getEnvironmentFlags();
@@ -110,9 +263,9 @@ test('test_isFeatureEnabled_environment', async () => {
110
263
  });
111
264
 
112
265
  test('test_fetch_recovers_after_single_API_error', async () => {
113
- fetch.mockRejectedValueOnce('Error during fetching the API response')
266
+ fetch.mockRejectedValueOnce('Error during fetching the API response');
114
267
  const flg = flagsmith({
115
- environmentKey: 'key',
268
+ environmentKey: 'key'
116
269
  });
117
270
 
118
271
  const flags = await flg.getEnvironmentFlags();
@@ -132,7 +285,7 @@ test.each([
132
285
  enableLocalEvaluation,
133
286
  environmentKey,
134
287
  defaultFlagHandler: () => new DefaultFlag('some-default-value', true),
135
- fetch: badFetch,
288
+ fetch: badFetch
136
289
  });
137
290
  const flags = await flg.getEnvironmentFlags();
138
291
  const flag = flags.getFlag('some_feature');
@@ -144,9 +297,9 @@ test.each([
144
297
 
145
298
  test('default flag handler used when timeout occurs', async () => {
146
299
  fetch.mockImplementation(async (...args) => {
147
- const forever = new Promise(() => {})
148
- await forever
149
- throw new Error('waited forever')
300
+ const forever = new Promise(() => {});
301
+ await forever;
302
+ throw new Error('waited forever');
150
303
  });
151
304
 
152
305
  const defaultFlag = new DefaultFlag('some-default-value', true);
@@ -156,7 +309,7 @@ test('default flag handler used when timeout occurs', async () => {
156
309
  const flg = flagsmith({
157
310
  environmentKey: 'key',
158
311
  defaultFlagHandler: defaultFlagHandler,
159
- requestTimeoutSeconds: 0.0001,
312
+ requestTimeoutSeconds: 0.0001
160
313
  });
161
314
 
162
315
  const flags = await flg.getEnvironmentFlags();
@@ -164,35 +317,32 @@ test('default flag handler used when timeout occurs', async () => {
164
317
  expect(flag.isDefault).toBe(true);
165
318
  expect(flag.enabled).toBe(defaultFlag.enabled);
166
319
  expect(flag.value).toBe(defaultFlag.value);
167
- })
320
+ });
168
321
 
169
322
  test('request timeout uses default if not provided', async () => {
170
-
171
323
  const flg = new Flagsmith({
172
- environmentKey: 'key',
324
+ environmentKey: 'key'
173
325
  });
174
326
 
175
327
  expect(flg.requestTimeoutMs).toBe(10000);
176
- })
328
+ });
177
329
 
178
330
  test('test_throws_when_no_identityFlags_returned_due_to_error', async () => {
179
331
  const flg = flagsmith({
180
332
  environmentKey: 'key',
181
- fetch: badFetch,
333
+ fetch: badFetch
182
334
  });
183
335
 
184
- await expect(async () => await flg.getIdentityFlags('identifier'))
185
- .rejects
186
- .toThrow();
336
+ await expect(async () => await flg.getIdentityFlags('identifier')).rejects.toThrow();
187
337
  });
188
338
 
189
339
  test('test onEnvironmentChange is called when provided', async () => {
190
- const callback = vi.fn()
340
+ const callback = vi.fn();
191
341
 
192
342
  const flg = new Flagsmith({
193
343
  environmentKey: 'ser.key',
194
344
  enableLocalEvaluation: true,
195
- onEnvironmentChange: callback,
345
+ onEnvironmentChange: callback
196
346
  });
197
347
 
198
348
  fetch.mockRejectedValueOnce(new Error('API error'));
@@ -209,7 +359,7 @@ test('test onEnvironmentChange is called after error', async () => {
209
359
  environmentKey: 'ser.key',
210
360
  enableLocalEvaluation: true,
211
361
  onEnvironmentChange: callback,
212
- fetch: badFetch,
362
+ fetch: badFetch
213
363
  });
214
364
  await flg.updateEnvironment();
215
365
  expect(callback).toHaveBeenCalled();
@@ -217,15 +367,17 @@ test('test onEnvironmentChange is called after error', async () => {
217
367
 
218
368
  test('getIdentityFlags throws error if identifier is empty string', async () => {
219
369
  const flg = flagsmith({
220
- environmentKey: 'key',
370
+ environmentKey: 'key'
221
371
  });
222
372
 
223
- await expect(flg.getIdentityFlags('')).rejects.toThrow('`identifier` argument is missing or invalid.');
224
- })
373
+ await expect(flg.getIdentityFlags('')).rejects.toThrow(
374
+ '`identifier` argument is missing or invalid.'
375
+ );
376
+ });
225
377
 
226
378
  test('getIdentitySegments throws error if identifier is empty string', async () => {
227
379
  const flg = flagsmith({
228
- environmentKey: 'key',
380
+ environmentKey: 'key'
229
381
  });
230
382
 
231
383
  await expect(flg.getIdentitySegments('')).rejects.toThrow(
@@ -254,15 +406,13 @@ test('offline_mode', async () => {
254
406
  expect(flag.enabled).toBe(true);
255
407
  expect(flag.value).toBe('offline-value');
256
408
 
257
-
258
- const identityFlags: Flags = await flg.getIdentityFlags("identity");
409
+ const identityFlags: Flags = await flg.getIdentityFlags('identity');
259
410
  flag = identityFlags.getFlag('some_feature');
260
411
  expect(flag.isDefault).toBe(false);
261
412
  expect(flag.enabled).toBe(true);
262
413
  expect(flag.value).toBe('offline-value');
263
414
  });
264
415
 
265
-
266
416
  test('test_flagsmith_uses_offline_handler_if_set_and_no_api_response', async () => {
267
417
  // Given
268
418
  const environment: EnvironmentModel = environmentModel(JSON.parse(offlineEnvironmentJSON));
@@ -281,14 +431,13 @@ test('test_flagsmith_uses_offline_handler_if_set_and_no_api_response', async ()
281
431
  vi.spyOn(flg, 'getEnvironmentFlags');
282
432
  vi.spyOn(flg, 'getIdentityFlags');
283
433
 
284
-
285
434
  flg.environmentFlagsUrl = 'http://some.flagsmith.com/api/v1/environment-flags';
286
435
  flg.identitiesUrl = 'http://some.flagsmith.com/api/v1/identities';
287
436
 
288
437
  // Mock a 500 Internal Server Error response
289
438
  const errorResponse = new Response(null, {
290
439
  status: 500,
291
- statusText: 'Internal Server Error',
440
+ statusText: 'Internal Server Error'
292
441
  });
293
442
 
294
443
  fetch.mockResolvedValue(errorResponse);
@@ -318,25 +467,28 @@ test('cannot use offline mode without offline handler', () => {
318
467
 
319
468
  test('cannot use both default handler and offline handler', () => {
320
469
  // When and Then
321
- expect(() => flagsmith({
322
- offlineHandler: new BaseOfflineHandler(),
323
- defaultFlagHandler: () => new DefaultFlag('foo', true)
324
- })).toThrowError('ValueError: Cannot use both defaultFlagHandler and offlineHandler.');
470
+ expect(() =>
471
+ flagsmith({
472
+ offlineHandler: new BaseOfflineHandler(),
473
+ defaultFlagHandler: () => new DefaultFlag('foo', true)
474
+ })
475
+ ).toThrowError('ValueError: Cannot use both defaultFlagHandler and offlineHandler.');
325
476
  });
326
477
 
327
478
  test('cannot create Flagsmith client in remote evaluation without API key', () => {
328
479
  // When and Then
329
- expect(() => new Flagsmith({ environmentKey: '' })).toThrowError('ValueError: environmentKey is required.');
480
+ expect(() => new Flagsmith({ environmentKey: '' })).toThrowError(
481
+ 'ValueError: environmentKey is required.'
482
+ );
330
483
  });
331
484
 
332
-
333
485
  test('test_localEvaluation_true__identity_overrides_evaluated', async () => {
334
486
  const flg = flagsmith({
335
487
  environmentKey: 'ser.key',
336
488
  enableLocalEvaluation: true
337
489
  });
338
490
 
339
- await flg.updateEnvironment()
491
+ await flg.updateEnvironment();
340
492
  const flags = await flg.getIdentityFlags('overridden-id');
341
493
  expect(flags.getFeatureValue('some_feature')).toEqual('some-overridden-value');
342
494
  });
@@ -360,3 +512,10 @@ test('getIdentityFlags succeeds if initial fetch failed then succeeded', async (
360
512
  const flags2 = await flg.getIdentityFlags('test-user');
361
513
  expect(flags2.isFeatureEnabled('some_feature')).toBe(true);
362
514
  });
515
+
516
+ test('get_user_agent_extracts_version_from_package_json', async () => {
517
+ const userAgent = getUserAgent();
518
+ const packageJson = require('../../package.json');
519
+
520
+ expect(userAgent).toBe(`flagsmith-nodejs-sdk/${packageJson.version}`);
521
+ });
@@ -1,32 +1,32 @@
1
- import * as fs from 'fs';
2
- import { LocalFileHandler } from '../../sdk/offline_handlers.js';
3
- import { EnvironmentModel } from '../../flagsmith-engine/index.js';
4
-
5
- import * as offlineEnvironment from "./data/offline-environment.json";
6
-
7
- vi.mock('fs')
8
-
9
- const offlineEnvironmentString = JSON.stringify(offlineEnvironment)
10
-
11
- test('local file handler', () => {
12
- const environmentDocumentFilePath = '/some/path/environment.json';
13
-
14
- // Mock the fs.readFileSync function to return environmentJson
15
-
16
- const readFileSyncMock = vi.spyOn(fs, 'readFileSync');
17
- readFileSyncMock.mockImplementation(() => offlineEnvironmentString);
18
-
19
- // Given
20
- const localFileHandler = new LocalFileHandler(environmentDocumentFilePath);
21
-
22
- // When
23
- const environmentModel = localFileHandler.getEnvironment();
24
-
25
- // Then
26
- expect(environmentModel).toBeInstanceOf(EnvironmentModel);
27
- expect(environmentModel.apiKey).toBe('B62qaMZNwfiqT76p38ggrQ');
28
- expect(readFileSyncMock).toHaveBeenCalledWith(environmentDocumentFilePath, 'utf8');
29
-
30
- // Restore the original implementation of fs.readFileSync
31
- readFileSyncMock.mockRestore();
32
- });
1
+ import * as fs from 'fs';
2
+ import { LocalFileHandler } from '../../sdk/offline_handlers.js';
3
+ import { EnvironmentModel } from '../../flagsmith-engine/index.js';
4
+
5
+ import * as offlineEnvironment from './data/offline-environment.json';
6
+
7
+ vi.mock('fs');
8
+
9
+ const offlineEnvironmentString = JSON.stringify(offlineEnvironment);
10
+
11
+ test('local file handler', () => {
12
+ const environmentDocumentFilePath = '/some/path/environment.json';
13
+
14
+ // Mock the fs.readFileSync function to return environmentJson
15
+
16
+ const readFileSyncMock = vi.spyOn(fs, 'readFileSync');
17
+ readFileSyncMock.mockImplementation(() => offlineEnvironmentString);
18
+
19
+ // Given
20
+ const localFileHandler = new LocalFileHandler(environmentDocumentFilePath);
21
+
22
+ // When
23
+ const environmentModel = localFileHandler.getEnvironment();
24
+
25
+ // Then
26
+ expect(environmentModel).toBeInstanceOf(EnvironmentModel);
27
+ expect(environmentModel.apiKey).toBe('B62qaMZNwfiqT76p38ggrQ');
28
+ expect(readFileSyncMock).toHaveBeenCalledWith(environmentDocumentFilePath, 'utf8');
29
+
30
+ // Restore the original implementation of fs.readFileSync
31
+ readFileSyncMock.mockRestore();
32
+ });
@@ -39,7 +39,6 @@ test('test_polling_manager_handles_double_start', async () => {
39
39
  expect(flagsmith.updateEnvironment).toHaveBeenCalled();
40
40
  });
41
41
 
42
-
43
42
  test('test_polling_manager_calls_update_environment_on_each_refresh', async () => {
44
43
  const flagsmith = new Flagsmith({
45
44
  environmentKey: 'key'
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { buildEnvironmentModel } from '../../flagsmith-engine/environments/util.js';
3
3
  import { AnalyticsProcessor } from '../../sdk/analytics.js';
4
- import Flagsmith, {FlagsmithConfig} from '../../sdk/index.js';
4
+ import Flagsmith, { FlagsmithConfig } from '../../sdk/index.js';
5
5
  import { Fetch, FlagsmithCache } from '../../sdk/types.js';
6
6
  import { Flags } from '../../sdk/models.js';
7
7
 
@@ -21,31 +21,36 @@ export class TestCache implements FlagsmithCache {
21
21
 
22
22
  export const fetch = vi.fn((url: string, options?: RequestInit) => {
23
23
  const headers = options?.headers as Record<string, string>;
24
- if (!headers) throw new Error('missing request headers')
24
+ if (!headers) throw new Error('missing request headers');
25
25
  const env = headers['X-Environment-Key'];
26
- if (!env) return Promise.resolve(new Response('missing x-environment-key header', { status: 404 }));
26
+ if (!env)
27
+ return Promise.resolve(new Response('missing x-environment-key header', { status: 404 }));
27
28
  if (url.includes('/environment-document')) {
28
29
  if (env.startsWith('ser.')) {
29
- return Promise.resolve(new Response(environmentJSON, { status: 200 }))
30
+ return Promise.resolve(new Response(environmentJSON, { status: 200 }));
30
31
  }
31
- return Promise.resolve(new Response('environment-document called without a server-side key', { status: 401 }))
32
+ return Promise.resolve(
33
+ new Response('environment-document called without a server-side key', { status: 401 })
34
+ );
32
35
  }
33
- if (url.includes("/flags")) {
34
- return Promise.resolve(new Response(flagsJSON, { status: 200 }))
36
+ if (url.includes('/flags')) {
37
+ return Promise.resolve(new Response(flagsJSON, { status: 200 }));
35
38
  }
36
- if (url.includes("/identities")) {
37
- return Promise.resolve(new Response(identitiesJSON, { status: 200 }))
39
+ if (url.includes('/identities')) {
40
+ return Promise.resolve(new Response(identitiesJSON, { status: 200 }));
38
41
  }
39
- return Promise.resolve(new Response('unknown url ' + url, { status: 404 }))
42
+ return Promise.resolve(new Response('unknown url ' + url, { status: 404 }));
40
43
  });
41
44
 
42
- export const badFetch: Fetch = () => { throw new Error('fetch failed')}
45
+ export const badFetch: Fetch = () => {
46
+ throw new Error('fetch failed');
47
+ };
43
48
 
44
49
  export function analyticsProcessor() {
45
50
  return new AnalyticsProcessor({
46
51
  environmentKey: 'test-key',
47
52
  analyticsUrl: 'http://testUrl/analytics/flags/',
48
- fetch: (url, options) => fetch(url.toString(), options),
53
+ fetch: (url, options) => fetch(url.toString(), options)
49
54
  });
50
55
  }
51
56
 
@@ -59,22 +64,25 @@ export function flagsmith(params: FlagsmithConfig = {}) {
59
64
  environmentRefreshIntervalSeconds: 0,
60
65
  requestRetryDelayMilliseconds: 0,
61
66
  fetch: (url, options) => fetch(url.toString(), options),
62
- ...params,
67
+ ...params
63
68
  });
64
69
  }
65
70
 
66
71
  export const environmentJSON = readFileSync(DATA_DIR + 'environment.json', 'utf-8');
67
72
 
68
- export const offlineEnvironmentJSON = readFileSync(DATA_DIR + 'offline-environment.json', 'utf-8')
73
+ export const offlineEnvironmentJSON = readFileSync(DATA_DIR + 'offline-environment.json', 'utf-8');
69
74
 
70
75
  export function environmentModel(environmentJSON: any) {
71
76
  return buildEnvironmentModel(environmentJSON);
72
77
  }
73
78
 
74
- export const flagsJSON = readFileSync(DATA_DIR + 'flags.json', 'utf-8')
79
+ export const flagsJSON = readFileSync(DATA_DIR + 'flags.json', 'utf-8');
75
80
 
76
- export const identitiesJSON = readFileSync(DATA_DIR + 'identities.json', 'utf-8')
81
+ export const identitiesJSON = readFileSync(DATA_DIR + 'identities.json', 'utf-8');
77
82
 
78
- export const transientIdentityJSON = readFileSync(DATA_DIR + 'transient-identity.json', 'utf-8')
83
+ export const transientIdentityJSON = readFileSync(DATA_DIR + 'transient-identity.json', 'utf-8');
79
84
 
80
- export const identityWithTransientTraitsJSON = readFileSync(DATA_DIR + 'identity-with-transient-traits.json', 'utf-8')
85
+ export const identityWithTransientTraitsJSON = readFileSync(
86
+ DATA_DIR + 'identity-with-transient-traits.json',
87
+ 'utf-8'
88
+ );
package/vitest.config.ts CHANGED
@@ -1,18 +1,13 @@
1
- import { defineConfig } from 'vitest/config'
1
+ import { defineConfig } from 'vitest/config';
2
2
 
3
3
  export default defineConfig({
4
- test: {
5
- globals: true,
6
- restoreMocks: true,
7
- coverage: {
8
- reporter: ['text'],
9
- exclude: [
10
- 'build/**'
11
- ],
12
- include: [
13
- 'sdk/**',
14
- 'flagsmith-engine/**',
15
- ]
4
+ test: {
5
+ globals: true,
6
+ restoreMocks: true,
7
+ coverage: {
8
+ reporter: ['text'],
9
+ exclude: ['build/**'],
10
+ include: ['sdk/**', 'flagsmith-engine/**']
11
+ }
16
12
  }
17
- },
18
- })
13
+ });