flagsmith-nodejs 6.0.0 → 6.1.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 (70) hide show
  1. package/.github/workflows/publish.yml +17 -17
  2. package/.github/workflows/pull_request.yaml +33 -33
  3. package/.husky/pre-commit +0 -0
  4. package/.prettierignore +2 -1
  5. package/README.md +2 -1
  6. package/build/cjs/flagsmith-engine/features/util.js +3 -3
  7. package/build/cjs/flagsmith-engine/index.d.ts +1 -1
  8. package/build/cjs/flagsmith-engine/index.js +2 -1
  9. package/build/cjs/flagsmith-engine/segments/models.js +7 -7
  10. package/build/cjs/flagsmith-engine/utils/hashing/index.js +1 -1
  11. package/build/cjs/index.d.ts +4 -4
  12. package/build/cjs/index.js +3 -1
  13. package/build/cjs/sdk/analytics.d.ts +1 -1
  14. package/build/cjs/sdk/index.d.ts +5 -5
  15. package/build/cjs/sdk/index.js +7 -5
  16. package/build/cjs/sdk/models.d.ts +32 -5
  17. package/build/cjs/sdk/models.js +25 -0
  18. package/build/cjs/sdk/types.d.ts +14 -4
  19. package/build/cjs/sdk/utils.d.ts +4 -4
  20. package/build/cjs/sdk/utils.js +2 -2
  21. package/build/esm/flagsmith-engine/features/models.js +1 -1
  22. package/build/esm/flagsmith-engine/features/util.js +3 -3
  23. package/build/esm/flagsmith-engine/index.d.ts +1 -1
  24. package/build/esm/flagsmith-engine/index.js +1 -1
  25. package/build/esm/flagsmith-engine/segments/models.js +7 -7
  26. package/build/esm/flagsmith-engine/utils/hashing/index.js +2 -2
  27. package/build/esm/flagsmith-engine/utils/index.js +1 -1
  28. package/build/esm/index.d.ts +4 -4
  29. package/build/esm/index.js +3 -3
  30. package/build/esm/sdk/analytics.d.ts +1 -1
  31. package/build/esm/sdk/index.d.ts +5 -5
  32. package/build/esm/sdk/index.js +6 -5
  33. package/build/esm/sdk/models.d.ts +32 -5
  34. package/build/esm/sdk/models.js +25 -0
  35. package/build/esm/sdk/types.d.ts +14 -4
  36. package/build/esm/sdk/utils.d.ts +4 -4
  37. package/build/esm/sdk/utils.js +2 -2
  38. package/flagsmith-engine/environments/util.ts +2 -2
  39. package/flagsmith-engine/features/models.ts +1 -1
  40. package/flagsmith-engine/features/util.ts +14 -14
  41. package/flagsmith-engine/identities/models.ts +1 -1
  42. package/flagsmith-engine/index.ts +1 -1
  43. package/flagsmith-engine/segments/evaluators.ts +2 -3
  44. package/flagsmith-engine/segments/models.ts +25 -15
  45. package/flagsmith-engine/utils/hashing/index.ts +3 -3
  46. package/flagsmith-engine/utils/index.ts +4 -2
  47. package/index.ts +19 -22
  48. package/package.json +2 -2
  49. package/sdk/analytics.ts +7 -5
  50. package/sdk/index.ts +38 -21
  51. package/sdk/models.ts +34 -12
  52. package/sdk/offline_handlers.ts +1 -1
  53. package/sdk/types.ts +17 -8
  54. package/sdk/utils.ts +8 -8
  55. package/tests/engine/e2e/engine.test.ts +2 -4
  56. package/tests/engine/unit/engine.test.ts +1 -5
  57. package/tests/engine/unit/features/models.test.ts +2 -2
  58. package/tests/engine/unit/identities/identities_builders.test.ts +1 -1
  59. package/tests/engine/unit/segments/segment_evaluators.test.ts +52 -23
  60. package/tests/engine/unit/segments/segments_model.test.ts +35 -37
  61. package/tests/engine/unit/utils/utils.test.ts +28 -30
  62. package/tests/sdk/analytics.test.ts +25 -26
  63. package/tests/sdk/flagsmith-cache.test.ts +84 -76
  64. package/tests/sdk/flagsmith-environment-flags.test.ts +93 -93
  65. package/tests/sdk/flagsmith-identity-flags.test.ts +146 -149
  66. package/tests/sdk/flagsmith.test.ts +40 -42
  67. package/tests/sdk/offline-handlers.test.ts +32 -32
  68. package/tests/sdk/polling.test.ts +0 -1
  69. package/tests/sdk/utils.ts +26 -18
  70. package/vitest.config.ts +10 -15
package/sdk/analytics.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { pino, Logger } from 'pino';
2
- import { Fetch } from "./types.js";
3
- import { FlagsmithConfig } from "./types.js";
2
+ import { Fetch } from './types.js';
3
+ import { FlagsmithConfig } from './types.js';
4
4
 
5
5
  export const ANALYTICS_ENDPOINT = './analytics/flags/';
6
6
 
7
7
  /** Duration in seconds to wait before trying to flush collected data after {@link trackFeature} is called. **/
8
8
  const ANALYTICS_TIMER = 10;
9
9
 
10
- const DEFAULT_REQUEST_TIMEOUT_MS = 3000
10
+ const DEFAULT_REQUEST_TIMEOUT_MS = 3000;
11
11
 
12
12
  export interface AnalyticsProcessorOptions {
13
13
  /** URL of the Flagsmith analytics events API endpoint
@@ -20,7 +20,7 @@ export interface AnalyticsProcessorOptions {
20
20
  requestTimeoutMs?: number;
21
21
  logger?: Logger;
22
22
  /** Custom {@link fetch} implementation to use for API requests. **/
23
- fetch?: Fetch
23
+ fetch?: Fetch;
24
24
 
25
25
  /** @deprecated Use {@link analyticsUrl} instead. **/
26
26
  baseApiUrl?: string;
@@ -76,7 +76,9 @@ export class AnalyticsProcessor {
76
76
  } catch (error) {
77
77
  // We don't want failing to write analytics to cause any exceptions in the main
78
78
  // thread so we just swallow them here.
79
- this.logger.warn('Failed to post analytics to Flagsmith API. Not clearing data, will retry.')
79
+ this.logger.warn(
80
+ 'Failed to post analytics to Flagsmith API. Not clearing data, will retry.'
81
+ );
80
82
  return;
81
83
  } finally {
82
84
  this.currentFlush = undefined;
package/sdk/index.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import { Dispatcher } from 'undici-types';
2
- import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine/index.js';
2
+ import {
3
+ getEnvironmentFeatureStates,
4
+ getIdentityFeatureStates
5
+ } from '../flagsmith-engine/index.js';
3
6
  import { EnvironmentModel } from '../flagsmith-engine/index.js';
4
7
  import { buildEnvironmentModel } from '../flagsmith-engine/environments/util.js';
5
8
  import { IdentityModel } from '../flagsmith-engine/index.js';
6
9
  import { TraitModel } from '../flagsmith-engine/index.js';
7
10
 
8
- import {ANALYTICS_ENDPOINT, AnalyticsProcessor} from './analytics.js';
11
+ import { ANALYTICS_ENDPOINT, AnalyticsProcessor } from './analytics.js';
9
12
  import { BaseOfflineHandler } from './offline_handlers.js';
10
13
  import { FlagsmithAPIError } from './errors.js';
11
14
 
@@ -14,13 +17,19 @@ import { EnvironmentDataPollingManager } from './polling_manager.js';
14
17
  import { Deferred, generateIdentitiesData, retryFetch } from './utils.js';
15
18
  import { SegmentModel } from '../flagsmith-engine/index.js';
16
19
  import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators.js';
17
- import { Fetch, FlagsmithCache, FlagsmithConfig, FlagsmithTraitValue, ITraitConfig } from './types.js';
20
+ import {
21
+ Fetch,
22
+ FlagsmithCache,
23
+ FlagsmithConfig,
24
+ FlagsmithTraitValue,
25
+ TraitConfig
26
+ } from './types.js';
18
27
  import { pino, Logger } from 'pino';
19
28
 
20
29
  export { AnalyticsProcessor, AnalyticsProcessorOptions } from './analytics.js';
21
30
  export { FlagsmithAPIError, FlagsmithClientError } from './errors.js';
22
31
 
23
- export { DefaultFlag, Flags } from './models.js';
32
+ export { BaseFlag, DefaultFlag, Flags } from './models.js';
24
33
  export { EnvironmentDataPollingManager } from './polling_manager.js';
25
34
  export { FlagsmithCache, FlagsmithConfig } from './types.js';
26
35
 
@@ -50,7 +59,7 @@ const DEFAULT_REQUEST_TIMEOUT_SECONDS = 10;
50
59
  * const bannerVariation: string = identityFlags.getFeatureValue('banner_flag')
51
60
  *
52
61
  * @see FlagsmithConfig
53
- */
62
+ */
54
63
  export class Flagsmith {
55
64
  environmentKey?: string = undefined;
56
65
  apiUrl?: string = undefined;
@@ -128,20 +137,23 @@ export class Flagsmith {
128
137
 
129
138
  const apiUrl = data.apiUrl || DEFAULT_API_URL;
130
139
  this.apiUrl = apiUrl.endsWith('/') ? apiUrl : `${apiUrl}/`;
131
- this.analyticsUrl = this.analyticsUrl || new URL(ANALYTICS_ENDPOINT, new Request(this.apiUrl).url).href
140
+ this.analyticsUrl =
141
+ this.analyticsUrl || new URL(ANALYTICS_ENDPOINT, new Request(this.apiUrl).url).href;
132
142
  this.environmentFlagsUrl = `${this.apiUrl}flags/`;
133
143
  this.identitiesUrl = `${this.apiUrl}identities/`;
134
144
  this.environmentUrl = `${this.apiUrl}environment-document/`;
135
145
 
136
146
  if (this.enableLocalEvaluation) {
137
147
  if (!this.environmentKey.startsWith('ser.')) {
138
- throw new Error('Using local evaluation requires a server-side environment key');
148
+ throw new Error(
149
+ 'Using local evaluation requires a server-side environment key'
150
+ );
139
151
  }
140
- if (this.environmentRefreshIntervalSeconds > 0){
152
+ if (this.environmentRefreshIntervalSeconds > 0) {
141
153
  this.environmentDataPollingManager = new EnvironmentDataPollingManager(
142
154
  this,
143
155
  this.environmentRefreshIntervalSeconds,
144
- this.logger,
156
+ this.logger
145
157
  );
146
158
  this.environmentDataPollingManager.start();
147
159
  }
@@ -152,8 +164,8 @@ export class Flagsmith {
152
164
  environmentKey: this.environmentKey,
153
165
  analyticsUrl: this.analyticsUrl,
154
166
  requestTimeoutMs: this.requestTimeoutMs,
155
- logger: this.logger,
156
- })
167
+ logger: this.logger
168
+ });
157
169
  }
158
170
  }
159
171
  }
@@ -174,7 +186,10 @@ export class Flagsmith {
174
186
  return await this.getEnvironmentFlagsFromApi();
175
187
  } catch (error) {
176
188
  if (!this.defaultFlagHandler) {
177
- throw new Error('getEnvironmentFlags failed and no default flag handler was provided', { cause: error });
189
+ throw new Error(
190
+ 'getEnvironmentFlags failed and no default flag handler was provided',
191
+ { cause: error }
192
+ );
178
193
  }
179
194
  this.logger.error(error, 'getEnvironmentFlags failed');
180
195
  return new Flags({
@@ -191,13 +206,13 @@ export class Flagsmith {
191
206
  *
192
207
  * @param {string} identifier a unique identifier for the identity in the current
193
208
  environment, e.g. email address, username, uuid
194
- * @param {{[key:string]:any | ITraitConfig}} traits? a dictionary of traits to add / update on the identity in
209
+ * @param {{[key:string]:any | TraitConfig}} traits? a dictionary of traits to add / update on the identity in
195
210
  Flagsmith, e.g. {"num_orders": 10} or {age: {value: 30, transient: true}}
196
211
  * @returns Flags object holding all the flags for the given identity.
197
212
  */
198
213
  async getIdentityFlags(
199
214
  identifier: string,
200
- traits?: { [key: string]: FlagsmithTraitValue | ITraitConfig },
215
+ traits?: { [key: string]: FlagsmithTraitValue | TraitConfig },
201
216
  transient: boolean = false
202
217
  ): Promise<Flags> {
203
218
  if (!identifier) {
@@ -216,7 +231,10 @@ export class Flagsmith {
216
231
  return await this.getIdentityFlagsFromApi(identifier, traits, transient);
217
232
  } catch (error) {
218
233
  if (!this.defaultFlagHandler) {
219
- throw new Error('getIdentityFlags failed and no default flag handler was provided', { cause: error })
234
+ throw new Error(
235
+ 'getIdentityFlags failed and no default flag handler was provided',
236
+ { cause: error }
237
+ );
220
238
  }
221
239
  this.logger.error(error, 'getIdentityFlags failed');
222
240
  return new Flags({
@@ -292,8 +310,8 @@ export class Flagsmith {
292
310
  async updateEnvironment(): Promise<void> {
293
311
  try {
294
312
  if (this.environmentPromise) {
295
- await this.environmentPromise
296
- return
313
+ await this.environmentPromise;
314
+ return;
297
315
  }
298
316
  const environment = await this.fetchEnvironment();
299
317
  this.onEnvironmentChange(null, environment);
@@ -334,7 +352,7 @@ export class Flagsmith {
334
352
  this.retries,
335
353
  this.requestTimeoutMs,
336
354
  this.requestRetryDelayMilliseconds,
337
- this.customFetch,
355
+ this.customFetch
338
356
  );
339
357
 
340
358
  if (data.status !== 200) {
@@ -438,7 +456,7 @@ export class Flagsmith {
438
456
 
439
457
  private async getIdentityFlagsFromApi(
440
458
  identifier: string,
441
- traits: { [key: string]: FlagsmithTraitValue | ITraitConfig },
459
+ traits: { [key: string]: FlagsmithTraitValue | TraitConfig },
442
460
  transient: boolean = false
443
461
  ) {
444
462
  if (!this.identitiesUrl) {
@@ -463,8 +481,7 @@ export class Flagsmith {
463
481
  traits: { key: string; value: any }[]
464
482
  ) {
465
483
  const traitModels = traits.map(trait => new TraitModel(trait.key, trait.value));
466
- let identityWithOverrides =
467
- this.identitiesWithOverridesByIdentifier?.get(identifier);
484
+ let identityWithOverrides = this.identitiesWithOverridesByIdentifier?.get(identifier);
468
485
  if (identityWithOverrides) {
469
486
  identityWithOverrides.updateTraits(traitModels);
470
487
  return identityWithOverrides;
package/sdk/models.ts CHANGED
@@ -1,34 +1,57 @@
1
1
  import { FeatureStateModel } from '../flagsmith-engine/features/models.js';
2
2
  import { AnalyticsProcessor } from './analytics.js';
3
3
 
4
+ type FlagValue = string | number | boolean | undefined;
5
+
6
+ /**
7
+ * A Flagsmith feature. It has an enabled/disabled state, and an optional {@link FlagValue}.
8
+ */
4
9
  export class BaseFlag {
10
+ /**
11
+ * Indicates whether this feature is enabled.
12
+ */
5
13
  enabled: boolean;
6
- value: string | number | boolean | undefined;
14
+ /**
15
+ * An optional {@link FlagValue} for this feature.
16
+ */
17
+ value: FlagValue;
18
+ /**
19
+ * If true, the state for this feature was determined by a default flag handler. See {@link DefaultFlag}.
20
+ */
7
21
  isDefault: boolean;
8
22
 
9
- constructor(
10
- value: string | number | boolean | undefined,
11
- enabled: boolean,
12
- isDefault: boolean
13
- ) {
23
+ constructor(value: FlagValue, enabled: boolean, isDefault: boolean) {
14
24
  this.value = value;
15
25
  this.enabled = enabled;
16
26
  this.isDefault = isDefault;
17
27
  }
18
28
  }
19
29
 
30
+ /**
31
+ * A {@link BaseFlag} returned by a default flag handler when flag evaluation fails.
32
+ * @see FlagsmithConfig#defaultFlagHandler
33
+ */
20
34
  export class DefaultFlag extends BaseFlag {
21
- constructor(value: string | number | boolean | undefined, enabled: boolean) {
35
+ constructor(value: FlagValue, enabled: boolean) {
22
36
  super(value, enabled, true);
23
37
  }
24
38
  }
25
39
 
40
+ /**
41
+ * A Flagsmith feature retrieved from a successful flag evaluation.
42
+ */
26
43
  export class Flag extends BaseFlag {
44
+ /**
45
+ * An identifier for this feature, unique in a single Flagsmith installation.
46
+ */
27
47
  featureId: number;
48
+ /**
49
+ * The programmatic name for this feature, unique per Flagsmith project.
50
+ */
28
51
  featureName: string;
29
52
 
30
53
  constructor(params: {
31
- value: string | number | boolean | undefined;
54
+ value: FlagValue;
32
55
  enabled: boolean;
33
56
  isDefault?: boolean;
34
57
  featureId: number;
@@ -82,7 +105,7 @@ export class Flags {
82
105
  defaultFlagHandler?: (f: string) => DefaultFlag;
83
106
  identityID?: string | number;
84
107
  }): Flags {
85
- const flags: { [key: string]: any } = {};
108
+ const flags: { [key: string]: Flag } = {};
86
109
  for (const fs of data.featureStates) {
87
110
  flags[fs.feature.name] = Flag.fromFeatureStateModel(fs, data.identityID);
88
111
  }
@@ -98,7 +121,7 @@ export class Flags {
98
121
  analyticsProcessor?: AnalyticsProcessor;
99
122
  defaultFlagHandler?: (v: string) => DefaultFlag;
100
123
  }): Flags {
101
- const flags: { [key: string]: any } = {};
124
+ const flags: { [key: string]: Flag } = {};
102
125
 
103
126
  for (const flagData of data.apiFlags) {
104
127
  flags[flagData['feature']['name']] = Flag.fromAPIFlag(flagData);
@@ -124,7 +147,6 @@ export class Flags {
124
147
  }
125
148
 
126
149
  return { enabled: false, isDefault: true, value: undefined };
127
-
128
150
  }
129
151
 
130
152
  if (this.analyticsProcessor && flag.featureId) {
@@ -134,7 +156,7 @@ export class Flags {
134
156
  return flag;
135
157
  }
136
158
 
137
- getFeatureValue(featureName: string): any {
159
+ getFeatureValue(featureName: string): FlagValue {
138
160
  return this.getFlag(featureName).value;
139
161
  }
140
162
 
@@ -3,7 +3,7 @@ import { buildEnvironmentModel } from '../flagsmith-engine/environments/util.js'
3
3
  import { EnvironmentModel } from '../flagsmith-engine/environments/models.js';
4
4
 
5
5
  export class BaseOfflineHandler {
6
- getEnvironment() : EnvironmentModel {
6
+ getEnvironment(): EnvironmentModel {
7
7
  throw new Error('Not implemented');
8
8
  }
9
9
  }
package/sdk/types.ts CHANGED
@@ -3,10 +3,12 @@ import { EnvironmentModel } from '../flagsmith-engine/index.js';
3
3
  import { Dispatcher } from 'undici-types';
4
4
  import { Logger } from 'pino';
5
5
  import { BaseOfflineHandler } from './offline_handlers.js';
6
- import { Flagsmith } from './index.js'
7
-
8
- export type IFlagsmithValue<T = string | number | boolean | null> = T;
6
+ import { Flagsmith } from './index.js';
9
7
 
8
+ /**
9
+ * A concrete type for the possible values of a feature.
10
+ */
11
+ export type FlagsmithValue<T = string | number | boolean | null> = T;
10
12
 
11
13
  /**
12
14
  * Stores and retrieves {@link Flags} from a cache.
@@ -26,7 +28,7 @@ export interface FlagsmithCache {
26
28
  set(key: string, value: Flags): Promise<void>;
27
29
  }
28
30
 
29
- export type Fetch = typeof fetch
31
+ export type Fetch = typeof fetch;
30
32
 
31
33
  /**
32
34
  * The configuration options for a {@link Flagsmith} client.
@@ -53,7 +55,7 @@ export interface FlagsmithConfig {
53
55
  /**
54
56
  * Custom headers to use in all HTTP requests.
55
57
  */
56
- customHeaders?: HeadersInit
58
+ customHeaders?: HeadersInit;
57
59
  /**
58
60
  * The network request timeout duration, in seconds.
59
61
  *
@@ -96,7 +98,7 @@ export interface FlagsmithConfig {
96
98
  * const defaultHandler = () => new DefaultFlag(undefined, false)
97
99
  *
98
100
  * // Enable only VIP flags by default
99
- * const vipDefaultHandler = (key: string) => new Default(undefined, key.startsWith('vip_'))
101
+ * const vipDefaultHandler = (key: string) => new DefaultFlag(undefined, key.startsWith('vip_'))
100
102
  */
101
103
  defaultFlagHandler?: (flagKey: string) => DefaultFlag;
102
104
  cache?: FlagsmithCache;
@@ -117,9 +119,16 @@ export interface FlagsmithConfig {
117
119
  offlineHandler?: BaseOfflineHandler;
118
120
  }
119
121
 
120
- export interface ITraitConfig {
122
+ /**
123
+ * Represents the configuration for a trait in Flagsmith.
124
+ *
125
+ * @property value The {@link FlagsmithTraitValue} for this trait.
126
+ * @property [transient] Indicates whether the trait should be persisted when used in a remote flag evaluation context.
127
+ * Defaults to false.
128
+ */
129
+ export interface TraitConfig {
121
130
  value: FlagsmithTraitValue;
122
131
  transient?: boolean;
123
132
  }
124
133
 
125
- export declare type FlagsmithTraitValue = IFlagsmithValue;
134
+ export declare type FlagsmithTraitValue = FlagsmithValue;
package/sdk/utils.ts CHANGED
@@ -1,11 +1,11 @@
1
- import {Fetch, FlagsmithTraitValue, ITraitConfig} from './types.js';
2
- import {Dispatcher} from "undici-types";
1
+ import { Fetch, FlagsmithTraitValue, TraitConfig } from './types.js';
2
+ import { Dispatcher } from 'undici-types';
3
3
 
4
- type Traits = { [key: string]: ITraitConfig | FlagsmithTraitValue };
4
+ type Traits = { [key: string]: TraitConfig | FlagsmithTraitValue };
5
5
 
6
6
  export function isTraitConfig(
7
- traitValue: ITraitConfig | FlagsmithTraitValue
8
- ): traitValue is ITraitConfig {
7
+ traitValue: TraitConfig | FlagsmithTraitValue
8
+ ): traitValue is TraitConfig {
9
9
  return !!traitValue && typeof traitValue == 'object' && traitValue.value !== undefined;
10
10
  }
11
11
 
@@ -15,12 +15,12 @@ export function generateIdentitiesData(identifier: string, traits: Traits, trans
15
15
  return {
16
16
  trait_key: key,
17
17
  trait_value: value?.value,
18
- transient: value?.transient,
18
+ transient: value?.transient
19
19
  };
20
20
  } else {
21
21
  return {
22
22
  trait_key: key,
23
- trait_value: value,
23
+ trait_value: value
24
24
  };
25
25
  }
26
26
  });
@@ -47,7 +47,7 @@ export const retryFetch = (
47
47
  retries: number = 3,
48
48
  timeoutMs: number = 10, // set an overall timeout for this function
49
49
  retryDelayMs: number = 1000,
50
- customFetch: Fetch,
50
+ customFetch: Fetch
51
51
  ): Promise<Response> => {
52
52
  const retryWrapper = async (n: number): Promise<Response> => {
53
53
  try {
@@ -3,11 +3,9 @@ import { EnvironmentModel } from '../../../flagsmith-engine/environments/models.
3
3
  import { buildEnvironmentModel } from '../../../flagsmith-engine/environments/util.js';
4
4
  import { IdentityModel } from '../../../flagsmith-engine/identities/models.js';
5
5
  import { buildIdentityModel } from '../../../flagsmith-engine/identities/util.js';
6
- import * as testData from '../engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json'
6
+ import * as testData from '../engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json';
7
7
 
8
- function extractTestCases(
9
- data: any
10
- ): {
8
+ function extractTestCases(data: any): {
11
9
  environment: EnvironmentModel;
12
10
  identity: IdentityModel;
13
11
  response: any;
@@ -73,11 +73,7 @@ test('test_identity_get_all_feature_states_with_traits_hideDisabledFlags', () =>
73
73
  const env = environmentWithSegmentOverride();
74
74
  env.project.hideDisabledFlags = true;
75
75
 
76
- const featureStates = getIdentityFeatureStates(
77
- env,
78
- identityInSegment(),
79
- [trait_models]
80
- );
76
+ const featureStates = getIdentityFeatureStates(env, identityInSegment(), [trait_models]);
81
77
  expect(featureStates.length).toBe(0);
82
78
  });
83
79
 
@@ -66,11 +66,11 @@ test('test_feature_state_get_value_mv_values', () => {
66
66
  const mvFeatureState = new FeatureStateModel(myFeature, true, 1);
67
67
  mvFeatureState.multivariateFeatureStateValues = [
68
68
  mvFeatureStateValue1,
69
- mvFeatureStateValue2,
69
+ mvFeatureStateValue2
70
70
  ];
71
71
 
72
72
  mvFeatureState.setValue(mvFeatureControlValue);
73
73
 
74
- expect(mvFeatureState.getValue("test")).toBe(mvFeatureValue2);
74
+ expect(mvFeatureState.getValue('test')).toBe(mvFeatureValue2);
75
75
  }
76
76
  });
@@ -47,7 +47,7 @@ test('test_build_identity_model_from_dictionary_uses_identity_feature_list_for_i
47
47
  id: 1,
48
48
  identifier: 'test-identity',
49
49
  environment_api_key: 'api-key',
50
- created_date: '2021-08-22T06:25:23.406995Z',
50
+ created_date: '2021-08-22T06:25:23.406995Z'
51
51
  };
52
52
 
53
53
  const identityModel = buildIdentityModel(identity_dict);
@@ -1,44 +1,70 @@
1
1
  import {
2
2
  ALL_RULE,
3
3
  CONDITION_OPERATORS,
4
- PERCENTAGE_SPLIT,
4
+ PERCENTAGE_SPLIT
5
5
  } from '../../../../flagsmith-engine/segments/constants.js';
6
- import {SegmentConditionModel} from '../../../../flagsmith-engine/segments/models.js';
7
- import {traitsMatchSegmentCondition, evaluateIdentityInSegment} from "../../../../flagsmith-engine/segments/evaluators.js";
8
- import {TraitModel, IdentityModel} from "../../../../flagsmith-engine/index.js";
9
- import {environment} from "../utils.js";
6
+ import { SegmentConditionModel } from '../../../../flagsmith-engine/segments/models.js';
7
+ import {
8
+ traitsMatchSegmentCondition,
9
+ evaluateIdentityInSegment
10
+ } from '../../../../flagsmith-engine/segments/evaluators.js';
11
+ import { TraitModel, IdentityModel } from '../../../../flagsmith-engine/index.js';
12
+ import { environment } from '../utils.js';
10
13
  import { buildSegmentModel } from '../../../../flagsmith-engine/segments/util.js';
11
14
  import { getHashedPercentateForObjIds } from '../../../../flagsmith-engine/utils/hashing/index.js';
12
15
 
13
-
14
16
  // todo: work out how to implement this in a test function or before hook
15
17
  vi.mock('../../../../flagsmith-engine/utils/hashing', () => ({
16
18
  getHashedPercentateForObjIds: vi.fn(() => 1)
17
19
  }));
18
20
 
19
-
20
- let traitExistenceTestCases: [string, string | null | undefined, string | null | undefined, TraitModel [],boolean][] = [
21
- [CONDITION_OPERATORS.IS_SET,'foo', null,[] , false],
22
- [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [new TraitModel('foo','bar')], true],
23
- [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [new TraitModel('foo','bar'), new TraitModel('fooBaz','baz')], true],
21
+ let traitExistenceTestCases: [
22
+ string,
23
+ string | null | undefined,
24
+ string | null | undefined,
25
+ TraitModel[],
26
+ boolean
27
+ ][] = [
28
+ [CONDITION_OPERATORS.IS_SET, 'foo', null, [], false],
29
+ [CONDITION_OPERATORS.IS_SET, 'foo', undefined, [new TraitModel('foo', 'bar')], true],
30
+ [
31
+ CONDITION_OPERATORS.IS_SET,
32
+ 'foo',
33
+ undefined,
34
+ [new TraitModel('foo', 'bar'), new TraitModel('fooBaz', 'baz')],
35
+ true
36
+ ],
24
37
  [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [], true],
25
- [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [new TraitModel('foo','bar')], false],
26
- [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [new TraitModel('foo','bar'), new TraitModel('fooBaz','baz')], false]
38
+ [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [new TraitModel('foo', 'bar')], false],
39
+ [
40
+ CONDITION_OPERATORS.IS_NOT_SET,
41
+ 'foo',
42
+ null,
43
+ [new TraitModel('foo', 'bar'), new TraitModel('fooBaz', 'baz')],
44
+ false
45
+ ]
27
46
  ];
28
47
 
29
48
  test('test_traits_match_segment_condition_for_trait_existence_operators', () => {
30
49
  for (const testCase of traitExistenceTestCases) {
31
- const [operator, conditionProperty, conditionValue, traits, expectedResult] = testCase
32
- let segmentModel = new SegmentConditionModel(operator, conditionValue, conditionProperty)
33
- expect(
34
- traitsMatchSegmentCondition (traits, segmentModel, 'any','any')
35
- ).toBe(expectedResult);
50
+ const [operator, conditionProperty, conditionValue, traits, expectedResult] = testCase;
51
+ let segmentModel = new SegmentConditionModel(operator, conditionValue, conditionProperty);
52
+ expect(traitsMatchSegmentCondition(traits, segmentModel, 'any', 'any')).toBe(
53
+ expectedResult
54
+ );
36
55
  }
37
56
  });
38
57
 
39
-
40
58
  test('evaluateIdentityInSegment uses django ID for hashed percentage when present', () => {
41
- var identityModel = new IdentityModel(Date.now().toString(), [], [], environment().apiKey, 'identity_1', undefined, 1);
59
+ var identityModel = new IdentityModel(
60
+ Date.now().toString(),
61
+ [],
62
+ [],
63
+ environment().apiKey,
64
+ 'identity_1',
65
+ undefined,
66
+ 1
67
+ );
42
68
  const segmentDefinition = {
43
69
  id: 1,
44
70
  name: 'percentage_split_segment',
@@ -49,7 +75,7 @@ test('evaluateIdentityInSegment uses django ID for hashed percentage when presen
49
75
  {
50
76
  operator: PERCENTAGE_SPLIT,
51
77
  property_: null,
52
- value: "10"
78
+ value: '10'
53
79
  }
54
80
  ],
55
81
  rules: []
@@ -62,6 +88,9 @@ test('evaluateIdentityInSegment uses django ID for hashed percentage when presen
62
88
  var result = evaluateIdentityInSegment(identityModel, segmentModel);
63
89
 
64
90
  expect(result).toBe(true);
65
- expect(getHashedPercentateForObjIds).toHaveBeenCalledTimes(1)
66
- expect(getHashedPercentateForObjIds).toHaveBeenCalledWith([segmentModel.id, identityModel.djangoID])
91
+ expect(getHashedPercentateForObjIds).toHaveBeenCalledTimes(1);
92
+ expect(getHashedPercentateForObjIds).toHaveBeenCalledWith([
93
+ segmentModel.id,
94
+ identityModel.djangoID
95
+ ]);
67
96
  });