Skip to content

Commit 2a86640

Browse files
chore: Add hook support in browser contract tests (#831)
Adds hook support in browser contract tests as well as adding the `track-hooks` capability.
1 parent 1519cb9 commit 2a86640

File tree

6 files changed

+106
-1
lines changed

6 files changed

+106
-1
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"packageManager": "yarn@3.4.1",
7171
"//": "Pin jsonc-parser because v3.3.0 breaks rollup-plugin-esbuild",
7272
"resolutions": {
73-
"jsonc-parser": "3.2.0"
73+
"jsonc-parser": "3.2.0",
74+
"parse5": "7.2.1"
7475
}
7576
}

packages/sdk/browser/contract-tests/entity/src/ClientEntity.ts

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { initialize, LDClient, LDLogger, LDOptions } from '@launchdarkly/js-clie
33
import { CommandParams, CommandType, ValueType } from './CommandParams';
44
import { CreateInstanceParams, SDKConfigParams } from './ConfigParams';
55
import { makeLogger } from './makeLogger';
6+
import TestHook from './TestHook';
67

78
export const badCommandError = new Error('unsupported command');
89
export const malformedCommand = new Error('command was malformed');
@@ -64,6 +65,12 @@ function makeSdkConfig(options: SDKConfigParams, tag: string) {
6465
};
6566
}
6667

68+
if (options.hooks) {
69+
cf.hooks = options.hooks.hooks.map(
70+
(hook) => new TestHook(hook.name, hook.callbackUri, hook.data, hook.errors),
71+
);
72+
}
73+
6774
cf.fetchGoals = false;
6875

6976
return cf;

packages/sdk/browser/contract-tests/entity/src/TestHarnessWebSocket.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export default class TestHarnessWebSocket {
4242
'anonymous-redaction',
4343
'strongly-typed',
4444
'client-prereq-events',
45+
'track-hooks',
4546
];
4647

4748
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
EvaluationSeriesContext,
3+
EvaluationSeriesData,
4+
Hook,
5+
HookMetadata,
6+
LDEvaluationDetail,
7+
TrackSeriesContext,
8+
} from '@launchdarkly/js-client-sdk';
9+
10+
export interface HookData {
11+
beforeEvaluation?: Record<string, unknown>;
12+
afterEvaluation?: Record<string, unknown>;
13+
}
14+
15+
export interface HookErrors {
16+
beforeEvaluation?: string;
17+
afterEvaluation?: string;
18+
afterTrack?: string;
19+
}
20+
21+
export default class TestHook implements Hook {
22+
private _name: string;
23+
private _endpoint: string;
24+
private _data?: HookData;
25+
private _errors?: HookErrors;
26+
27+
constructor(name: string, endpoint: string, data?: HookData, errors?: HookErrors) {
28+
this._name = name;
29+
this._endpoint = endpoint;
30+
this._data = data;
31+
this._errors = errors;
32+
}
33+
34+
private async _safePost(body: unknown): Promise<void> {
35+
try {
36+
await fetch(this._endpoint, {
37+
method: 'POST',
38+
body: JSON.stringify(body),
39+
});
40+
} catch {
41+
// The test could move on before the post, so we are ignoring
42+
// failed posts.
43+
}
44+
}
45+
46+
getMetadata(): HookMetadata {
47+
return {
48+
name: this._name,
49+
};
50+
}
51+
52+
beforeEvaluation(
53+
hookContext: EvaluationSeriesContext,
54+
data: EvaluationSeriesData,
55+
): EvaluationSeriesData {
56+
if (this._errors?.beforeEvaluation) {
57+
throw new Error(this._errors.beforeEvaluation);
58+
}
59+
this._safePost({
60+
evaluationSeriesContext: hookContext,
61+
evaluationSeriesData: data,
62+
stage: 'beforeEvaluation',
63+
});
64+
return { ...data, ...(this._data?.beforeEvaluation || {}) };
65+
}
66+
67+
afterEvaluation(
68+
hookContext: EvaluationSeriesContext,
69+
data: EvaluationSeriesData,
70+
detail: LDEvaluationDetail,
71+
): EvaluationSeriesData {
72+
if (this._errors?.afterEvaluation) {
73+
throw new Error(this._errors.afterEvaluation);
74+
}
75+
this._safePost({
76+
evaluationSeriesContext: hookContext,
77+
evaluationSeriesData: data,
78+
stage: 'afterEvaluation',
79+
evaluationDetail: detail,
80+
});
81+
82+
return { ...data, ...(this._data?.afterEvaluation || {}) };
83+
}
84+
85+
afterTrack(hookContext: TrackSeriesContext): void {
86+
if (this._errors?.afterTrack) {
87+
throw new Error(this._errors.afterTrack);
88+
}
89+
this._safePost({
90+
trackSeriesContext: hookContext,
91+
stage: 'afterTrack',
92+
});
93+
}
94+
}

packages/sdk/browser/src/common.ts

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type {
3232
LDLogLevel,
3333
LDMultiKindContext,
3434
LDSingleKindContext,
35+
TrackSeriesContext,
3536
} from '@launchdarkly/js-client-sdk-common';
3637

3738
/**

packages/shared/sdk-client/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export type {
2828
IdentifySeriesData,
2929
IdentifySeriesResult,
3030
IdentifySeriesStatus,
31+
TrackSeriesContext,
3132
LDInspection,
3233
} from './api';
3334

0 commit comments

Comments
 (0)