launchdarkly-js-sdk-common 4.0.0 → 4.0.1
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/.circleci/config.yml +22 -0
- package/.eslintignore +4 -0
- package/.eslintrc.yaml +104 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/pull_request_template.md +21 -0
- package/.ldrelease/config.yml +24 -0
- package/.prettierignore +1 -0
- package/.prettierrc +5 -0
- package/CHANGELOG.md +4 -0
- package/CONTRIBUTING.md +45 -0
- package/babel.config.js +18 -0
- package/docs/typedoc.js +11 -0
- package/jest.config.js +15 -0
- package/package.json +3 -29
- package/scripts/better-audit.sh +76 -0
- package/src/EventEmitter.js +60 -0
- package/src/EventProcessor.js +175 -0
- package/src/EventSender.js +87 -0
- package/src/EventSummarizer.js +84 -0
- package/src/Identity.js +26 -0
- package/src/InitializationState.js +83 -0
- package/src/PersistentFlagStore.js +50 -0
- package/src/PersistentStorage.js +81 -0
- package/src/Requestor.js +111 -0
- package/src/Stream.js +154 -0
- package/src/UserFilter.js +75 -0
- package/src/UserValidator.js +56 -0
- package/src/__tests__/.eslintrc.yaml +7 -0
- package/src/__tests__/EventProcessor-test.js +559 -0
- package/src/__tests__/EventSender-test.js +252 -0
- package/src/__tests__/EventSource-mock.js +61 -0
- package/src/__tests__/EventSummarizer-test.js +103 -0
- package/src/__tests__/LDClient-events-test.js +757 -0
- package/src/__tests__/LDClient-localstorage-test.js +179 -0
- package/src/__tests__/LDClient-streaming-test.js +683 -0
- package/src/__tests__/LDClient-test.js +761 -0
- package/src/__tests__/PersistentFlagStore-test.js +111 -0
- package/src/__tests__/Requestor-test.js +362 -0
- package/src/__tests__/Stream-test.js +299 -0
- package/src/__tests__/UserFilter-test.js +93 -0
- package/src/__tests__/UserValidator-test.js +57 -0
- package/src/__tests__/configuration-test.js +217 -0
- package/src/__tests__/diagnosticEvents-test.js +449 -0
- package/src/__tests__/loggers-test.js +149 -0
- package/src/__tests__/mockHttp.js +122 -0
- package/src/__tests__/promiseCoalescer-test.js +128 -0
- package/src/__tests__/stubPlatform.js +148 -0
- package/src/__tests__/testUtils.js +77 -0
- package/src/__tests__/utils-test.js +148 -0
- package/src/configuration.js +151 -0
- package/src/diagnosticEvents.js +269 -0
- package/src/errors.js +37 -0
- package/src/index.js +772 -0
- package/src/jest.setup.js +1 -0
- package/src/loggers.js +93 -0
- package/src/messages.js +217 -0
- package/src/promiseCoalescer.js +52 -0
- package/src/utils.js +214 -0
- package/test-types.ts +96 -0
- package/tsconfig.json +13 -0
- package/dist/ldclient-common.cjs.js +0 -2
- package/dist/ldclient-common.cjs.js.map +0 -1
- package/dist/ldclient-common.es.js +0 -2
- package/dist/ldclient-common.es.js.map +0 -1
- package/dist/ldclient-common.min.js +0 -2
- package/dist/ldclient-common.min.js.map +0 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as messages from '../messages';
|
|
2
|
+
import * as utils from '../utils';
|
|
3
|
+
|
|
4
|
+
import { sleepAsync, withCloseable } from 'launchdarkly-js-test-helpers';
|
|
5
|
+
|
|
6
|
+
import { respond, respondJson } from './mockHttp';
|
|
7
|
+
import * as stubPlatform from './stubPlatform';
|
|
8
|
+
|
|
9
|
+
// These tests cover the "bootstrap: 'localstorage'" mode. The actual implementation of local storage
|
|
10
|
+
// is provided by the platform-specific SDKs; we use a mock implementation here.
|
|
11
|
+
|
|
12
|
+
describe('LDClient local storage', () => {
|
|
13
|
+
const envName = 'UNKNOWN_ENVIRONMENT_ID';
|
|
14
|
+
const user = { key: 'user' };
|
|
15
|
+
const lsKey = 'ld:' + envName + ':' + utils.btoa(JSON.stringify(user));
|
|
16
|
+
let platform;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
platform = stubPlatform.defaults();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
async function withServer(asyncCallback) {
|
|
23
|
+
const server = platform.testing.http.newServer();
|
|
24
|
+
server.byDefault(respondJson({}));
|
|
25
|
+
return await withCloseable(server, asyncCallback);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function withClient(user, extraConfig, asyncCallback) {
|
|
29
|
+
// We specify bootstrap: 'localstorage' for all tests in this file
|
|
30
|
+
const config = { baseUrl: 'shouldnt-use-this', bootstrap: 'localstorage', sendEvents: false, ...extraConfig };
|
|
31
|
+
const client = platform.testing.makeClient(envName, user, config);
|
|
32
|
+
return await withCloseable(client, asyncCallback);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('bootstrapping from local storage', () => {
|
|
36
|
+
it('does not try to use local storage if the platform says it is unavailable', async () => {
|
|
37
|
+
platform.localStorage = null;
|
|
38
|
+
|
|
39
|
+
await withServer(async server => {
|
|
40
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
41
|
+
await client.waitForInitialization();
|
|
42
|
+
|
|
43
|
+
// should see a flag request to the server right away, as if bootstrap was not specified
|
|
44
|
+
expect(server.requests.length()).toEqual(1);
|
|
45
|
+
|
|
46
|
+
expect(platform.testing.logger.output.warn).toEqual([messages.localStorageUnavailable()]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('uses cached flags if available and requests flags from server after ready', async () => {
|
|
52
|
+
const json = '{"flag-key": 1}';
|
|
53
|
+
platform.testing.setLocalStorageImmediately(lsKey, json);
|
|
54
|
+
|
|
55
|
+
await withServer(async server => {
|
|
56
|
+
// This no-op request handler means that the flags request will simply hang with no
|
|
57
|
+
// response, so we can be sure that we're seeing only the initial flags from local storage.
|
|
58
|
+
server.byDefault(() => {});
|
|
59
|
+
|
|
60
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
61
|
+
await client.waitForInitialization();
|
|
62
|
+
|
|
63
|
+
expect(client.variation('flag-key')).toEqual(1);
|
|
64
|
+
|
|
65
|
+
await sleepAsync(0); // allow any pending async tasks to complete
|
|
66
|
+
|
|
67
|
+
expect(server.requests.length()).toEqual(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('starts with empty flags and requests them from server if there are no cached flags', async () => {
|
|
73
|
+
const flags = { 'flag-key': { value: 1 } };
|
|
74
|
+
|
|
75
|
+
await withServer(async server => {
|
|
76
|
+
server.byDefault(respondJson(flags));
|
|
77
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
78
|
+
// don't wait for ready event - verifying that variation() doesn't throw an error if called before ready
|
|
79
|
+
expect(client.variation('flag-key', 0)).toEqual(0);
|
|
80
|
+
|
|
81
|
+
// verify that the flags get requested from LD
|
|
82
|
+
await client.waitForInitialization();
|
|
83
|
+
expect(client.variation('flag-key')).toEqual(1);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should handle localStorage.get returning an error', async () => {
|
|
89
|
+
const myError = new Error('deliberate error');
|
|
90
|
+
platform.localStorage.get = () => Promise.reject(myError);
|
|
91
|
+
const flags = { 'enable-foo': { value: true } };
|
|
92
|
+
|
|
93
|
+
await withServer(async server => {
|
|
94
|
+
server.byDefault(respondJson(flags));
|
|
95
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
96
|
+
await client.waitForInitialization();
|
|
97
|
+
expect(platform.testing.logger.output.warn).toEqual([messages.localStorageUnavailable(myError)]);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle localStorage.set returning an error', async () => {
|
|
103
|
+
const myError = new Error('deliberate error');
|
|
104
|
+
platform.localStorage.set = () => Promise.reject(myError);
|
|
105
|
+
const flags = { 'enable-foo': { value: true } };
|
|
106
|
+
|
|
107
|
+
await withServer(async server => {
|
|
108
|
+
server.byDefault(respondJson(flags));
|
|
109
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
110
|
+
await client.waitForInitialization();
|
|
111
|
+
|
|
112
|
+
await sleepAsync(0); // allow any pending async tasks to complete
|
|
113
|
+
|
|
114
|
+
expect(platform.testing.logger.output.warn).toEqual([messages.localStorageUnavailable(myError)]);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should not update cached settings if there was an error fetching flags', async () => {
|
|
120
|
+
const json = '{"enable-foo": true}';
|
|
121
|
+
platform.testing.setLocalStorageImmediately(lsKey, json);
|
|
122
|
+
|
|
123
|
+
await withServer(async server => {
|
|
124
|
+
server.byDefault(respond(503));
|
|
125
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
126
|
+
await client.waitForInitialization();
|
|
127
|
+
|
|
128
|
+
await sleepAsync(0); // allow any pending async tasks to complete
|
|
129
|
+
|
|
130
|
+
const value = platform.testing.getLocalStorageImmediately(lsKey);
|
|
131
|
+
expect(value).toEqual(json);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should use hash as localStorage key when secure mode is enabled', async () => {
|
|
137
|
+
const hash = 'totallyLegitHash';
|
|
138
|
+
const lsKeyHash = 'ld:UNKNOWN_ENVIRONMENT_ID:' + hash;
|
|
139
|
+
const flags = { 'enable-foo': { value: true } };
|
|
140
|
+
|
|
141
|
+
await withServer(async server => {
|
|
142
|
+
server.byDefault(respondJson(flags));
|
|
143
|
+
await withClient(user, { baseUrl: server.url, hash }, async client => {
|
|
144
|
+
await client.waitForInitialization();
|
|
145
|
+
const value = platform.testing.getLocalStorageImmediately(lsKeyHash);
|
|
146
|
+
expect(JSON.parse(value)).toEqual({
|
|
147
|
+
$schema: 1,
|
|
148
|
+
'enable-foo': { value: true },
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should clear localStorage when user context is changed', async () => {
|
|
155
|
+
const lsKey2 = 'ld:UNKNOWN_ENVIRONMENT_ID:' + utils.btoa('{"key":"user2"}');
|
|
156
|
+
const flags = { 'enable-foo': { value: true } };
|
|
157
|
+
const user2 = { key: 'user2' };
|
|
158
|
+
|
|
159
|
+
await withServer(async server => {
|
|
160
|
+
server.byDefault(respondJson(flags));
|
|
161
|
+
await withClient(user, { baseUrl: server.url }, async client => {
|
|
162
|
+
await client.waitForInitialization();
|
|
163
|
+
|
|
164
|
+
await sleepAsync(0); // allow any pending async tasks to complete
|
|
165
|
+
|
|
166
|
+
await client.identify(user2);
|
|
167
|
+
|
|
168
|
+
const value1 = platform.testing.getLocalStorageImmediately(lsKey);
|
|
169
|
+
expect(value1).not.toEqual(expect.anything());
|
|
170
|
+
const value2 = platform.testing.getLocalStorageImmediately(lsKey2);
|
|
171
|
+
expect(JSON.parse(value2)).toEqual({
|
|
172
|
+
$schema: 1,
|
|
173
|
+
'enable-foo': { value: true },
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|