Skip to content

Commit 19585cb

Browse files
committed
Additional tests.
1 parent 93b1ba6 commit 19585cb

File tree

3 files changed

+311
-2
lines changed

3 files changed

+311
-2
lines changed

packages/shared/sdk-client/__tests__/HookRunner.test.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,37 @@ describe('given a hook runner and test hook', () => {
101101
expect(method).toHaveBeenCalled();
102102
expect(logger.error).not.toHaveBeenCalled();
103103
});
104+
105+
it('should pass evaluation series data from before to after hooks', () => {
106+
const key = 'test-flag';
107+
const context: LDContext = { kind: 'user', key: 'user-123' };
108+
const defaultValue = false;
109+
const evaluationResult: LDEvaluationDetail = {
110+
value: true,
111+
variationIndex: 1,
112+
reason: { kind: 'OFF' },
113+
};
114+
115+
testHook.beforeEvaluation = jest
116+
.fn()
117+
.mockImplementation((_, series) => ({ ...series, testData: 'before data' }));
118+
119+
testHook.afterEvaluation = jest.fn();
120+
121+
const method = jest.fn().mockReturnValue(evaluationResult);
122+
123+
hookRunner.withEvaluation(key, context, defaultValue, method);
124+
125+
expect(testHook.beforeEvaluation).toHaveBeenCalled();
126+
expect(testHook.afterEvaluation).toHaveBeenCalledWith(
127+
expect.anything(),
128+
expect.objectContaining({ testData: 'before data' }),
129+
evaluationResult,
130+
);
131+
});
104132
});
105133

106-
describe('when handling an identifcation', () => {
134+
describe('when handling an identification', () => {
107135
it('should execute identify hooks', () => {
108136
const context: LDContext = { kind: 'user', key: 'user-123' };
109137
const timeout = 10;
@@ -150,6 +178,28 @@ describe('given a hook runner and test hook', () => {
150178
),
151179
);
152180
});
181+
182+
it('should pass identify series data from before to after hooks', () => {
183+
const context: LDContext = { kind: 'user', key: 'user-123' };
184+
const timeout = 10;
185+
const identifyResult: IdentifyResult = 'completed';
186+
187+
testHook.beforeIdentify = jest
188+
.fn()
189+
.mockImplementation((_, series) => ({ ...series, testData: 'before identify data' }));
190+
191+
testHook.afterIdentify = jest.fn();
192+
193+
const identifyCallback = hookRunner.identify(context, timeout);
194+
identifyCallback(identifyResult);
195+
196+
expect(testHook.beforeIdentify).toHaveBeenCalled();
197+
expect(testHook.afterIdentify).toHaveBeenCalledWith(
198+
expect.anything(),
199+
expect.objectContaining({ testData: 'before identify data' }),
200+
identifyResult,
201+
);
202+
});
153203
});
154204

155205
it('should use the added hook in future invocations', () => {
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { AutoEnvAttributes } from '@launchdarkly/js-sdk-common';
2+
3+
import { Hook, HookMetadata } from '../src/api';
4+
import LDClientImpl from '../src/LDClientImpl';
5+
import { createBasicPlatform } from './createBasicPlatform';
6+
import { makeTestDataManagerFactory } from './TestDataManager';
7+
8+
it('should use hooks registered during configuration', async () => {
9+
const testHook: Hook = {
10+
beforeEvaluation: jest.fn(),
11+
afterEvaluation: jest.fn(),
12+
beforeIdentify: jest.fn(),
13+
afterIdentify: jest.fn(),
14+
getMetadata(): HookMetadata {
15+
return {
16+
name: 'test hook',
17+
};
18+
},
19+
};
20+
21+
const platform = createBasicPlatform();
22+
const factory = makeTestDataManagerFactory('sdk-key', platform, {
23+
disableNetwork: true,
24+
});
25+
const client = new LDClientImpl(
26+
'sdk-key',
27+
AutoEnvAttributes.Disabled,
28+
platform,
29+
{
30+
sendEvents: false,
31+
hooks: [testHook],
32+
},
33+
factory,
34+
);
35+
36+
await client.identify({ key: 'user-key' });
37+
await client.variation('flag-key', false);
38+
39+
expect(testHook.beforeIdentify).toHaveBeenCalledWith(
40+
{ context: { key: 'user-key' }, timeout: undefined },
41+
{},
42+
);
43+
expect(testHook.afterIdentify).toHaveBeenCalledWith(
44+
{ context: { key: 'user-key' }, timeout: undefined },
45+
{},
46+
'completed',
47+
);
48+
expect(testHook.beforeEvaluation).toHaveBeenCalledWith(
49+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
50+
{},
51+
);
52+
expect(testHook.afterEvaluation).toHaveBeenCalledWith(
53+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
54+
{},
55+
{
56+
reason: {
57+
errorKind: 'FLAG_NOT_FOUND',
58+
kind: 'ERROR',
59+
},
60+
value: false,
61+
variationIndex: null,
62+
},
63+
);
64+
});
65+
66+
it('should execute hooks that are added using addHook', async () => {
67+
const platform = createBasicPlatform();
68+
const factory = makeTestDataManagerFactory('sdk-key', platform, {
69+
disableNetwork: true,
70+
});
71+
const client = new LDClientImpl(
72+
'sdk-key',
73+
AutoEnvAttributes.Disabled,
74+
platform,
75+
{
76+
sendEvents: false,
77+
},
78+
factory,
79+
);
80+
81+
const addedHook: Hook = {
82+
beforeEvaluation: jest.fn(),
83+
afterEvaluation: jest.fn(),
84+
beforeIdentify: jest.fn(),
85+
afterIdentify: jest.fn(),
86+
getMetadata(): HookMetadata {
87+
return {
88+
name: 'added hook',
89+
};
90+
},
91+
};
92+
93+
client.addHook(addedHook);
94+
95+
await client.identify({ key: 'user-key' });
96+
await client.variation('flag-key', false);
97+
98+
expect(addedHook.beforeIdentify).toHaveBeenCalledWith(
99+
{ context: { key: 'user-key' }, timeout: undefined },
100+
{},
101+
);
102+
expect(addedHook.afterIdentify).toHaveBeenCalledWith(
103+
{ context: { key: 'user-key' }, timeout: undefined },
104+
{},
105+
'completed',
106+
);
107+
expect(addedHook.beforeEvaluation).toHaveBeenCalledWith(
108+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
109+
{},
110+
);
111+
expect(addedHook.afterEvaluation).toHaveBeenCalledWith(
112+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
113+
{},
114+
{
115+
reason: {
116+
errorKind: 'FLAG_NOT_FOUND',
117+
kind: 'ERROR',
118+
},
119+
value: false,
120+
variationIndex: null,
121+
},
122+
);
123+
});
124+
125+
it('should execute both initial hooks and hooks added using addHook', async () => {
126+
const initialHook: Hook = {
127+
beforeEvaluation: jest.fn(),
128+
afterEvaluation: jest.fn(),
129+
beforeIdentify: jest.fn(),
130+
afterIdentify: jest.fn(),
131+
getMetadata(): HookMetadata {
132+
return {
133+
name: 'initial hook',
134+
};
135+
},
136+
};
137+
138+
const platform = createBasicPlatform();
139+
const factory = makeTestDataManagerFactory('sdk-key', platform, {
140+
disableNetwork: true,
141+
});
142+
const client = new LDClientImpl(
143+
'sdk-key',
144+
AutoEnvAttributes.Disabled,
145+
platform,
146+
{
147+
sendEvents: false,
148+
hooks: [initialHook],
149+
},
150+
factory,
151+
);
152+
153+
const addedHook: Hook = {
154+
beforeEvaluation: jest.fn(),
155+
afterEvaluation: jest.fn(),
156+
beforeIdentify: jest.fn(),
157+
afterIdentify: jest.fn(),
158+
getMetadata(): HookMetadata {
159+
return {
160+
name: 'added hook',
161+
};
162+
},
163+
};
164+
165+
client.addHook(addedHook);
166+
167+
await client.identify({ key: 'user-key' });
168+
await client.variation('flag-key', false);
169+
170+
// Check initial hook
171+
expect(initialHook.beforeIdentify).toHaveBeenCalledWith(
172+
{ context: { key: 'user-key' }, timeout: undefined },
173+
{},
174+
);
175+
expect(initialHook.afterIdentify).toHaveBeenCalledWith(
176+
{ context: { key: 'user-key' }, timeout: undefined },
177+
{},
178+
'completed',
179+
);
180+
expect(initialHook.beforeEvaluation).toHaveBeenCalledWith(
181+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
182+
{},
183+
);
184+
expect(initialHook.afterEvaluation).toHaveBeenCalledWith(
185+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
186+
{},
187+
{
188+
reason: {
189+
errorKind: 'FLAG_NOT_FOUND',
190+
kind: 'ERROR',
191+
},
192+
value: false,
193+
variationIndex: null,
194+
},
195+
);
196+
197+
// Check added hook
198+
expect(addedHook.beforeIdentify).toHaveBeenCalledWith(
199+
{ context: { key: 'user-key' }, timeout: undefined },
200+
{},
201+
);
202+
expect(addedHook.afterIdentify).toHaveBeenCalledWith(
203+
{ context: { key: 'user-key' }, timeout: undefined },
204+
{},
205+
'completed',
206+
);
207+
expect(addedHook.beforeEvaluation).toHaveBeenCalledWith(
208+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
209+
{},
210+
);
211+
expect(addedHook.afterEvaluation).toHaveBeenCalledWith(
212+
{ context: { key: 'user-key' }, defaultValue: false, flagKey: 'flag-key' },
213+
{},
214+
{
215+
reason: {
216+
errorKind: 'FLAG_NOT_FOUND',
217+
kind: 'ERROR',
218+
},
219+
value: false,
220+
variationIndex: null,
221+
},
222+
);
223+
});

packages/shared/sdk-client/__tests__/TestDataManager.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,33 @@ import { Configuration } from '../src/configuration/Configuration';
1212
import { BaseDataManager, DataManagerFactory } from '../src/DataManager';
1313
import { FlagManager } from '../src/flag-manager/FlagManager';
1414
import LDEmitter from '../src/LDEmitter';
15+
import { DataSourcePaths } from '../src/streaming/DataSourceConfig';
1516

1617
export default class TestDataManager extends BaseDataManager {
18+
constructor(
19+
platform: Platform,
20+
flagManager: FlagManager,
21+
credential: string,
22+
config: Configuration,
23+
getPollingPaths: () => DataSourcePaths,
24+
getStreamingPaths: () => DataSourcePaths,
25+
baseHeaders: LDHeaders,
26+
emitter: LDEmitter,
27+
private readonly disableNetwork: boolean,
28+
diagnosticsManager?: internal.DiagnosticsManager,
29+
) {
30+
super(
31+
platform,
32+
flagManager,
33+
credential,
34+
config,
35+
getPollingPaths,
36+
getStreamingPaths,
37+
baseHeaders,
38+
emitter,
39+
diagnosticsManager,
40+
);
41+
}
1742
override async identify(
1843
identifyResolve: () => void,
1944
identifyReject: (err: Error) => void,
@@ -33,6 +58,10 @@ export default class TestDataManager extends BaseDataManager {
3358
'Identify - Flags loaded from cache, but identify was requested with "waitForNetworkResults"',
3459
);
3560
}
61+
if (this.disableNetwork) {
62+
identifyResolve();
63+
return;
64+
}
3665

3766
this.setupConnection(context, identifyResolve, identifyReject);
3867
}
@@ -52,7 +81,13 @@ export default class TestDataManager extends BaseDataManager {
5281
}
5382
}
5483

55-
export function makeTestDataManagerFactory(sdkKey: string, platform: Platform): DataManagerFactory {
84+
export function makeTestDataManagerFactory(
85+
sdkKey: string,
86+
platform: Platform,
87+
options: {
88+
disableNetwork?: boolean;
89+
},
90+
): DataManagerFactory {
5691
return (
5792
flagManager: FlagManager,
5893
configuration: Configuration,
@@ -83,6 +118,7 @@ export function makeTestDataManagerFactory(sdkKey: string, platform: Platform):
83118
}),
84119
baseHeaders,
85120
emitter,
121+
!!options.disableNetwork,
86122
diagnosticsManager,
87123
);
88124
}

0 commit comments

Comments
 (0)