@depup/launchdarkly-node-server-sdk 7.0.4-depup.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/.babelrc +16 -0
- package/.circleci/config.yml +89 -0
- package/.eslintignore +5 -0
- package/.eslintrc.yaml +114 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/pull_request_template.md +21 -0
- package/.github/workflows/stale.yml +8 -0
- package/.hound.yml +33 -0
- package/.ldrelease/config.yml +28 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +603 -0
- package/CODEOWNERS +2 -0
- package/CONTRIBUTING.md +55 -0
- package/LICENSE.txt +13 -0
- package/README.md +36 -0
- package/SECURITY.md +5 -0
- package/attribute_reference.js +217 -0
- package/big_segments.js +117 -0
- package/caching_store_wrapper.js +240 -0
- package/changes.json +30 -0
- package/configuration.js +235 -0
- package/context.js +98 -0
- package/context_filter.js +137 -0
- package/contract-tests/README.md +7 -0
- package/contract-tests/index.js +109 -0
- package/contract-tests/log.js +23 -0
- package/contract-tests/package.json +15 -0
- package/contract-tests/sdkClientEntity.js +110 -0
- package/contract-tests/testharness-suppressions.txt +2 -0
- package/diagnostic_events.js +151 -0
- package/docs/typedoc.js +10 -0
- package/errors.js +26 -0
- package/evaluator.js +822 -0
- package/event_factory.js +121 -0
- package/event_processor.js +320 -0
- package/event_summarizer.js +101 -0
- package/feature_store.js +120 -0
- package/feature_store_event_wrapper.js +258 -0
- package/file_data_source.js +192 -0
- package/flags_state.js +46 -0
- package/index.d.ts +2426 -0
- package/index.js +452 -0
- package/integrations.js +7 -0
- package/interfaces.js +2 -0
- package/loggers.js +125 -0
- package/messages.js +31 -0
- package/operators.js +106 -0
- package/package.json +105 -0
- package/polling.js +70 -0
- package/requestor.js +62 -0
- package/scripts/better-audit.sh +76 -0
- package/sharedtest/big_segment_store_tests.js +86 -0
- package/sharedtest/feature_store_tests.js +177 -0
- package/sharedtest/persistent_feature_store_tests.js +183 -0
- package/sharedtest/store_tests.js +7 -0
- package/streaming.js +179 -0
- package/test/LDClient-big-segments-test.js +92 -0
- package/test/LDClient-end-to-end-test.js +218 -0
- package/test/LDClient-evaluation-all-flags-test.js +226 -0
- package/test/LDClient-evaluation-test.js +204 -0
- package/test/LDClient-events-test.js +502 -0
- package/test/LDClient-listeners-test.js +180 -0
- package/test/LDClient-test.js +96 -0
- package/test/LDClient-tls-test.js +110 -0
- package/test/attribute_reference-test.js +494 -0
- package/test/big_segments-test.js +182 -0
- package/test/caching_store_wrapper-test.js +434 -0
- package/test/configuration-test.js +249 -0
- package/test/context-test.js +93 -0
- package/test/context_filter-test.js +424 -0
- package/test/diagnostic_events-test.js +152 -0
- package/test/evaluator-big-segments-test.js +301 -0
- package/test/evaluator-bucketing-test.js +333 -0
- package/test/evaluator-clause-test.js +277 -0
- package/test/evaluator-flag-test.js +452 -0
- package/test/evaluator-pre-conditions-test.js +105 -0
- package/test/evaluator-rule-test.js +131 -0
- package/test/evaluator-segment-match-test.js +310 -0
- package/test/evaluator_helpers.js +106 -0
- package/test/event_processor-test.js +680 -0
- package/test/event_summarizer-test.js +146 -0
- package/test/feature_store-test.js +42 -0
- package/test/feature_store_event_wrapper-test.js +182 -0
- package/test/feature_store_test_base.js +60 -0
- package/test/file_data_source-test.js +255 -0
- package/test/loggers-test.js +126 -0
- package/test/operators-test.js +102 -0
- package/test/polling-test.js +158 -0
- package/test/requestor-test.js +60 -0
- package/test/store_tests_big_segments-test.js +61 -0
- package/test/streaming-test.js +323 -0
- package/test/stubs.js +107 -0
- package/test/test_data-test.js +341 -0
- package/test/update_queue-test.js +61 -0
- package/test-types.ts +210 -0
- package/test_data.js +323 -0
- package/tsconfig.json +14 -0
- package/update_queue.js +28 -0
- package/utils/__tests__/httpUtils-test.js +39 -0
- package/utils/__tests__/wrapPromiseCallback-test.js +33 -0
- package/utils/asyncUtils.js +32 -0
- package/utils/httpUtils.js +105 -0
- package/utils/stringifyAttrs.js +14 -0
- package/utils/wrapPromiseCallback.js +36 -0
- package/versioned_data_kind.js +34 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
const { TestData } = require('../integrations');
|
|
2
|
+
const stubs = require('./stubs');
|
|
3
|
+
|
|
4
|
+
describe('LDClient.allFlagsState', () => {
|
|
5
|
+
const defaultUser = { key: 'user' };
|
|
6
|
+
|
|
7
|
+
it('captures flag state', async () => {
|
|
8
|
+
const value1 = 'value1', value2 = 'value2', value3 = 'value3';
|
|
9
|
+
const flag1 = {
|
|
10
|
+
key: 'key1',
|
|
11
|
+
version: 100,
|
|
12
|
+
on: false,
|
|
13
|
+
offVariation: 0,
|
|
14
|
+
variations: [ value1 ]
|
|
15
|
+
};
|
|
16
|
+
const flag2 = {
|
|
17
|
+
key: 'key2',
|
|
18
|
+
version: 200,
|
|
19
|
+
on: false,
|
|
20
|
+
offVariation: 1,
|
|
21
|
+
variations: [ 'x', value2 ],
|
|
22
|
+
trackEvents: true,
|
|
23
|
+
debugEventsUntilDate: 1000
|
|
24
|
+
};
|
|
25
|
+
// flag3 has an experiment (evaluation is a fallthrough and TrackEventsFallthrough is on)
|
|
26
|
+
const flag3 = {
|
|
27
|
+
key: 'key3',
|
|
28
|
+
version: 300,
|
|
29
|
+
on: true,
|
|
30
|
+
fallthrough: { variation: 1 },
|
|
31
|
+
variations: [ 'x', value3 ],
|
|
32
|
+
trackEvents: false,
|
|
33
|
+
trackEventsFallthrough: true
|
|
34
|
+
};
|
|
35
|
+
const td = TestData();
|
|
36
|
+
td.usePreconfiguredFlag(flag1);
|
|
37
|
+
td.usePreconfiguredFlag(flag2);
|
|
38
|
+
td.usePreconfiguredFlag(flag3);
|
|
39
|
+
|
|
40
|
+
const client = stubs.createClient({ updateProcessor: td });
|
|
41
|
+
await client.waitForInitialization();
|
|
42
|
+
const state = await client.allFlagsState(defaultUser);
|
|
43
|
+
expect(state.valid).toEqual(true);
|
|
44
|
+
expect(state.allValues()).toEqual({ [flag1.key]: value1, [flag2.key]: value2, [flag3.key]: value3 });
|
|
45
|
+
expect(state.getFlagValue(flag1.key)).toEqual(value1);
|
|
46
|
+
expect(state.toJSON()).toEqual({
|
|
47
|
+
[flag1.key]: value1,
|
|
48
|
+
[flag2.key]: value2,
|
|
49
|
+
[flag3.key]: value3,
|
|
50
|
+
$flagsState: {
|
|
51
|
+
[flag1.key]: {
|
|
52
|
+
version: flag1.version,
|
|
53
|
+
variation: 0,
|
|
54
|
+
},
|
|
55
|
+
[flag2.key]: {
|
|
56
|
+
version: flag2.version,
|
|
57
|
+
variation: 1,
|
|
58
|
+
trackEvents: true,
|
|
59
|
+
debugEventsUntilDate: 1000
|
|
60
|
+
},
|
|
61
|
+
[flag3.key]: {
|
|
62
|
+
version: flag3.version,
|
|
63
|
+
variation: 1,
|
|
64
|
+
reason: { kind: 'FALLTHROUGH' },
|
|
65
|
+
trackEvents: true,
|
|
66
|
+
trackReason: true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
$valid: true
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('can filter for only client-side flags', async () => {
|
|
74
|
+
const td = TestData();
|
|
75
|
+
td.usePreconfiguredFlag({ key: 'server-side-1', on: false, offVariation: 0, variations: ['a'], clientSide: false });
|
|
76
|
+
td.usePreconfiguredFlag({ key: 'server-side-2', on: false, offVariation: 0, variations: ['b'], clientSide: false });
|
|
77
|
+
td.usePreconfiguredFlag({ key: 'client-side-1', on: false, offVariation: 0, variations: ['value1'], clientSide: true });
|
|
78
|
+
td.usePreconfiguredFlag({ key: 'client-side-2', on: false, offVariation: 0, variations: ['value2'], clientSide: true });
|
|
79
|
+
const client = stubs.createClient({ updateProcessor: td });
|
|
80
|
+
await client.waitForInitialization();
|
|
81
|
+
const state = await client.allFlagsState(defaultUser, { clientSideOnly: true });
|
|
82
|
+
expect(state.valid).toEqual(true);
|
|
83
|
+
expect(state.allValues()).toEqual({ 'client-side-1': 'value1', 'client-side-2': 'value2' });
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('can include reasons', async () => {
|
|
87
|
+
const td = TestData();
|
|
88
|
+
td.usePreconfiguredFlag({
|
|
89
|
+
key: 'feature',
|
|
90
|
+
version: 100,
|
|
91
|
+
offVariation: 1,
|
|
92
|
+
variations: ['a', 'b'],
|
|
93
|
+
trackEvents: true,
|
|
94
|
+
debugEventsUntilDate: 1000
|
|
95
|
+
});
|
|
96
|
+
const client = stubs.createClient({ updateProcessor: td });
|
|
97
|
+
await client.waitForInitialization();
|
|
98
|
+
const state = await client.allFlagsState(defaultUser, { withReasons: true });
|
|
99
|
+
expect(state.valid).toEqual(true);
|
|
100
|
+
expect(state.allValues()).toEqual({feature: 'b'});
|
|
101
|
+
expect(state.getFlagValue('feature')).toEqual('b');
|
|
102
|
+
expect(state.toJSON()).toEqual({
|
|
103
|
+
feature: 'b',
|
|
104
|
+
$flagsState: {
|
|
105
|
+
feature: {
|
|
106
|
+
version: 100,
|
|
107
|
+
variation: 1,
|
|
108
|
+
reason: { kind: 'OFF' },
|
|
109
|
+
trackEvents: true,
|
|
110
|
+
debugEventsUntilDate: 1000
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
$valid: true
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('can omit details for untracked flags', async () => {
|
|
118
|
+
const flag1 = {
|
|
119
|
+
key: 'flag1',
|
|
120
|
+
version: 100,
|
|
121
|
+
offVariation: 0,
|
|
122
|
+
variations: ['value1']
|
|
123
|
+
};
|
|
124
|
+
const flag2 = {
|
|
125
|
+
key: 'flag2',
|
|
126
|
+
version: 200,
|
|
127
|
+
offVariation: 0,
|
|
128
|
+
variations: ['value2'],
|
|
129
|
+
trackEvents: true
|
|
130
|
+
};
|
|
131
|
+
const flag3 = {
|
|
132
|
+
key: 'flag3',
|
|
133
|
+
version: 300,
|
|
134
|
+
offVariation: 0,
|
|
135
|
+
variations: ['value3'],
|
|
136
|
+
debugEventsUntilDate: 1000
|
|
137
|
+
};
|
|
138
|
+
const td = TestData();
|
|
139
|
+
td.usePreconfiguredFlag(flag1);
|
|
140
|
+
td.usePreconfiguredFlag(flag2);
|
|
141
|
+
td.usePreconfiguredFlag(flag3);
|
|
142
|
+
|
|
143
|
+
const client = stubs.createClient({ updateProcessor: td });
|
|
144
|
+
await client.waitForInitialization();
|
|
145
|
+
const state = await client.allFlagsState(defaultUser, { withReasons: true, detailsOnlyForTrackedFlags: true });
|
|
146
|
+
expect(state.valid).toEqual(true);
|
|
147
|
+
expect(state.allValues()).toEqual({flag1: 'value1', flag2: 'value2', flag3: 'value3'});
|
|
148
|
+
expect(state.getFlagValue('flag1')).toEqual('value1');
|
|
149
|
+
expect(state.toJSON()).toEqual({
|
|
150
|
+
flag1: 'value1',
|
|
151
|
+
flag2: 'value2',
|
|
152
|
+
flag3: 'value3',
|
|
153
|
+
$flagsState: {
|
|
154
|
+
flag1: {
|
|
155
|
+
variation: 0
|
|
156
|
+
},
|
|
157
|
+
flag2: {
|
|
158
|
+
version: 200,
|
|
159
|
+
variation: 0,
|
|
160
|
+
reason: { kind: 'OFF' },
|
|
161
|
+
trackEvents: true
|
|
162
|
+
},
|
|
163
|
+
flag3: {
|
|
164
|
+
version: 300,
|
|
165
|
+
variation: 0,
|
|
166
|
+
reason: { kind: 'OFF' },
|
|
167
|
+
debugEventsUntilDate: 1000
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
$valid: true
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('returns empty state in offline mode and logs a message', async () => {
|
|
175
|
+
const flag = {
|
|
176
|
+
key: 'flagkey',
|
|
177
|
+
on: false,
|
|
178
|
+
offVariation: null
|
|
179
|
+
};
|
|
180
|
+
const td = TestData();
|
|
181
|
+
td.usePreconfiguredFlag(flag);
|
|
182
|
+
const logger = stubs.stubLogger();
|
|
183
|
+
const client = stubs.createClient({ offline: true, logger: logger, updateProcessor: td });
|
|
184
|
+
await client.waitForInitialization();
|
|
185
|
+
const state = await client.allFlagsState(defaultUser);
|
|
186
|
+
expect(state.valid).toEqual(false);
|
|
187
|
+
expect(state.allValues()).toEqual({});
|
|
188
|
+
expect(logger.info).toHaveBeenCalledTimes(1);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('does not overflow the call stack when evaluating a huge number of flags', async () => {
|
|
192
|
+
const flagCount = 5000;
|
|
193
|
+
const td = TestData();
|
|
194
|
+
for (let i = 0; i < flagCount; i++) {
|
|
195
|
+
td.usePreconfiguredFlag({
|
|
196
|
+
key: 'feature' + i,
|
|
197
|
+
version: 1,
|
|
198
|
+
on: false
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const client = stubs.createClient({ updateProcessor: td });
|
|
202
|
+
await client.waitForInitialization();
|
|
203
|
+
const state = await client.allFlagsState(defaultUser);
|
|
204
|
+
expect(Object.keys(state.allValues()).length).toEqual(flagCount);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('can use a callback instead of a Promise', done => {
|
|
208
|
+
const client = stubs.createClient({ offline: true }, { });
|
|
209
|
+
client.on('ready', () => {
|
|
210
|
+
client.allFlagsState(defaultUser, {}, (err, state) => {
|
|
211
|
+
expect(state.valid).toEqual(false);
|
|
212
|
+
done();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('can omit options parameter with callback', done => {
|
|
218
|
+
const client = stubs.createClient({ offline: true }, { });
|
|
219
|
+
client.on('ready', () => {
|
|
220
|
+
client.allFlagsState(defaultUser, (err, state) => {
|
|
221
|
+
expect(state.valid).toEqual(false);
|
|
222
|
+
done();
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
const { TestData } = require('../integrations');
|
|
2
|
+
const stubs = require('./stubs');
|
|
3
|
+
|
|
4
|
+
describe('LDClient', () => {
|
|
5
|
+
|
|
6
|
+
var defaultUser = { key: 'user' };
|
|
7
|
+
|
|
8
|
+
describe('variation()', () => {
|
|
9
|
+
it('evaluates an existing flag', async () => {
|
|
10
|
+
const td = TestData();
|
|
11
|
+
td.update(td.flag('flagkey').on(true).variations('a', 'b').fallthroughVariation(1));
|
|
12
|
+
var client = stubs.createClient({ updateProcessor: td });
|
|
13
|
+
await client.waitForInitialization();
|
|
14
|
+
var result = await client.variation('flagkey', defaultUser, 'c');
|
|
15
|
+
expect(result).toEqual('b');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns default for unknown flag', async () => {
|
|
19
|
+
var client = stubs.createClient({}, {});
|
|
20
|
+
await client.waitForInitialization();
|
|
21
|
+
var result = await client.variation('flagkey', defaultUser, 'default');
|
|
22
|
+
expect(result).toEqual('default');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('returns default if client is offline', async () => {
|
|
26
|
+
const td = TestData();
|
|
27
|
+
td.update(td.flag('flagkey').variations('value').variationForAll(0));
|
|
28
|
+
var logger = stubs.stubLogger();
|
|
29
|
+
var client = stubs.createClient({ offline: true, updateProcessor: td, logger });
|
|
30
|
+
await client.waitForInitialization();
|
|
31
|
+
var result = await client.variation('flagkey', defaultUser, 'default');
|
|
32
|
+
expect(result).toEqual('default');
|
|
33
|
+
expect(logger.info).toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('returns default if client and store are not initialized', async () => {
|
|
37
|
+
// Can't use TestData to set up this condition, because it always initializes successfully
|
|
38
|
+
const flag = {
|
|
39
|
+
key: 'flagkey',
|
|
40
|
+
version: 1,
|
|
41
|
+
on: false,
|
|
42
|
+
offVariation: 0,
|
|
43
|
+
variations: ['value']
|
|
44
|
+
};
|
|
45
|
+
const featureStore = stubs.uninitializedStoreWithFlags(flag);
|
|
46
|
+
var client = stubs.createClient({ featureStore });
|
|
47
|
+
var result = await client.variation('flagkey', defaultUser, 'default');
|
|
48
|
+
expect(result).toEqual('default');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('returns value from store if store is initialized but client is not', async () => {
|
|
52
|
+
// Can't use TestData to set up this condition, because it always initializes successfully
|
|
53
|
+
var featureStore = stubs.initializedStoreWithFlags({
|
|
54
|
+
key: 'flagkey',
|
|
55
|
+
version: 1,
|
|
56
|
+
on: false,
|
|
57
|
+
offVariation: 0,
|
|
58
|
+
variations: ['value']
|
|
59
|
+
});
|
|
60
|
+
var logger = stubs.stubLogger();
|
|
61
|
+
var updateProcessor = stubs.stubUpdateProcessor();
|
|
62
|
+
updateProcessor.shouldInitialize = false;
|
|
63
|
+
var client = stubs.createClient({ updateProcessor, featureStore, logger });
|
|
64
|
+
var result = await client.variation('flagkey', defaultUser, 'default');
|
|
65
|
+
expect(result).toEqual('value');
|
|
66
|
+
expect(logger.warn).toHaveBeenCalled();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns default if flag key is not specified', async () => {
|
|
70
|
+
var client = stubs.createClient({}, {});
|
|
71
|
+
await client.waitForInitialization();
|
|
72
|
+
var result = await client.variation(null, defaultUser, 'default');
|
|
73
|
+
expect(result).toEqual('default');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('returns default for flag that evaluates to null', async () => {
|
|
77
|
+
const td = TestData();
|
|
78
|
+
td.usePreconfiguredFlag({ // TestData normally won't construct a flag with offVariation: null
|
|
79
|
+
key: 'flagkey',
|
|
80
|
+
on: false,
|
|
81
|
+
offVariation: null
|
|
82
|
+
});
|
|
83
|
+
var client = stubs.createClient({ updateProcessor: td });
|
|
84
|
+
await client.waitForInitialization();
|
|
85
|
+
var result = await client.variation('flagkey', defaultUser, 'default');
|
|
86
|
+
expect(result).toEqual('default');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('can use a callback instead of a Promise', done => {
|
|
90
|
+
var client = stubs.createClient({}, {});
|
|
91
|
+
client.on('ready', () => {
|
|
92
|
+
client.variation('flagkey', defaultUser, 'default', (err, result) => {
|
|
93
|
+
expect(err).toBeNull();
|
|
94
|
+
expect(result).toEqual('default');
|
|
95
|
+
done();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('variationDetail()', () => {
|
|
102
|
+
it('evaluates an existing flag', async () => {
|
|
103
|
+
const td = TestData();
|
|
104
|
+
td.update(td.flag('flagkey').on(true).variations('a', 'b').fallthroughVariation(1));
|
|
105
|
+
var client = stubs.createClient({ updateProcessor: td });
|
|
106
|
+
await client.waitForInitialization();
|
|
107
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'c');
|
|
108
|
+
expect(result).toMatchObject({ value: 'b', variationIndex: 1, reason: { kind: 'FALLTHROUGH' } });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns default for unknown flag', async () => {
|
|
112
|
+
var client = stubs.createClient({}, { });
|
|
113
|
+
await client.waitForInitialization();
|
|
114
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'default');
|
|
115
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null,
|
|
116
|
+
reason: { kind: 'ERROR', errorKind: 'FLAG_NOT_FOUND' } });
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('returns default if client is offline', async () => {
|
|
120
|
+
// Can't use TestData to set up this condition, because the data source isn't used in offline mode
|
|
121
|
+
var flag = {
|
|
122
|
+
key: 'flagkey',
|
|
123
|
+
version: 1,
|
|
124
|
+
on: false,
|
|
125
|
+
offVariation: 0,
|
|
126
|
+
variations: ['value']
|
|
127
|
+
};
|
|
128
|
+
var logger = stubs.stubLogger();
|
|
129
|
+
var client = stubs.createClient({ offline: true, logger: logger }, { flagkey: flag });
|
|
130
|
+
await client.waitForInitialization();
|
|
131
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'default');
|
|
132
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null,
|
|
133
|
+
reason: { kind: 'ERROR', errorKind: 'CLIENT_NOT_READY' }});
|
|
134
|
+
expect(logger.info).toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('returns default if client and store are not initialized', async () => {
|
|
138
|
+
// Can't use TestData to set up this condition, because it always initializes successfully
|
|
139
|
+
var flag = {
|
|
140
|
+
key: 'flagkey',
|
|
141
|
+
version: 1,
|
|
142
|
+
on: false,
|
|
143
|
+
offVariation: 0,
|
|
144
|
+
variations: ['value']
|
|
145
|
+
};
|
|
146
|
+
const featureStore = stubs.uninitializedStoreWithFlags(flag);
|
|
147
|
+
var client = stubs.createClient({ featureStore });
|
|
148
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'default');
|
|
149
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null,
|
|
150
|
+
reason: { kind: 'ERROR', errorKind: 'CLIENT_NOT_READY' } });
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('returns value from store if store is initialized but client is not', async () => {
|
|
154
|
+
// Can't use TestData to set up this condition, because it always initializes successfully
|
|
155
|
+
var featureStore = stubs.initializedStoreWithFlags({
|
|
156
|
+
key: 'flagkey',
|
|
157
|
+
version: 1,
|
|
158
|
+
on: false,
|
|
159
|
+
offVariation: 0,
|
|
160
|
+
variations: ['value']
|
|
161
|
+
});
|
|
162
|
+
var logger = stubs.stubLogger();
|
|
163
|
+
var updateProcessor = stubs.stubUpdateProcessor();
|
|
164
|
+
updateProcessor.shouldInitialize = false;
|
|
165
|
+
var client = stubs.createClient({ updateProcessor, featureStore, logger });
|
|
166
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'default');
|
|
167
|
+
expect(result).toMatchObject({ value: 'value', variationIndex: 0, reason: { kind: 'OFF' }})
|
|
168
|
+
expect(logger.warn).toHaveBeenCalled();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('returns default if flag key is not specified', async () => {
|
|
172
|
+
var client = stubs.createClient({}, { });
|
|
173
|
+
await client.waitForInitialization();
|
|
174
|
+
var result = await client.variationDetail(null, defaultUser, 'default');
|
|
175
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null,
|
|
176
|
+
reason: { kind: 'ERROR', errorKind: 'FLAG_NOT_FOUND' } });
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('returns default for flag that evaluates to null', async () => {
|
|
180
|
+
const td = TestData();
|
|
181
|
+
td.usePreconfiguredFlag({ // TestData normally won't construct a flag with offVariation: null
|
|
182
|
+
key: 'flagkey',
|
|
183
|
+
on: false,
|
|
184
|
+
offVariation: null
|
|
185
|
+
});
|
|
186
|
+
var client = stubs.createClient({ updateProcessor: td });
|
|
187
|
+
await client.waitForInitialization();
|
|
188
|
+
var result = await client.variationDetail('flagkey', defaultUser, 'default');
|
|
189
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null, reason: { kind: 'OFF' } });
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('can use a callback instead of a Promise', done => {
|
|
193
|
+
var client = stubs.createClient({}, {});
|
|
194
|
+
client.on('ready', () => {
|
|
195
|
+
client.variationDetail('flagkey', defaultUser, 'default', (err, result) => {
|
|
196
|
+
expect(err).toBeNull();
|
|
197
|
+
expect(result).toMatchObject({ value: 'default', variationIndex: null,
|
|
198
|
+
reason: { kind: 'ERROR', errorKind: 'FLAG_NOT_FOUND' } });
|
|
199
|
+
done();
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|