Skip to content

Commit 2678eec

Browse files
committed
added event tests
Signed-off-by: jarebudev <[email protected]>
1 parent ca52bf1 commit 2678eec

File tree

2 files changed

+153
-25
lines changed

2 files changed

+153
-25
lines changed

libs/providers/unleash-web/src/lib/unleash-web-provider.spec.ts

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,128 @@
11
import { UnleashWebProvider } from './unleash-web-provider';
22
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
3+
import {
4+
EvaluationContext,
5+
OpenFeature,
6+
ProviderEvents,
7+
ProviderStatus,
8+
StandardResolutionReasons,
9+
ErrorCode,
10+
EvaluationDetails,
11+
JsonValue,
12+
} from '@openfeature/web-sdk';
313

414
import testdata from './testdata.json';
515
import TestLogger from './test-logger';
616

7-
describe('UnleashWebProvider', () => {
8-
const endpoint = 'http://localhost:4242';
9-
const logger = new TestLogger();
10-
const valueProperty = 'value';
17+
const endpoint = 'http://localhost:4242';
18+
const logger = new TestLogger();
19+
const valueProperty = 'value';
1120

21+
describe('UnleashWebProvider', () => {
1222
let provider: UnleashWebProvider;
1323

24+
beforeAll(async () => {
25+
enableFetchMocks();
26+
});
27+
28+
it('should be an instance of UnleashWebProvider', async () => {
29+
fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
30+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test',}, logger);
31+
await provider.initialize();
32+
expect(provider).toBeInstanceOf(UnleashWebProvider);
33+
});
34+
35+
});
36+
37+
describe('events', () => {
38+
1439
beforeEach(() => {
15-
fetchMock.mockClear();
16-
fetchMock.mockReset();
40+
fetchMock.resetMocks();
1741
});
1842

1943
beforeAll(async () => {
2044
enableFetchMocks();
21-
//fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
22-
fetchMock.mockResponseOnce(JSON.stringify(testdata));
45+
});
46+
47+
it('should emit ProviderEvents.ConfigurationChanged and ProviderEvents.Ready events when provider is initialized', async () => {
48+
let provider: UnleashWebProvider;
49+
fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
2350
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test',}, logger);
51+
52+
const configChangeHandler = jest.fn();
53+
const readyHandler = jest.fn();
54+
provider.events.addHandler(ProviderEvents.ConfigurationChanged, configChangeHandler);
55+
provider.events.addHandler(ProviderEvents.Ready, readyHandler);
2456
await provider.initialize();
57+
expect(configChangeHandler).toHaveBeenCalledWith({
58+
message: 'Flags changed',
59+
});
60+
expect(readyHandler).toHaveBeenCalledWith({
61+
message: 'Ready',
62+
});
2563
});
2664

27-
it('should be an instance of UnleashWebProvider', async () => {
28-
expect(provider).toBeInstanceOf(UnleashWebProvider);
65+
it('should emit ProviderEvents.Error event when provider errors on initialization', async () => {
66+
let provider: UnleashWebProvider;
67+
fetchMock.mockResponseOnce('{}', { status: 401 });
68+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test',}, logger);
69+
const handler = jest.fn();
70+
provider.events.addHandler(ProviderEvents.Error, handler);
71+
await provider.initialize();
72+
expect(handler).toHaveBeenCalledWith({
73+
message: 'Error',
74+
});
75+
});
76+
77+
it('should emit ProviderEvents.ConfigurationChanged when the flags change', async () => {
78+
let provider: UnleashWebProvider;
79+
fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
80+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test', refreshInterval: 2}, logger);
81+
await provider.initialize();
82+
await new Promise<void>((resolve) => {
83+
let configChangeHandler = function() {
84+
resolve();
85+
};
86+
provider.events.addHandler(ProviderEvents.ConfigurationChanged, configChangeHandler);
87+
fetchMock.mockResponseOnce(JSON.stringify(testdata));
88+
});
89+
});
90+
91+
it('should emit ProviderEvents.Ready when provider recovers from an error', async () => {
92+
let provider: UnleashWebProvider;
93+
fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
94+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test', refreshInterval: 2}, logger);
95+
await provider.initialize();
96+
await new Promise<void>((resolve) => {
97+
let errorHandler = function() {
98+
resolve();
99+
};
100+
provider.events.addHandler(ProviderEvents.Error, errorHandler);
101+
fetchMock.mockResponseOnce('{}', { status: 401 });
102+
});
103+
104+
await new Promise<void>((resolve) => {
105+
let readyHandler = function() {
106+
resolve();
107+
};
108+
provider.events.addHandler(ProviderEvents.Ready, readyHandler);
109+
fetchMock.mockResponseOnce(JSON.stringify(testdata));
110+
});
111+
}, 10000);
112+
});
113+
114+
describe('UnleashWebProvider evaluations', () => {
115+
let provider: UnleashWebProvider;
116+
117+
beforeEach(() => {
118+
fetchMock.resetMocks();
119+
});
120+
121+
beforeAll(async () => {
122+
enableFetchMocks();
123+
fetchMock.mockResponseOnce(JSON.stringify(testdata));
124+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test',}, logger);
125+
await provider.initialize();
29126
});
30127

31128
describe('method resolveBooleanEvaluation', () => {

libs/providers/unleash-web/src/lib/unleash-web-provider.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
1-
import { EvaluationContext, Provider, Logger, JsonValue, FlagNotFoundError, OpenFeatureEventEmitter, ProviderEvents, ResolutionDetails, ProviderFatalError, StandardResolutionReasons } from '@openfeature/web-sdk';
2-
import { UnleashClient, IConfig, IContext, IMutableContext } from 'unleash-proxy-client';
3-
import { UnleashOptions, UnleashContextOptions } from './options';
1+
import {
2+
EvaluationContext,
3+
Provider,
4+
Logger,
5+
JsonValue,
6+
FlagNotFoundError,
7+
OpenFeatureEventEmitter,
8+
ProviderEvents,
9+
ResolutionDetails,
10+
ProviderFatalError,
11+
StandardResolutionReasons
12+
} from '@openfeature/web-sdk';
13+
import {
14+
UnleashClient,
15+
IConfig,
16+
IContext,
17+
IMutableContext
18+
} from 'unleash-proxy-client';
19+
import {
20+
UnleashOptions,
21+
UnleashContextOptions
22+
} from './options';
423

524
export class UnleashWebProvider implements Provider {
625
metadata = {
@@ -28,6 +47,7 @@ export class UnleashWebProvider implements Provider {
2847
url: options.url,
2948
clientKey: options.clientKey,
3049
appName: options.appName,
50+
refreshInterval: options.refreshInterval,
3151
};
3252
this._client = new UnleashClient(config);
3353
}
@@ -40,33 +60,44 @@ export class UnleashWebProvider implements Provider {
4060
private async initializeClient() {
4161
try {
4262
this.registerEventListeners();
43-
this._client?.start();
44-
return new Promise<void>((resolve) => {
45-
this._client?.on('ready', () => {
46-
this._logger?.info('Unleash ready event received');
47-
resolve();
48-
});
49-
});
63+
await this._client?.start();
5064
} catch (e) {
5165
throw new ProviderFatalError(getErrorMessage(e));
5266
}
5367
}
5468

5569
private registerEventListeners() {
70+
this._client?.on('ready', () => {
71+
this._logger?.info('Unleash ready event received');
72+
this.events.emit(ProviderEvents.Ready, {
73+
message: 'Ready'
74+
});
75+
});
5676
this._client?.on('update', () => {
5777
this._logger?.info('Unleash update event received');
5878
this.events.emit(ProviderEvents.ConfigurationChanged, {
5979
message: 'Flags changed'
6080
});
6181
});
82+
this._client?.on('error', () => {
83+
this._logger?.info('Unleash error event received');
84+
this.events.emit(ProviderEvents.Error, {
85+
message: 'Error'
86+
});
87+
});
88+
this._client?.on('recovered', () => {
89+
this._logger?.info('Unleash recovered event received');
90+
this.events.emit(ProviderEvents.Ready, {
91+
message: 'Recovered'
92+
});
93+
});
6294
}
6395

6496
async onContextChange(_oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
6597
let unleashContext = new Map();
6698
let properties = new Map();
6799
Object.keys(newContext).forEach((key) => {
68-
this._logger?.info(key + " = " + newContext[key]);
69-
switch(key) {
100+
switch (key) {
70101
case "appName":
71102
case "userId":
72103
case "environment":
@@ -117,7 +148,7 @@ export class UnleashWebProvider implements Provider {
117148
private evaluate<T>(flagKey: string, defaultValue: T): ResolutionDetails<T> {
118149
const evaluatedVariant = this._client?.getVariant(flagKey);
119150
let value;
120-
let retVariant
151+
let variant
121152
this._logger?.debug("evaluatedVariant = " + JSON.stringify(evaluatedVariant));
122153
if (typeof evaluatedVariant === 'undefined') {
123154
throw new FlagNotFoundError();
@@ -127,11 +158,11 @@ export class UnleashWebProvider implements Provider {
127158
value = defaultValue as T;
128159
}
129160
else {
130-
retVariant = evaluatedVariant.name;
161+
variant = evaluatedVariant.name;
131162
value = evaluatedVariant.payload?.value;
132163
}
133164
return {
134-
variant: retVariant,
165+
variant: variant,
135166
value: value as T,
136167
};
137168
}

0 commit comments

Comments
 (0)