Skip to content

Commit 276a740

Browse files
authored
fix: add status to flagd web (#497)
Signed-off-by: Todd Baert <[email protected]>
1 parent 80990b3 commit 276a740

File tree

4 files changed

+90
-38
lines changed

4 files changed

+90
-38
lines changed

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

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { CallbackClient, Code, ConnectError, PromiseClient } from '@bufbuild/connect';
22
import { Struct } from '@bufbuild/protobuf';
3-
import { Client, ErrorCode, JsonValue, OpenFeature, ProviderEvents, StandardResolutionReasons } from '@openfeature/web-sdk';
3+
import {
4+
Client,
5+
ErrorCode,
6+
JsonValue,
7+
OpenFeature,
8+
ProviderEvents,
9+
ProviderStatus,
10+
StandardResolutionReasons,
11+
} from '@openfeature/web-sdk';
412
import fetchMock from 'jest-fetch-mock';
513
import { Service } from '../proto/ts/schema/v1/schema_connect';
614
import { AnyFlag, EventStreamResponse, ResolveAllResponse } from '../proto/ts/schema/v1/schema_pb';
@@ -52,7 +60,7 @@ class MockCallbackClient implements Partial<CallbackClient<typeof Service>> {
5260
(
5361
_,
5462
messageCallback: (response: EventStreamResponse) => void,
55-
closeCallback: (error: ConnectError) => void
63+
closeCallback: (error: ConnectError) => void,
5664
): (() => void) => {
5765
this.messageCallback = messageCallback;
5866
this.closeCallback = closeCallback;
@@ -63,7 +71,7 @@ class MockCallbackClient implements Partial<CallbackClient<typeof Service>> {
6371
}
6472

6573
return this.cancelFunction;
66-
}
74+
},
6775
);
6876
}
6977

@@ -122,9 +130,9 @@ describe(FlagdWebProvider.name, () => {
122130
{ host: 'fake.com' },
123131
console,
124132
new MockPromiseClient() as unknown as PromiseClient<typeof Service>,
125-
mockCallbackClient as unknown as CallbackClient<typeof Service>
133+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
126134
);
127-
OpenFeature.setProvider(provider);
135+
OpenFeature.setProvider('resolution functionality test', provider);
128136
client = OpenFeature.getClient('resolution functionality test');
129137

130138
client.addHandler(ProviderEvents.Ready, () => {
@@ -165,38 +173,64 @@ describe(FlagdWebProvider.name, () => {
165173
});
166174

167175
describe('events', () => {
176+
let provider: FlagdWebProvider;
168177
let client: Client;
169178
let mockCallbackClient: MockCallbackClient;
170179
const mockPromiseClient = new MockPromiseClient() as unknown as PromiseClient<typeof Service>;
171180
const context = { some: 'value' };
172181

173182
beforeEach(() => {
174183
mockCallbackClient = new MockCallbackClient();
175-
OpenFeature.setProvider(
176-
new FlagdWebProvider(
177-
{ host: 'fake.com', maxRetries: -1 },
178-
console,
179-
mockPromiseClient,
180-
mockCallbackClient as unknown as CallbackClient<typeof Service>
181-
)
184+
provider = new FlagdWebProvider(
185+
{ host: 'fake.com', maxRetries: -1 },
186+
console,
187+
mockPromiseClient,
188+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
182189
);
190+
OpenFeature.setProvider('events-test', provider);
183191
client = OpenFeature.getClient('events-test');
184192
});
185193

186194
describe(ProviderEvents.Ready, () => {
187-
it('should be fired as soon as client subscribes, if ready', (done) => {
195+
it('should fire as soon as client subscribes, if ready', (done) => {
196+
try {
197+
// should start NOT_READY
198+
expect(provider.status).toEqual(ProviderStatus.NOT_READY);
199+
done();
200+
} catch (err) {
201+
done(err);
202+
}
203+
188204
mockCallbackClient.mockMessage({
189205
type: EVENT_PROVIDER_READY,
190206
});
191207

192208
client.addHandler(ProviderEvents.Ready, () => {
193-
done();
209+
try {
210+
expect(provider.status).toEqual(ProviderStatus.READY);
211+
done();
212+
} catch (err) {
213+
done(err);
214+
}
194215
});
195216
});
196217

197-
it('should fire if message received', (done) => {
198-
client.addHandler(ProviderEvents.Ready, () => {
218+
it('should fire and be ready if message received', (done) => {
219+
try {
220+
// should start NOT_READY
221+
expect(provider.status).toEqual(ProviderStatus.NOT_READY);
199222
done();
223+
} catch (err) {
224+
done(err);
225+
}
226+
227+
client.addHandler(ProviderEvents.Ready, () => {
228+
try {
229+
expect(provider.status).toEqual(ProviderStatus.READY);
230+
done();
231+
} catch (err) {
232+
done(err);
233+
}
200234
});
201235
mockCallbackClient.mockMessage({
202236
type: EVENT_PROVIDER_READY,
@@ -215,12 +249,13 @@ describe(FlagdWebProvider.name, () => {
215249
});
216250

217251
it('should trigger call to resolveAll with current context', (done) => {
218-
219252
client.addHandler(ProviderEvents.ConfigurationChanged, () => {
220253
try {
221-
expect(mockPromiseClient.resolveAll).toHaveBeenLastCalledWith({context: Struct.fromJson(context as JsonValue)});
254+
expect(mockPromiseClient.resolveAll).toHaveBeenLastCalledWith({
255+
context: Struct.fromJson(context as JsonValue),
256+
});
222257
done();
223-
} catch(err) {
258+
} catch (err) {
224259
done(err);
225260
}
226261
});
@@ -235,7 +270,12 @@ describe(FlagdWebProvider.name, () => {
235270
describe(ProviderEvents.Error, () => {
236271
it('should fire if message received', (done) => {
237272
client.addHandler(ProviderEvents.Error, () => {
238-
done();
273+
try {
274+
expect(provider.status).toEqual(ProviderStatus.ERROR);
275+
done();
276+
} catch (err) {
277+
done(err);
278+
}
239279
});
240280
mockCallbackClient.mockClose({
241281
code: Code.Unavailable,
@@ -251,19 +291,20 @@ describe(FlagdWebProvider.name, () => {
251291
beforeEach(() => {
252292
mockCallbackClient = new MockCallbackClient();
253293
OpenFeature.setProvider(
294+
'shutdown test',
254295
new FlagdWebProvider(
255296
{ host: 'fake.com', maxRetries: -1 },
256297
console,
257298
mockPromiseClient,
258-
mockCallbackClient as unknown as CallbackClient<typeof Service>
259-
)
299+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
300+
),
260301
);
261302
});
262303

263304
describe('API close', () => {
264-
it('should call cancel function on provider', () => {
305+
it('should call cancel function on provider', async () => {
265306
expect(mockCallbackClient.cancelFunction).not.toHaveBeenCalled();
266-
OpenFeature.close();
307+
await OpenFeature.close();
267308
expect(mockCallbackClient.cancelFunction).toHaveBeenCalled();
268309
});
269310
});
@@ -274,12 +315,13 @@ describe(FlagdWebProvider.name, () => {
274315
it('should attempt reconnect many times', (done) => {
275316
const mockCallbackClient = new MockCallbackClient();
276317
OpenFeature.setProvider(
318+
'should attempt many reconnect test',
277319
new FlagdWebProvider(
278320
{ host: 'fake.com' },
279321
console,
280322
undefined,
281-
mockCallbackClient as unknown as CallbackClient<typeof Service>
282-
)
323+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
324+
),
283325
);
284326
mockCallbackClient.fail = true;
285327
mockCallbackClient.mockClose({
@@ -300,12 +342,13 @@ describe(FlagdWebProvider.name, () => {
300342
it('should attempt reconnect if maxRetries (1) times', (done) => {
301343
const mockCallbackClient = new MockCallbackClient();
302344
OpenFeature.setProvider(
345+
'should connect test',
303346
new FlagdWebProvider(
304347
{ host: 'fake.com', maxRetries: 1 },
305348
console,
306349
undefined,
307-
mockCallbackClient as unknown as CallbackClient<typeof Service>
308-
)
350+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
351+
),
309352
);
310353

311354
mockCallbackClient.fail = true;
@@ -325,12 +368,13 @@ describe(FlagdWebProvider.name, () => {
325368
it('should NOT attempt reconnect if maxRetries (-1) times', (done) => {
326369
const mockCallbackClient = new MockCallbackClient();
327370
OpenFeature.setProvider(
371+
'should not reconnect test',
328372
new FlagdWebProvider(
329373
{ host: 'fake.com', maxRetries: -1 },
330374
console,
331375
undefined,
332-
mockCallbackClient as unknown as CallbackClient<typeof Service>
333-
)
376+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
377+
),
334378
);
335379

336380
mockCallbackClient.fail = true;
@@ -357,9 +401,9 @@ describe(FlagdWebProvider.name, () => {
357401
{ host: 'fake.com' },
358402
console,
359403
new MockPromiseClient() as unknown as PromiseClient<typeof Service>,
360-
mockCallbackClient as unknown as CallbackClient<typeof Service>
404+
mockCallbackClient as unknown as CallbackClient<typeof Service>,
361405
);
362-
OpenFeature.setProvider(provider);
406+
OpenFeature.setProvider('resolution functionality test', provider);
363407
client = OpenFeature.getClient('resolution functionality test');
364408

365409
client.addHandler(ProviderEvents.Ready, () => {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
OpenFeatureEventEmitter,
1212
Provider,
1313
ProviderEvents,
14+
ProviderStatus,
1415
ResolutionDetails,
1516
StandardResolutionReasons,
1617
TypeMismatchError,
@@ -33,6 +34,7 @@ export class FlagdWebProvider implements Provider {
3334
name: 'flagd-web',
3435
};
3536

37+
private _status = ProviderStatus.NOT_READY;
3638
private _connected = false;
3739
private _promiseClient: PromiseClient<typeof Service>;
3840
private _callbackClient: CallbackClient<typeof Service>;
@@ -61,6 +63,10 @@ export class FlagdWebProvider implements Provider {
6163
this._logger = logger;
6264
}
6365

66+
get status() {
67+
return this._status;
68+
}
69+
6470
events = new OpenFeatureEventEmitter();
6571

6672
async onContextChange(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
@@ -122,6 +128,7 @@ export class FlagdWebProvider implements Provider {
122128
case EVENT_PROVIDER_READY:
123129
this.fetchAll(currentContext).then(() => {
124130
this.resetConnectionState();
131+
this._status = ProviderStatus.READY;
125132
resolve();
126133
});
127134
return;
@@ -134,6 +141,7 @@ export class FlagdWebProvider implements Provider {
134141
}
135142
},
136143
(err) => {
144+
this._status = ProviderStatus.ERROR;
137145
this._logger?.error(`${FlagdWebProvider.name}: could not establish connection to flagd, ${err?.message}`);
138146
this._logger?.debug(err?.stack);
139147
if (this._retry < this._maxRetries) {

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@bufbuild/connect-web": "^0.11.0",
1616
"@bufbuild/protobuf": "^1.2.0",
1717
"@grpc/grpc-js": "^1.8.20",
18-
"@openfeature/web-sdk": "^0.3.6-experimental",
18+
"@openfeature/web-sdk": "^0.3.10-experimental",
1919
"@opentelemetry/api": "^1.3.0",
2020
"@protobuf-ts/grpc-transport": "^2.9.0",
2121
"@protobuf-ts/runtime-rpc": "^2.9.0",
@@ -68,4 +68,4 @@
6868
"ts-node": "10.9.1",
6969
"typescript": "5.1.6"
7070
}
71-
}
71+
}

0 commit comments

Comments
 (0)