flagsmith-nodejs 6.0.1 → 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.
- package/.github/workflows/publish.yml +17 -17
- package/.github/workflows/pull_request.yaml +33 -33
- package/.husky/pre-commit +0 -0
- package/.prettierignore +2 -1
- package/README.md +2 -1
- package/build/cjs/flagsmith-engine/features/util.js +3 -3
- package/build/cjs/flagsmith-engine/index.d.ts +1 -1
- package/build/cjs/flagsmith-engine/index.js +2 -1
- package/build/cjs/flagsmith-engine/segments/models.js +7 -7
- package/build/cjs/flagsmith-engine/utils/hashing/index.js +1 -1
- package/build/cjs/index.d.ts +4 -4
- package/build/cjs/index.js +3 -1
- package/build/cjs/sdk/analytics.d.ts +1 -1
- package/build/cjs/sdk/index.d.ts +5 -5
- package/build/cjs/sdk/index.js +7 -5
- package/build/cjs/sdk/models.d.ts +25 -0
- package/build/cjs/sdk/models.js +25 -0
- package/build/cjs/sdk/types.d.ts +14 -4
- package/build/cjs/sdk/utils.d.ts +4 -4
- package/build/cjs/sdk/utils.js +2 -2
- package/build/esm/flagsmith-engine/features/models.js +1 -1
- package/build/esm/flagsmith-engine/features/util.js +3 -3
- package/build/esm/flagsmith-engine/index.d.ts +1 -1
- package/build/esm/flagsmith-engine/index.js +1 -1
- package/build/esm/flagsmith-engine/segments/models.js +7 -7
- package/build/esm/flagsmith-engine/utils/hashing/index.js +2 -2
- package/build/esm/flagsmith-engine/utils/index.js +1 -1
- package/build/esm/index.d.ts +4 -4
- package/build/esm/index.js +3 -3
- package/build/esm/sdk/analytics.d.ts +1 -1
- package/build/esm/sdk/index.d.ts +5 -5
- package/build/esm/sdk/index.js +6 -5
- package/build/esm/sdk/models.d.ts +25 -0
- package/build/esm/sdk/models.js +25 -0
- package/build/esm/sdk/types.d.ts +14 -4
- package/build/esm/sdk/utils.d.ts +4 -4
- package/build/esm/sdk/utils.js +2 -2
- package/flagsmith-engine/environments/util.ts +2 -2
- package/flagsmith-engine/features/models.ts +1 -1
- package/flagsmith-engine/features/util.ts +14 -14
- package/flagsmith-engine/identities/models.ts +1 -1
- package/flagsmith-engine/index.ts +1 -1
- package/flagsmith-engine/segments/evaluators.ts +2 -3
- package/flagsmith-engine/segments/models.ts +25 -15
- package/flagsmith-engine/utils/hashing/index.ts +3 -3
- package/flagsmith-engine/utils/index.ts +4 -2
- package/index.ts +19 -22
- package/package.json +1 -1
- package/sdk/analytics.ts +7 -5
- package/sdk/index.ts +38 -21
- package/sdk/models.ts +25 -0
- package/sdk/offline_handlers.ts +1 -1
- package/sdk/types.ts +17 -8
- package/sdk/utils.ts +8 -8
- package/tests/engine/e2e/engine.test.ts +2 -4
- package/tests/engine/unit/engine.test.ts +1 -5
- package/tests/engine/unit/features/models.test.ts +2 -2
- package/tests/engine/unit/identities/identities_builders.test.ts +1 -1
- package/tests/engine/unit/segments/segment_evaluators.test.ts +52 -23
- package/tests/engine/unit/segments/segments_model.test.ts +35 -37
- package/tests/engine/unit/utils/utils.test.ts +28 -30
- package/tests/sdk/analytics.test.ts +25 -26
- package/tests/sdk/flagsmith-cache.test.ts +84 -76
- package/tests/sdk/flagsmith-environment-flags.test.ts +93 -93
- package/tests/sdk/flagsmith-identity-flags.test.ts +146 -149
- package/tests/sdk/flagsmith.test.ts +40 -42
- package/tests/sdk/offline-handlers.test.ts +32 -32
- package/tests/sdk/polling.test.ts +0 -1
- package/tests/sdk/utils.ts +26 -18
- package/vitest.config.ts +10 -15
|
@@ -1,213 +1,210 @@
|
|
|
1
1
|
import Flagsmith from '../../sdk/index.js';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
fetch,
|
|
4
|
+
environmentJSON,
|
|
5
|
+
flagsmith,
|
|
6
|
+
identitiesJSON,
|
|
7
|
+
identityWithTransientTraitsJSON,
|
|
8
|
+
transientIdentityJSON,
|
|
9
|
+
badFetch
|
|
10
10
|
} from './utils.js';
|
|
11
11
|
import { DefaultFlag } from '../../sdk/models.js';
|
|
12
12
|
|
|
13
13
|
vi.mock('../../sdk/polling_manager');
|
|
14
14
|
|
|
15
15
|
test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', async () => {
|
|
16
|
-
|
|
16
|
+
const identifier = 'identifier';
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const flg = flagsmith();
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags();
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
23
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
24
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test('test_get_identity_flags_uses_environment_when_local_environment_no_traits', async () => {
|
|
28
|
-
|
|
28
|
+
const identifier = 'identifier';
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const flg = flagsmith({
|
|
31
|
+
environmentKey: 'ser.key',
|
|
32
|
+
enableLocalEvaluation: true
|
|
33
|
+
});
|
|
34
34
|
|
|
35
|
+
const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags();
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(identityFlags[0].value).toBe('some-value');
|
|
40
|
-
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
37
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
38
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
39
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const identifier = 'identifier';
|
|
44
|
+
const traits = { some_trait: 'some_value' };
|
|
45
|
+
const flg = flagsmith();
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags();
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
50
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
51
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
53
52
|
});
|
|
54
53
|
|
|
55
54
|
test('test_default_flag_is_not_used_when_identity_flags_returned', async () => {
|
|
56
|
-
|
|
55
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
const flg = flagsmith({
|
|
60
|
+
environmentKey: 'key',
|
|
61
|
+
defaultFlagHandler: defaultFlagHandler
|
|
62
|
+
});
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
65
|
+
const flag = flags.getFlag('some_feature');
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
expect(flag.isDefault).toBe(false);
|
|
68
|
+
expect(flag.value).not.toBe(defaultFlag.value);
|
|
69
|
+
expect(flag.value).toBe('some-value');
|
|
71
70
|
});
|
|
72
71
|
|
|
73
72
|
test('test_default_flag_is_used_when_no_identity_flags_returned', async () => {
|
|
74
|
-
|
|
73
|
+
fetch.mockResolvedValue(new Response(JSON.stringify({ flags: [], traits: [] })));
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
76
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
const flg = new Flagsmith({
|
|
79
|
+
environmentKey: 'key',
|
|
80
|
+
defaultFlagHandler: defaultFlagHandler
|
|
81
|
+
});
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
84
|
+
const flag = flags.getFlag('some_feature');
|
|
86
85
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
expect(flag.isDefault).toBe(true);
|
|
87
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
88
|
+
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
90
89
|
});
|
|
91
90
|
|
|
92
91
|
test('test_default_flag_is_used_when_no_identity_flags_returned_due_to_error', async () => {
|
|
93
|
-
|
|
92
|
+
fetch.mockResolvedValue(new Response('bad data'));
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
95
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
const flg = new Flagsmith({
|
|
98
|
+
environmentKey: 'key',
|
|
99
|
+
defaultFlagHandler: defaultFlagHandler
|
|
100
|
+
});
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
103
|
+
const flag = flags.getFlag('some_feature');
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
expect(flag.isDefault).toBe(true);
|
|
106
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
107
|
+
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
109
108
|
});
|
|
110
109
|
|
|
111
110
|
test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => {
|
|
112
|
-
|
|
111
|
+
fetch.mockResolvedValue(new Response(JSON.stringify({ flags: [], traits: [] })));
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
const flg = flagsmith({
|
|
114
|
+
environmentKey: 'key'
|
|
115
|
+
});
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
118
|
+
const flag = flags.getFlag('some_feature');
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
expect(flag.isDefault).toBe(true);
|
|
121
|
+
expect(flag.value).toBe(undefined);
|
|
122
|
+
expect(flag.enabled).toBe(false);
|
|
124
123
|
});
|
|
125
124
|
|
|
126
125
|
test('test_get_identity_flags_multivariate_value_with_local_evaluation_enabled', async () => {
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
fetch.mockResolvedValue(new Response(environmentJSON));
|
|
127
|
+
const identifier = 'identifier';
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
const flg = flagsmith({
|
|
130
|
+
environmentKey: 'ser.key',
|
|
131
|
+
enableLocalEvaluation: true
|
|
132
|
+
});
|
|
134
133
|
|
|
135
|
-
|
|
134
|
+
const identityFlags = await flg.getIdentityFlags(identifier);
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
expect(identityFlags.getFeatureValue('mv_feature')).toBe('bar');
|
|
137
|
+
expect(identityFlags.isFeatureEnabled('mv_feature')).toBe(false);
|
|
139
138
|
});
|
|
140
139
|
|
|
141
|
-
|
|
142
140
|
test('test_transient_identity', async () => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
141
|
+
fetch.mockResolvedValue(new Response(transientIdentityJSON));
|
|
142
|
+
const identifier = 'transient_identifier';
|
|
143
|
+
const traits = { some_trait: 'some_value' };
|
|
144
|
+
const traitsInRequest = [{ trait_key: Object.keys(traits)[0], trait_value: traits.some_trait }];
|
|
145
|
+
const transient = true;
|
|
146
|
+
const flg = flagsmith();
|
|
147
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits, transient)).allFlags();
|
|
148
|
+
|
|
149
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
150
|
+
`https://edge.api.flagsmith.com/api/v1/identities/`,
|
|
151
|
+
expect.objectContaining({
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'sometestfakekey' },
|
|
154
|
+
body: JSON.stringify({ identifier, traits: traitsInRequest, transient })
|
|
155
|
+
})
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
expect(identityFlags[0].enabled).toBe(false);
|
|
159
|
+
expect(identityFlags[0].value).toBe('some-transient-identity-value');
|
|
160
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
163
161
|
});
|
|
164
162
|
|
|
165
|
-
|
|
166
163
|
test('test_identity_with_transient_traits', async () => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
164
|
+
fetch.mockResolvedValue(new Response(identityWithTransientTraitsJSON));
|
|
165
|
+
const identifier = 'transient_trait_identifier';
|
|
166
|
+
const traits = {
|
|
167
|
+
some_trait: 'some_value',
|
|
168
|
+
another_trait: { value: 'another_value', transient: true },
|
|
169
|
+
explicitly_non_transient_trait: { value: 'non_transient_value', transient: false }
|
|
170
|
+
};
|
|
171
|
+
const traitsInRequest = [
|
|
172
|
+
{
|
|
173
|
+
trait_key: Object.keys(traits)[0],
|
|
174
|
+
trait_value: traits.some_trait
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
trait_key: Object.keys(traits)[1],
|
|
178
|
+
trait_value: traits.another_trait.value,
|
|
179
|
+
transient: true
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
trait_key: Object.keys(traits)[2],
|
|
183
|
+
trait_value: traits.explicitly_non_transient_trait.value,
|
|
184
|
+
transient: false
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
const flg = flagsmith();
|
|
188
|
+
|
|
189
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags();
|
|
190
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
191
|
+
`https://edge.api.flagsmith.com/api/v1/identities/`,
|
|
192
|
+
expect.objectContaining({
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'sometestfakekey' },
|
|
195
|
+
body: JSON.stringify({ identifier, traits: traitsInRequest })
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
199
|
+
expect(identityFlags[0].value).toBe('some-identity-with-transient-trait-value');
|
|
200
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
204
201
|
});
|
|
205
202
|
|
|
206
203
|
test('getIdentityFlags fails if API call failed and no default flag handler was provided', async () => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
})
|
|
204
|
+
const flg = flagsmith({
|
|
205
|
+
fetch: badFetch
|
|
206
|
+
});
|
|
207
|
+
await expect(flg.getIdentityFlags('user')).rejects.toThrow(
|
|
208
|
+
'getIdentityFlags failed and no default flag handler was provided'
|
|
209
|
+
);
|
|
210
|
+
});
|
|
@@ -29,26 +29,26 @@ 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
43
|
test('test_set_agent_options', async () => {
|
|
44
|
-
const agent = new Agent({})
|
|
44
|
+
const agent = new Agent({});
|
|
45
45
|
|
|
46
46
|
fetch.mockImplementationOnce((url, options) => {
|
|
47
47
|
//@ts-ignore I give up
|
|
48
48
|
if (options.dispatcher !== agent) {
|
|
49
|
-
throw new Error(
|
|
49
|
+
throw new Error('Agent has not been set on retry fetch');
|
|
50
50
|
}
|
|
51
|
-
return Promise.resolve(new Response(environmentJSON))
|
|
51
|
+
return Promise.resolve(new Response(environmentJSON));
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
const flg = flagsmith({
|
|
@@ -69,7 +69,6 @@ test('test_get_identity_segments', async () => {
|
|
|
69
69
|
expect(segments2.length).toEqual(0);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
|
|
73
72
|
test('test_get_identity_segments_empty_without_local_eval', async () => {
|
|
74
73
|
const flg = new Flagsmith({
|
|
75
74
|
environmentKey: 'ser.key',
|
|
@@ -82,7 +81,7 @@ test('test_get_identity_segments_empty_without_local_eval', async () => {
|
|
|
82
81
|
test('test_update_environment_uses_req_when_inited', async () => {
|
|
83
82
|
const flg = flagsmith({
|
|
84
83
|
environmentKey: 'ser.key',
|
|
85
|
-
enableLocalEvaluation: true
|
|
84
|
+
enableLocalEvaluation: true
|
|
86
85
|
});
|
|
87
86
|
|
|
88
87
|
delay(400);
|
|
@@ -100,7 +99,7 @@ test('test_isFeatureEnabled_environment', async () => {
|
|
|
100
99
|
const flg = new Flagsmith({
|
|
101
100
|
environmentKey: 'key',
|
|
102
101
|
defaultFlagHandler: defaultFlagHandler,
|
|
103
|
-
enableAnalytics: true
|
|
102
|
+
enableAnalytics: true
|
|
104
103
|
});
|
|
105
104
|
|
|
106
105
|
const flags = await flg.getEnvironmentFlags();
|
|
@@ -110,9 +109,9 @@ test('test_isFeatureEnabled_environment', async () => {
|
|
|
110
109
|
});
|
|
111
110
|
|
|
112
111
|
test('test_fetch_recovers_after_single_API_error', async () => {
|
|
113
|
-
fetch.mockRejectedValueOnce('Error during fetching the API response')
|
|
112
|
+
fetch.mockRejectedValueOnce('Error during fetching the API response');
|
|
114
113
|
const flg = flagsmith({
|
|
115
|
-
environmentKey: 'key'
|
|
114
|
+
environmentKey: 'key'
|
|
116
115
|
});
|
|
117
116
|
|
|
118
117
|
const flags = await flg.getEnvironmentFlags();
|
|
@@ -132,7 +131,7 @@ test.each([
|
|
|
132
131
|
enableLocalEvaluation,
|
|
133
132
|
environmentKey,
|
|
134
133
|
defaultFlagHandler: () => new DefaultFlag('some-default-value', true),
|
|
135
|
-
fetch: badFetch
|
|
134
|
+
fetch: badFetch
|
|
136
135
|
});
|
|
137
136
|
const flags = await flg.getEnvironmentFlags();
|
|
138
137
|
const flag = flags.getFlag('some_feature');
|
|
@@ -144,9 +143,9 @@ test.each([
|
|
|
144
143
|
|
|
145
144
|
test('default flag handler used when timeout occurs', async () => {
|
|
146
145
|
fetch.mockImplementation(async (...args) => {
|
|
147
|
-
const forever = new Promise(() => {})
|
|
148
|
-
await forever
|
|
149
|
-
throw new Error('waited forever')
|
|
146
|
+
const forever = new Promise(() => {});
|
|
147
|
+
await forever;
|
|
148
|
+
throw new Error('waited forever');
|
|
150
149
|
});
|
|
151
150
|
|
|
152
151
|
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
@@ -156,7 +155,7 @@ test('default flag handler used when timeout occurs', async () => {
|
|
|
156
155
|
const flg = flagsmith({
|
|
157
156
|
environmentKey: 'key',
|
|
158
157
|
defaultFlagHandler: defaultFlagHandler,
|
|
159
|
-
requestTimeoutSeconds: 0.0001
|
|
158
|
+
requestTimeoutSeconds: 0.0001
|
|
160
159
|
});
|
|
161
160
|
|
|
162
161
|
const flags = await flg.getEnvironmentFlags();
|
|
@@ -164,35 +163,32 @@ test('default flag handler used when timeout occurs', async () => {
|
|
|
164
163
|
expect(flag.isDefault).toBe(true);
|
|
165
164
|
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
166
165
|
expect(flag.value).toBe(defaultFlag.value);
|
|
167
|
-
})
|
|
166
|
+
});
|
|
168
167
|
|
|
169
168
|
test('request timeout uses default if not provided', async () => {
|
|
170
|
-
|
|
171
169
|
const flg = new Flagsmith({
|
|
172
|
-
environmentKey: 'key'
|
|
170
|
+
environmentKey: 'key'
|
|
173
171
|
});
|
|
174
172
|
|
|
175
173
|
expect(flg.requestTimeoutMs).toBe(10000);
|
|
176
|
-
})
|
|
174
|
+
});
|
|
177
175
|
|
|
178
176
|
test('test_throws_when_no_identityFlags_returned_due_to_error', async () => {
|
|
179
177
|
const flg = flagsmith({
|
|
180
178
|
environmentKey: 'key',
|
|
181
|
-
fetch: badFetch
|
|
179
|
+
fetch: badFetch
|
|
182
180
|
});
|
|
183
181
|
|
|
184
|
-
await expect(async () => await flg.getIdentityFlags('identifier'))
|
|
185
|
-
.rejects
|
|
186
|
-
.toThrow();
|
|
182
|
+
await expect(async () => await flg.getIdentityFlags('identifier')).rejects.toThrow();
|
|
187
183
|
});
|
|
188
184
|
|
|
189
185
|
test('test onEnvironmentChange is called when provided', async () => {
|
|
190
|
-
const callback = vi.fn()
|
|
186
|
+
const callback = vi.fn();
|
|
191
187
|
|
|
192
188
|
const flg = new Flagsmith({
|
|
193
189
|
environmentKey: 'ser.key',
|
|
194
190
|
enableLocalEvaluation: true,
|
|
195
|
-
onEnvironmentChange: callback
|
|
191
|
+
onEnvironmentChange: callback
|
|
196
192
|
});
|
|
197
193
|
|
|
198
194
|
fetch.mockRejectedValueOnce(new Error('API error'));
|
|
@@ -209,7 +205,7 @@ test('test onEnvironmentChange is called after error', async () => {
|
|
|
209
205
|
environmentKey: 'ser.key',
|
|
210
206
|
enableLocalEvaluation: true,
|
|
211
207
|
onEnvironmentChange: callback,
|
|
212
|
-
fetch: badFetch
|
|
208
|
+
fetch: badFetch
|
|
213
209
|
});
|
|
214
210
|
await flg.updateEnvironment();
|
|
215
211
|
expect(callback).toHaveBeenCalled();
|
|
@@ -217,15 +213,17 @@ test('test onEnvironmentChange is called after error', async () => {
|
|
|
217
213
|
|
|
218
214
|
test('getIdentityFlags throws error if identifier is empty string', async () => {
|
|
219
215
|
const flg = flagsmith({
|
|
220
|
-
environmentKey: 'key'
|
|
216
|
+
environmentKey: 'key'
|
|
221
217
|
});
|
|
222
218
|
|
|
223
|
-
await expect(flg.getIdentityFlags('')).rejects.toThrow(
|
|
224
|
-
|
|
219
|
+
await expect(flg.getIdentityFlags('')).rejects.toThrow(
|
|
220
|
+
'`identifier` argument is missing or invalid.'
|
|
221
|
+
);
|
|
222
|
+
});
|
|
225
223
|
|
|
226
224
|
test('getIdentitySegments throws error if identifier is empty string', async () => {
|
|
227
225
|
const flg = flagsmith({
|
|
228
|
-
environmentKey: 'key'
|
|
226
|
+
environmentKey: 'key'
|
|
229
227
|
});
|
|
230
228
|
|
|
231
229
|
await expect(flg.getIdentitySegments('')).rejects.toThrow(
|
|
@@ -254,15 +252,13 @@ test('offline_mode', async () => {
|
|
|
254
252
|
expect(flag.enabled).toBe(true);
|
|
255
253
|
expect(flag.value).toBe('offline-value');
|
|
256
254
|
|
|
257
|
-
|
|
258
|
-
const identityFlags: Flags = await flg.getIdentityFlags("identity");
|
|
255
|
+
const identityFlags: Flags = await flg.getIdentityFlags('identity');
|
|
259
256
|
flag = identityFlags.getFlag('some_feature');
|
|
260
257
|
expect(flag.isDefault).toBe(false);
|
|
261
258
|
expect(flag.enabled).toBe(true);
|
|
262
259
|
expect(flag.value).toBe('offline-value');
|
|
263
260
|
});
|
|
264
261
|
|
|
265
|
-
|
|
266
262
|
test('test_flagsmith_uses_offline_handler_if_set_and_no_api_response', async () => {
|
|
267
263
|
// Given
|
|
268
264
|
const environment: EnvironmentModel = environmentModel(JSON.parse(offlineEnvironmentJSON));
|
|
@@ -281,14 +277,13 @@ test('test_flagsmith_uses_offline_handler_if_set_and_no_api_response', async ()
|
|
|
281
277
|
vi.spyOn(flg, 'getEnvironmentFlags');
|
|
282
278
|
vi.spyOn(flg, 'getIdentityFlags');
|
|
283
279
|
|
|
284
|
-
|
|
285
280
|
flg.environmentFlagsUrl = 'http://some.flagsmith.com/api/v1/environment-flags';
|
|
286
281
|
flg.identitiesUrl = 'http://some.flagsmith.com/api/v1/identities';
|
|
287
282
|
|
|
288
283
|
// Mock a 500 Internal Server Error response
|
|
289
284
|
const errorResponse = new Response(null, {
|
|
290
285
|
status: 500,
|
|
291
|
-
statusText: 'Internal Server Error'
|
|
286
|
+
statusText: 'Internal Server Error'
|
|
292
287
|
});
|
|
293
288
|
|
|
294
289
|
fetch.mockResolvedValue(errorResponse);
|
|
@@ -318,25 +313,28 @@ test('cannot use offline mode without offline handler', () => {
|
|
|
318
313
|
|
|
319
314
|
test('cannot use both default handler and offline handler', () => {
|
|
320
315
|
// When and Then
|
|
321
|
-
expect(() =>
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
316
|
+
expect(() =>
|
|
317
|
+
flagsmith({
|
|
318
|
+
offlineHandler: new BaseOfflineHandler(),
|
|
319
|
+
defaultFlagHandler: () => new DefaultFlag('foo', true)
|
|
320
|
+
})
|
|
321
|
+
).toThrowError('ValueError: Cannot use both defaultFlagHandler and offlineHandler.');
|
|
325
322
|
});
|
|
326
323
|
|
|
327
324
|
test('cannot create Flagsmith client in remote evaluation without API key', () => {
|
|
328
325
|
// When and Then
|
|
329
|
-
expect(() => new Flagsmith({ environmentKey: '' })).toThrowError(
|
|
326
|
+
expect(() => new Flagsmith({ environmentKey: '' })).toThrowError(
|
|
327
|
+
'ValueError: environmentKey is required.'
|
|
328
|
+
);
|
|
330
329
|
});
|
|
331
330
|
|
|
332
|
-
|
|
333
331
|
test('test_localEvaluation_true__identity_overrides_evaluated', async () => {
|
|
334
332
|
const flg = flagsmith({
|
|
335
333
|
environmentKey: 'ser.key',
|
|
336
334
|
enableLocalEvaluation: true
|
|
337
335
|
});
|
|
338
336
|
|
|
339
|
-
await flg.updateEnvironment()
|
|
337
|
+
await flg.updateEnvironment();
|
|
340
338
|
const flags = await flg.getIdentityFlags('overridden-id');
|
|
341
339
|
expect(flags.getFeatureValue('some_feature')).toEqual('some-overridden-value');
|
|
342
340
|
});
|