@@ -89,11 +89,11 @@ describe('GoFeatureFlagWebProvider', () => {
89
89
const logger = new TestLogger ( ) ;
90
90
91
91
beforeEach ( async ( ) => {
92
- await WS . clean ( ) ;
92
+ WS . clean ( ) ;
93
93
await OpenFeature . close ( ) ;
94
94
fetchMock . mockClear ( ) ;
95
95
fetchMock . mockReset ( ) ;
96
- await jest . resetAllMocks ( ) ;
96
+ jest . resetAllMocks ( ) ;
97
97
websocketMockServer = new WS ( websocketEndpoint , { jsonProtocol : true } ) ;
98
98
fetchMock . post ( allFlagsEndpoint , defaultAllFlagResponse ) ;
99
99
fetchMock . post ( dataCollectorEndpoint , 200 ) ;
@@ -109,14 +109,14 @@ describe('GoFeatureFlagWebProvider', () => {
109
109
} ) ;
110
110
111
111
afterEach ( async ( ) => {
112
- await WS . clean ( ) ;
112
+ WS . clean ( ) ;
113
113
websocketMockServer . close ( ) ;
114
114
await OpenFeature . close ( ) ;
115
- await OpenFeature . clearHooks ( ) ;
115
+ OpenFeature . clearHooks ( ) ;
116
116
fetchMock . mockClear ( ) ;
117
117
fetchMock . mockReset ( ) ;
118
118
await defaultProvider ?. onClose ( ) ;
119
- await jest . resetAllMocks ( ) ;
119
+ jest . resetAllMocks ( ) ;
120
120
readyHandler . mockReset ( ) ;
121
121
errorHandler . mockReset ( ) ;
122
122
configurationChangedHandler . mockReset ( ) ;
@@ -145,8 +145,8 @@ describe('GoFeatureFlagWebProvider', () => {
145
145
describe ( 'flag evaluation' , ( ) => {
146
146
it ( 'should change evaluation value if context has changed' , async ( ) => {
147
147
await OpenFeature . setContext ( defaultContext ) ;
148
- OpenFeature . setProvider ( 'test-provider' , defaultProvider ) ;
149
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
148
+ await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
149
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
150
150
await websocketMockServer . connected ;
151
151
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
152
152
@@ -168,11 +168,11 @@ describe('GoFeatureFlagWebProvider', () => {
168
168
await OpenFeature . setContext ( defaultContext ) ;
169
169
const providerName = expect . getState ( ) . currentTestName || 'test' ;
170
170
OpenFeature . setProvider ( providerName , newDefaultProvider ( ) ) ;
171
- const client = await OpenFeature . getClient ( providerName ) ;
171
+ const client = OpenFeature . getClient ( providerName ) ;
172
172
await websocketMockServer . connected ;
173
173
// Need to wait before using the mock
174
174
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
175
- await websocketMockServer . close ( ) ;
175
+ websocketMockServer . close ( ) ;
176
176
177
177
const got = client . getBooleanDetails ( 'bool_flag' , false ) ;
178
178
expect ( got . reason ) . toEqual ( StandardResolutionReasons . CACHED ) ;
@@ -183,11 +183,11 @@ describe('GoFeatureFlagWebProvider', () => {
183
183
const providerName = expect . getState ( ) . currentTestName || 'test' ;
184
184
await OpenFeature . setContext ( defaultContext ) ;
185
185
OpenFeature . setProvider ( providerName , newDefaultProvider ( ) ) ;
186
- const client = await OpenFeature . getClient ( providerName ) ;
186
+ const client = OpenFeature . getClient ( providerName ) ;
187
187
client . addHandler ( ProviderEvents . Error , errorHandler ) ;
188
188
// wait the event to be triggered
189
189
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
190
- expect ( errorHandler ) . toBeCalled ( ) ;
190
+ expect ( errorHandler ) . toHaveBeenCalled ( ) ;
191
191
expect ( logger . inMemoryLogger [ 'error' ] [ 0 ] ) . toEqual (
192
192
'GoFeatureFlagWebProvider: invalid token used to contact GO Feature Flag instance: Error: Request failed with status code 401' ,
193
193
) ;
@@ -196,15 +196,15 @@ describe('GoFeatureFlagWebProvider', () => {
196
196
it ( 'should emit an error if we receive a 404 from GO Feature Flag' , async ( ) => {
197
197
fetchMock . post ( allFlagsEndpoint , 404 , { overwriteRoutes : true } ) ;
198
198
await OpenFeature . setContext ( defaultContext ) ;
199
- OpenFeature . setProvider ( 'test-provider' , defaultProvider ) ;
200
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
199
+ await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
200
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
201
201
client . addHandler ( ProviderEvents . Ready , readyHandler ) ;
202
202
client . addHandler ( ProviderEvents . Error , errorHandler ) ;
203
203
client . addHandler ( ProviderEvents . Stale , staleHandler ) ;
204
204
client . addHandler ( ProviderEvents . ConfigurationChanged , configurationChangedHandler ) ;
205
205
// wait the event to be triggered
206
206
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
207
- expect ( errorHandler ) . toBeCalled ( ) ;
207
+ expect ( errorHandler ) . toHaveBeenCalled ( ) ;
208
208
expect ( logger . inMemoryLogger [ 'error' ] [ 0 ] ) . toEqual (
209
209
'GoFeatureFlagWebProvider: impossible to call go-feature-flag relay proxy Error: Request failed with status code 404' ,
210
210
) ;
@@ -214,7 +214,7 @@ describe('GoFeatureFlagWebProvider', () => {
214
214
const flagKey = 'bool_flag' ;
215
215
await OpenFeature . setContext ( defaultContext ) ;
216
216
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
217
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
217
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
218
218
await websocketMockServer . connected ;
219
219
const got = client . getBooleanDetails ( flagKey , false ) ;
220
220
const want : EvaluationDetails < boolean > = {
@@ -233,7 +233,7 @@ describe('GoFeatureFlagWebProvider', () => {
233
233
const flagKey = 'string_flag' ;
234
234
await OpenFeature . setContext ( defaultContext ) ;
235
235
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
236
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
236
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
237
237
await websocketMockServer . connected ;
238
238
const got = client . getStringDetails ( flagKey , 'false' ) ;
239
239
const want : EvaluationDetails < string > = {
@@ -252,7 +252,7 @@ describe('GoFeatureFlagWebProvider', () => {
252
252
const flagKey = 'number_flag' ;
253
253
await OpenFeature . setContext ( defaultContext ) ;
254
254
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
255
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
255
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
256
256
await websocketMockServer . connected ;
257
257
const got = client . getNumberDetails ( flagKey , 456 ) ;
258
258
const want : EvaluationDetails < number > = {
@@ -271,7 +271,7 @@ describe('GoFeatureFlagWebProvider', () => {
271
271
const flagKey = 'object_flag' ;
272
272
await OpenFeature . setContext ( defaultContext ) ;
273
273
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
274
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
274
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
275
275
await websocketMockServer . connected ;
276
276
const got = client . getObjectDetails ( flagKey , { error : true } ) ;
277
277
const want : EvaluationDetails < JsonValue > = {
@@ -290,7 +290,7 @@ describe('GoFeatureFlagWebProvider', () => {
290
290
const flagKey = 'bool_flag' ;
291
291
await OpenFeature . setContext ( defaultContext ) ;
292
292
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
293
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
293
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
294
294
await websocketMockServer . connected ;
295
295
const got = client . getStringDetails ( flagKey , 'false' ) ;
296
296
const want : EvaluationDetails < string > = {
@@ -308,7 +308,7 @@ describe('GoFeatureFlagWebProvider', () => {
308
308
const flagKey = 'not-exist' ;
309
309
await OpenFeature . setContext ( defaultContext ) ;
310
310
await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
311
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
311
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
312
312
await websocketMockServer . connected ;
313
313
const got = client . getBooleanDetails ( flagKey , false ) ;
314
314
const want : EvaluationDetails < boolean > = {
@@ -354,8 +354,8 @@ describe('GoFeatureFlagWebProvider', () => {
354
354
describe ( 'eventing' , ( ) => {
355
355
it ( 'should call client handler with ProviderEvents.Ready when websocket is connected' , async ( ) => {
356
356
// await OpenFeature.setContext(defaultContext); // we deactivate this call because the context is already set, and we want to avoid calling contextChanged function
357
- OpenFeature . setProvider ( 'test-provider' , defaultProvider ) ;
358
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
357
+ await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
358
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
359
359
client . addHandler ( ProviderEvents . Ready , readyHandler ) ;
360
360
client . addHandler ( ProviderEvents . Error , errorHandler ) ;
361
361
client . addHandler ( ProviderEvents . Stale , staleHandler ) ;
@@ -365,16 +365,16 @@ describe('GoFeatureFlagWebProvider', () => {
365
365
await websocketMockServer . connected ;
366
366
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
367
367
368
- expect ( readyHandler ) . toBeCalled ( ) ;
369
- expect ( errorHandler ) . not . toBeCalled ( ) ;
370
- expect ( configurationChangedHandler ) . not . toBeCalled ( ) ;
371
- expect ( staleHandler ) . not . toBeCalled ( ) ;
368
+ expect ( readyHandler ) . toHaveBeenCalled ( ) ;
369
+ expect ( errorHandler ) . not . toHaveBeenCalled ( ) ;
370
+ expect ( configurationChangedHandler ) . not . toHaveBeenCalled ( ) ;
371
+ expect ( staleHandler ) . not . toHaveBeenCalled ( ) ;
372
372
} ) ;
373
373
374
374
it ( 'should call client handler with ProviderEvents.ConfigurationChanged when websocket is sending update' , async ( ) => {
375
375
// await OpenFeature.setContext(defaultContext); // we deactivate this call because the context is already set, and we want to avoid calling contextChanged function
376
- OpenFeature . setProvider ( 'test-provider' , defaultProvider ) ;
377
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
376
+ await OpenFeature . setProviderAndWait ( 'test-provider' , defaultProvider ) ;
377
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
378
378
379
379
client . addHandler ( ProviderEvents . Ready , readyHandler ) ;
380
380
client . addHandler ( ProviderEvents . Error , errorHandler ) ;
@@ -403,10 +403,10 @@ describe('GoFeatureFlagWebProvider', () => {
403
403
// waiting the call to the API to be successful
404
404
await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
405
405
406
- expect ( readyHandler ) . toBeCalled ( ) ;
407
- expect ( errorHandler ) . not . toBeCalled ( ) ;
408
- expect ( configurationChangedHandler ) . toBeCalled ( ) ;
409
- expect ( staleHandler ) . not . toBeCalled ( ) ;
406
+ expect ( readyHandler ) . toHaveBeenCalled ( ) ;
407
+ expect ( errorHandler ) . not . toHaveBeenCalled ( ) ;
408
+ expect ( configurationChangedHandler ) . toHaveBeenCalled ( ) ;
409
+ expect ( staleHandler ) . not . toHaveBeenCalled ( ) ;
410
410
expect ( configurationChangedHandler . mock . calls [ 0 ] [ 0 ] ) . toEqual ( {
411
411
clientName : 'test-provider' ,
412
412
domain : 'test-provider' ,
@@ -433,8 +433,8 @@ describe('GoFeatureFlagWebProvider', () => {
433
433
} ,
434
434
logger ,
435
435
) ;
436
- OpenFeature . setProvider ( 'test-provider' , provider ) ;
437
- const client = await OpenFeature . getClient ( 'test-provider' ) ;
436
+ await OpenFeature . setProviderAndWait ( 'test-provider' , provider ) ;
437
+ const client = OpenFeature . getClient ( 'test-provider' ) ;
438
438
client . addHandler ( ProviderEvents . Ready , readyHandler ) ;
439
439
client . addHandler ( ProviderEvents . Error , errorHandler ) ;
440
440
client . addHandler ( ProviderEvents . Stale , staleHandler ) ;
@@ -444,14 +444,14 @@ describe('GoFeatureFlagWebProvider', () => {
444
444
await websocketMockServer . connected ;
445
445
446
446
// Need to wait before using the mock
447
- await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
448
- await websocketMockServer . close ( ) ;
447
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
448
+ websocketMockServer . close ( ) ;
449
449
await new Promise ( ( resolve ) => setTimeout ( resolve , 300 ) ) ;
450
450
451
- expect ( readyHandler ) . toBeCalled ( ) ;
452
- expect ( errorHandler ) . not . toBeCalled ( ) ;
453
- expect ( configurationChangedHandler ) . not . toBeCalled ( ) ;
454
- expect ( staleHandler ) . toBeCalled ( ) ;
451
+ expect ( readyHandler ) . toHaveBeenCalled ( ) ;
452
+ expect ( errorHandler ) . not . toHaveBeenCalled ( ) ;
453
+ expect ( configurationChangedHandler ) . not . toHaveBeenCalled ( ) ;
454
+ expect ( staleHandler ) . toHaveBeenCalled ( ) ;
455
455
} ) ;
456
456
} ) ;
457
457
@@ -470,7 +470,7 @@ describe('GoFeatureFlagWebProvider', () => {
470
470
logger ,
471
471
) ;
472
472
473
- OpenFeature . setProvider ( clientName , p ) ;
473
+ await OpenFeature . setProviderAndWait ( clientName , p ) ;
474
474
const client = OpenFeature . getClient ( clientName ) ;
475
475
await websocketMockServer . connected ;
476
476
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
@@ -501,7 +501,7 @@ describe('GoFeatureFlagWebProvider', () => {
501
501
logger ,
502
502
) ;
503
503
504
- OpenFeature . setProvider ( clientName , p ) ;
504
+ await OpenFeature . setProviderAndWait ( clientName , p ) ;
505
505
const client = OpenFeature . getClient ( clientName ) ;
506
506
await websocketMockServer . connected ;
507
507
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
@@ -531,7 +531,7 @@ describe('GoFeatureFlagWebProvider', () => {
531
531
logger ,
532
532
) ;
533
533
534
- OpenFeature . setProvider ( clientName , p ) ;
534
+ await OpenFeature . setProviderAndWait ( clientName , p ) ;
535
535
const client = OpenFeature . getClient ( clientName ) ;
536
536
await websocketMockServer . connected ;
537
537
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
@@ -559,7 +559,7 @@ describe('GoFeatureFlagWebProvider', () => {
559
559
logger ,
560
560
) ;
561
561
562
- OpenFeature . setProvider ( clientName , p ) ;
562
+ await OpenFeature . setProviderAndWait ( clientName , p ) ;
563
563
const client = OpenFeature . getClient ( clientName ) ;
564
564
await websocketMockServer . connected ;
565
565
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
@@ -574,7 +574,7 @@ describe('GoFeatureFlagWebProvider', () => {
574
574
it ( 'should have a log when data collector is not available' , async ( ) => {
575
575
const clientName = expect . getState ( ) . currentTestName ?? 'test-provider' ;
576
576
fetchMock . post ( dataCollectorEndpoint , 500 , { overwriteRoutes : true } ) ;
577
- OpenFeature . setContext ( defaultContext ) ;
577
+ await OpenFeature . setContext ( defaultContext ) ;
578
578
const p = new GoFeatureFlagWebProvider (
579
579
{
580
580
endpoint : endpoint ,
@@ -585,7 +585,7 @@ describe('GoFeatureFlagWebProvider', () => {
585
585
logger ,
586
586
) ;
587
587
588
- OpenFeature . setProvider ( clientName , p ) ;
588
+ await OpenFeature . setProviderAndWait ( clientName , p ) ;
589
589
const client = OpenFeature . getClient ( clientName ) ;
590
590
await websocketMockServer . connected ;
591
591
await new Promise ( ( resolve ) => setTimeout ( resolve , 5 ) ) ;
@@ -606,4 +606,51 @@ describe('GoFeatureFlagWebProvider', () => {
606
606
await OpenFeature . close ( ) ;
607
607
} ) ;
608
608
} ) ;
609
+ it ( 'should resolve when WebSocket is open' , async ( ) => {
610
+ const provider = new GoFeatureFlagWebProvider ( { endpoint : 'http://localhost:1031' , apiTimeout : 1000 } ) ;
611
+ await provider . initialize ( { targetingKey : 'user-key' } ) ;
612
+ const websocket = new WebSocket ( websocketEndpoint ) ;
613
+ await websocketMockServer . connected ;
614
+ await expect ( provider . waitWebsocketFinalStatus ( websocket ) ) . resolves . toBeUndefined ( ) ;
615
+ } ) ;
616
+
617
+ // how can I mock a websocket server to stay in CONNECTING state
618
+ it ( 'should timeout if websocket stay in CONNECTING state' , async ( ) => {
619
+ const provider = new GoFeatureFlagWebProvider ( { endpoint : 'http://localhost:1031' , apiTimeout : 1000 } ) ;
620
+ await provider . initialize ( { targetingKey : 'user-key' } ) ;
621
+ const websocket = new MockWebSocketConnectingState ( websocketEndpoint ) ;
622
+
623
+ // Now you can test the behavior when the WebSocket is in CONNECTING state
624
+ await expect ( provider . waitWebsocketFinalStatus ( websocket ) ) . rejects . toBe (
625
+ 'timeout of 1000 ms reached when initializing the websocket' ,
626
+ ) ;
627
+ } ) ;
609
628
} ) ;
629
+
630
+ class MockWebSocketConnectingState extends WebSocket {
631
+ constructor ( url : string , protocols ?: string | string [ ] ) {
632
+ super ( url , protocols ) ;
633
+ }
634
+
635
+ get readyState ( ) {
636
+ return WebSocket . CONNECTING ;
637
+ }
638
+
639
+ set onopen ( _ : { ( this : WebSocket , event : Event ) : void ; ( ) : void } ) {
640
+ // Do nothing to prevent setting the onopen handler
641
+ }
642
+
643
+ set onclose ( _ : { ( ) : Promise < void > ; ( ) : void } ) {
644
+ // Do nothing to prevent setting the onclose handler
645
+ }
646
+
647
+ addEventListener (
648
+ type : string ,
649
+ listener : EventListenerOrEventListenerObject ,
650
+ options ?: boolean | AddEventListenerOptions ,
651
+ ) : void {
652
+ if ( type !== 'open' && type !== 'close' ) {
653
+ super . addEventListener ( type , listener , options ) ;
654
+ }
655
+ }
656
+ }
0 commit comments