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.
- package/.github/workflows/conventional-commit.yml +29 -0
- package/.github/workflows/pull_request.yaml +1 -1
- package/.github/workflows/release-please.yml +18 -0
- package/.gitmodules +1 -0
- package/.husky/pre-commit +0 -0
- package/.prettierignore +2 -1
- package/.prettierrc.cjs +9 -1
- package/.release-please-manifest.json +1 -0
- package/CHANGELOG.md +552 -0
- package/CODEOWNERS +1 -0
- package/README.md +2 -3
- 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/analytics.js +3 -1
- package/build/cjs/sdk/index.d.ts +5 -5
- package/build/cjs/sdk/index.js +48 -10
- 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 +5 -4
- package/build/cjs/sdk/utils.js +16 -3
- 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/analytics.js +3 -1
- package/build/esm/sdk/index.d.ts +5 -5
- package/build/esm/sdk/index.js +48 -11
- 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 +5 -4
- package/build/esm/sdk/utils.js +14 -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/release-please-config.json +62 -0
- package/sdk/analytics.ts +10 -6
- package/sdk/index.ts +91 -28
- package/sdk/models.ts +25 -0
- package/sdk/offline_handlers.ts +1 -1
- package/sdk/types.ts +17 -8
- package/sdk/utils.ts +21 -8
- package/tests/engine/e2e/engine.test.ts +2 -4
- package/tests/engine/unit/engine.test.ts +1 -6
- 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 +30 -26
- package/tests/sdk/flagsmith-cache.test.ts +84 -76
- package/tests/sdk/flagsmith-environment-flags.test.ts +121 -93
- package/tests/sdk/flagsmith-identity-flags.test.ts +155 -149
- package/tests/sdk/flagsmith.test.ts +202 -43
- 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,154 +1,182 @@
|
|
|
1
1
|
import Flagsmith from '../../sdk/index.js';
|
|
2
2
|
import { environmentJSON, environmentModel, flagsJSON, flagsmith, fetch } from './utils.js';
|
|
3
3
|
import { DefaultFlag } from '../../sdk/models.js';
|
|
4
|
+
import { getUserAgent } from '../../sdk/utils.js';
|
|
4
5
|
|
|
5
6
|
vi.mock('../../sdk/polling_manager');
|
|
6
7
|
|
|
7
8
|
test('test_get_environment_flags_calls_api_when_no_local_environment', async () => {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const flg = flagsmith();
|
|
10
|
+
const allFlags = await (await flg.getEnvironmentFlags()).allFlags();
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
expect(fetch).toBeCalledTimes(1);
|
|
13
|
+
expect(allFlags[0].enabled).toBe(true);
|
|
14
|
+
expect(allFlags[0].value).toBe('some-value');
|
|
15
|
+
expect(allFlags[0].featureName).toBe('some_feature');
|
|
15
16
|
});
|
|
16
17
|
|
|
17
18
|
test('test_default_flag_is_used_when_no_environment_flags_returned', async () => {
|
|
18
|
-
|
|
19
|
+
fetch.mockResolvedValue(new Response(JSON.stringify([])));
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const flg = new Flagsmith({
|
|
26
|
+
environmentKey: 'key',
|
|
27
|
+
defaultFlagHandler: defaultFlagHandler,
|
|
28
|
+
customHeaders: {
|
|
29
|
+
'X-Test-Header': '1'
|
|
30
|
+
}
|
|
31
|
+
});
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const flags = await flg.getEnvironmentFlags();
|
|
34
|
+
const flag = flags.getFlag('some_feature');
|
|
35
|
+
expect(flag.isDefault).toBe(true);
|
|
36
|
+
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
37
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
test('test_analytics_processor_tracks_flags', async () => {
|
|
40
|
-
|
|
41
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const flg = flagsmith({
|
|
46
|
+
environmentKey: 'key',
|
|
47
|
+
defaultFlagHandler: defaultFlagHandler,
|
|
48
|
+
enableAnalytics: true
|
|
49
|
+
});
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const flags = await flg.getEnvironmentFlags();
|
|
52
|
+
const flag = flags.getFlag('some_feature');
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
expect(flag.isDefault).toBe(false);
|
|
55
|
+
expect(flag.enabled).toBe(true);
|
|
56
|
+
expect(flag.value).toBe('some-value');
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
test('test_getFeatureValue', async () => {
|
|
59
|
-
|
|
60
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const flg = flagsmith({
|
|
65
|
+
environmentKey: 'key',
|
|
66
|
+
defaultFlagHandler: defaultFlagHandler,
|
|
67
|
+
enableAnalytics: true
|
|
68
|
+
});
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
const flags = await flg.getEnvironmentFlags();
|
|
71
|
+
const featureValue = flags.getFeatureValue('some_feature');
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
expect(featureValue).toBe('some-value');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('test_user_agent_is_set_when_fetching_environment_flags', async () => {
|
|
77
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
78
|
+
|
|
79
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
80
|
+
|
|
81
|
+
const flg = flagsmith({
|
|
82
|
+
environmentKey: 'key',
|
|
83
|
+
defaultFlagHandler: defaultFlagHandler,
|
|
84
|
+
enableAnalytics: true
|
|
85
|
+
});
|
|
86
|
+
const flags = await flg.getEnvironmentFlags();
|
|
87
|
+
const featureValue = flags.getFeatureValue('some_feature');
|
|
88
|
+
|
|
89
|
+
expect(featureValue).toBe('some-value');
|
|
90
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
91
|
+
`https://edge.api.flagsmith.com/api/v1/flags/`,
|
|
92
|
+
expect.objectContaining({
|
|
93
|
+
method: 'GET',
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
'X-Environment-Key': 'key',
|
|
97
|
+
'User-Agent': getUserAgent()
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
);
|
|
73
101
|
});
|
|
74
102
|
|
|
75
103
|
test('test_throws_when_no_default_flag_handler_after_multiple_API_errors', async () => {
|
|
76
|
-
|
|
104
|
+
fetch.mockRejectedValue('Error during fetching the API response');
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
const flg = flagsmith({
|
|
107
|
+
environmentKey: 'key'
|
|
108
|
+
});
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
110
|
+
await expect(async () => {
|
|
111
|
+
const flags = await flg.getEnvironmentFlags();
|
|
112
|
+
const flag = flags.getFlag('some_feature');
|
|
113
|
+
}).rejects.toThrow('getEnvironmentFlags failed and no default flag handler was provided');
|
|
86
114
|
});
|
|
87
115
|
|
|
88
116
|
test('test_non_200_response_raises_flagsmith_api_error', async () => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
117
|
+
const errorResponse403 = new Response('403 Forbidden', {
|
|
118
|
+
status: 403
|
|
119
|
+
});
|
|
120
|
+
fetch.mockResolvedValue(errorResponse403);
|
|
93
121
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
122
|
+
const flg = new Flagsmith({
|
|
123
|
+
environmentKey: 'some'
|
|
124
|
+
});
|
|
97
125
|
|
|
98
|
-
|
|
126
|
+
await expect(flg.getEnvironmentFlags()).rejects.toThrow();
|
|
99
127
|
});
|
|
100
128
|
test('test_default_flag_is_not_used_when_environment_flags_returned', async () => {
|
|
101
|
-
|
|
129
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
102
130
|
|
|
103
|
-
|
|
131
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
104
132
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
133
|
+
const flg = flagsmith({
|
|
134
|
+
environmentKey: 'key',
|
|
135
|
+
defaultFlagHandler: defaultFlagHandler
|
|
136
|
+
});
|
|
109
137
|
|
|
110
|
-
|
|
111
|
-
|
|
138
|
+
const flags = await flg.getEnvironmentFlags();
|
|
139
|
+
const flag = flags.getFlag('some_feature');
|
|
112
140
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
141
|
+
expect(flag.isDefault).toBe(false);
|
|
142
|
+
expect(flag.value).not.toBe(defaultFlag.value);
|
|
143
|
+
expect(flag.value).toBe('some-value');
|
|
116
144
|
});
|
|
117
145
|
|
|
118
146
|
test('test_default_flag_is_used_when_bad_api_response_happens', async () => {
|
|
119
|
-
|
|
147
|
+
fetch.mockResolvedValue(new Response('bad-data'));
|
|
120
148
|
|
|
121
|
-
|
|
149
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
122
150
|
|
|
123
|
-
|
|
151
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
124
152
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
153
|
+
const flg = new Flagsmith({
|
|
154
|
+
environmentKey: 'key',
|
|
155
|
+
defaultFlagHandler: defaultFlagHandler
|
|
156
|
+
});
|
|
129
157
|
|
|
130
|
-
|
|
131
|
-
|
|
158
|
+
const flags = await flg.getEnvironmentFlags();
|
|
159
|
+
const flag = flags.getFlag('some_feature');
|
|
132
160
|
|
|
133
|
-
|
|
134
|
-
|
|
161
|
+
expect(flag.isDefault).toBe(true);
|
|
162
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
135
163
|
});
|
|
136
164
|
|
|
137
165
|
test('test_local_evaluation', async () => {
|
|
138
|
-
|
|
166
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
139
167
|
|
|
140
|
-
|
|
168
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
141
169
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
170
|
+
const flg = flagsmith({
|
|
171
|
+
environmentKey: 'ser.key',
|
|
172
|
+
enableLocalEvaluation: true,
|
|
173
|
+
defaultFlagHandler: defaultFlagHandler
|
|
174
|
+
});
|
|
147
175
|
|
|
148
|
-
|
|
149
|
-
|
|
176
|
+
const flags = await flg.getEnvironmentFlags();
|
|
177
|
+
const flag = flags.getFlag('some_feature');
|
|
150
178
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
179
|
+
expect(flag.isDefault).toBe(false);
|
|
180
|
+
expect(flag.value).not.toBe(defaultFlag.value);
|
|
181
|
+
expect(flag.value).toBe('some-value');
|
|
154
182
|
});
|
|
@@ -1,213 +1,219 @@
|
|
|
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
|
+
import { getUserAgent } from '../../sdk/utils.js';
|
|
12
13
|
|
|
13
14
|
vi.mock('../../sdk/polling_manager');
|
|
14
15
|
|
|
15
16
|
test('test_get_identity_flags_calls_api_when_no_local_environment_no_traits', async () => {
|
|
16
|
-
|
|
17
|
+
const identifier = 'identifier';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
const flg = flagsmith();
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags();
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
24
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
25
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
test('test_get_identity_flags_uses_environment_when_local_environment_no_traits', async () => {
|
|
28
|
-
|
|
29
|
+
const identifier = 'identifier';
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const flg = flagsmith({
|
|
32
|
+
environmentKey: 'ser.key',
|
|
33
|
+
enableLocalEvaluation: true
|
|
34
|
+
});
|
|
34
35
|
|
|
36
|
+
const identityFlags = (await flg.getIdentityFlags(identifier)).allFlags();
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(identityFlags[0].value).toBe('some-value');
|
|
40
|
-
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
38
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
39
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
40
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
test('test_get_identity_flags_calls_api_when_no_local_environment_with_traits', async () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const identifier = 'identifier';
|
|
45
|
+
const traits = { some_trait: 'some_value' };
|
|
46
|
+
const flg = flagsmith();
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags();
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
51
|
+
expect(identityFlags[0].value).toBe('some-value');
|
|
52
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test('test_default_flag_is_not_used_when_identity_flags_returned', async () => {
|
|
56
|
-
|
|
56
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const flg = flagsmith({
|
|
61
|
+
environmentKey: 'key',
|
|
62
|
+
defaultFlagHandler: defaultFlagHandler
|
|
63
|
+
});
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
66
|
+
const flag = flags.getFlag('some_feature');
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
expect(flag.isDefault).toBe(false);
|
|
69
|
+
expect(flag.value).not.toBe(defaultFlag.value);
|
|
70
|
+
expect(flag.value).toBe('some-value');
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
test('test_default_flag_is_used_when_no_identity_flags_returned', async () => {
|
|
74
|
-
|
|
74
|
+
fetch.mockResolvedValue(new Response(JSON.stringify({ flags: [], traits: [] })));
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
77
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
const flg = new Flagsmith({
|
|
80
|
+
environmentKey: 'key',
|
|
81
|
+
defaultFlagHandler: defaultFlagHandler
|
|
82
|
+
});
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
85
|
+
const flag = flags.getFlag('some_feature');
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
expect(flag.isDefault).toBe(true);
|
|
88
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
89
|
+
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
test('test_default_flag_is_used_when_no_identity_flags_returned_due_to_error', async () => {
|
|
93
|
-
|
|
93
|
+
fetch.mockResolvedValue(new Response('bad data'));
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
const defaultFlag = new DefaultFlag('some-default-value', true);
|
|
96
|
+
const defaultFlagHandler = (featureName: string) => defaultFlag;
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
const flg = new Flagsmith({
|
|
99
|
+
environmentKey: 'key',
|
|
100
|
+
defaultFlagHandler: defaultFlagHandler
|
|
101
|
+
});
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
104
|
+
const flag = flags.getFlag('some_feature');
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
expect(flag.isDefault).toBe(true);
|
|
107
|
+
expect(flag.value).toBe(defaultFlag.value);
|
|
108
|
+
expect(flag.enabled).toBe(defaultFlag.enabled);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
test('test_default_flag_is_used_when_no_identity_flags_returned_and_no_custom_default_flag_handler', async () => {
|
|
112
|
-
|
|
112
|
+
fetch.mockResolvedValue(new Response(JSON.stringify({ flags: [], traits: [] })));
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
const flg = flagsmith({
|
|
115
|
+
environmentKey: 'key'
|
|
116
|
+
});
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
const flags = await flg.getIdentityFlags('identifier');
|
|
119
|
+
const flag = flags.getFlag('some_feature');
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
expect(flag.isDefault).toBe(true);
|
|
122
|
+
expect(flag.value).toBe(undefined);
|
|
123
|
+
expect(flag.enabled).toBe(false);
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
test('test_get_identity_flags_multivariate_value_with_local_evaluation_enabled', async () => {
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
fetch.mockResolvedValue(new Response(environmentJSON));
|
|
128
|
+
const identifier = 'identifier';
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
const flg = flagsmith({
|
|
131
|
+
environmentKey: 'ser.key',
|
|
132
|
+
enableLocalEvaluation: true
|
|
133
|
+
});
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
const identityFlags = await flg.getIdentityFlags(identifier);
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
expect(identityFlags.getFeatureValue('mv_feature')).toBe('bar');
|
|
138
|
+
expect(identityFlags.isFeatureEnabled('mv_feature')).toBe(false);
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
-
|
|
142
141
|
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
|
-
|
|
142
|
+
fetch.mockResolvedValue(new Response(transientIdentityJSON));
|
|
143
|
+
const identifier = 'transient_identifier';
|
|
144
|
+
const traits = { some_trait: 'some_value' };
|
|
145
|
+
const traitsInRequest = [{ trait_key: Object.keys(traits)[0], trait_value: traits.some_trait }];
|
|
146
|
+
const transient = true;
|
|
147
|
+
const flg = flagsmith();
|
|
148
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits, transient)).allFlags();
|
|
149
|
+
|
|
150
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
151
|
+
`https://edge.api.flagsmith.com/api/v1/identities/`,
|
|
152
|
+
expect.objectContaining({
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: {
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
'X-Environment-Key': 'sometestfakekey',
|
|
157
|
+
'User-Agent': getUserAgent()
|
|
158
|
+
},
|
|
159
|
+
body: JSON.stringify({ identifier, traits: traitsInRequest, transient })
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(identityFlags[0].enabled).toBe(false);
|
|
164
|
+
expect(identityFlags[0].value).toBe('some-transient-identity-value');
|
|
165
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
163
166
|
});
|
|
164
167
|
|
|
165
|
-
|
|
166
168
|
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
|
-
|
|
169
|
+
fetch.mockResolvedValue(new Response(identityWithTransientTraitsJSON));
|
|
170
|
+
const identifier = 'transient_trait_identifier';
|
|
171
|
+
const traits = {
|
|
172
|
+
some_trait: 'some_value',
|
|
173
|
+
another_trait: { value: 'another_value', transient: true },
|
|
174
|
+
explicitly_non_transient_trait: { value: 'non_transient_value', transient: false }
|
|
175
|
+
};
|
|
176
|
+
const traitsInRequest = [
|
|
177
|
+
{
|
|
178
|
+
trait_key: Object.keys(traits)[0],
|
|
179
|
+
trait_value: traits.some_trait
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
trait_key: Object.keys(traits)[1],
|
|
183
|
+
trait_value: traits.another_trait.value,
|
|
184
|
+
transient: true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
trait_key: Object.keys(traits)[2],
|
|
188
|
+
trait_value: traits.explicitly_non_transient_trait.value,
|
|
189
|
+
transient: false
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
const flg = flagsmith();
|
|
193
|
+
|
|
194
|
+
const identityFlags = (await flg.getIdentityFlags(identifier, traits)).allFlags();
|
|
195
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
196
|
+
`https://edge.api.flagsmith.com/api/v1/identities/`,
|
|
197
|
+
expect.objectContaining({
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: {
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
'X-Environment-Key': 'sometestfakekey',
|
|
202
|
+
'User-Agent': getUserAgent()
|
|
203
|
+
},
|
|
204
|
+
body: JSON.stringify({ identifier, traits: traitsInRequest })
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
expect(identityFlags[0].enabled).toBe(true);
|
|
208
|
+
expect(identityFlags[0].value).toBe('some-identity-with-transient-trait-value');
|
|
209
|
+
expect(identityFlags[0].featureName).toBe('some_feature');
|
|
204
210
|
});
|
|
205
211
|
|
|
206
212
|
test('getIdentityFlags fails if API call failed and no default flag handler was provided', async () => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
})
|
|
213
|
+
const flg = flagsmith({
|
|
214
|
+
fetch: badFetch
|
|
215
|
+
});
|
|
216
|
+
await expect(flg.getIdentityFlags('user')).rejects.toThrow(
|
|
217
|
+
'getIdentityFlags failed and no default flag handler was provided'
|
|
218
|
+
);
|
|
219
|
+
});
|