@@ -22,7 +22,7 @@ import { render, renderHook, screen, waitFor } from '@testing-library/react';
22
22
import '@testing-library/jest-dom' ;
23
23
24
24
import { OptimizelyProvider } from './Provider' ;
25
- import { OnReadyResult , ReactSDKClient , VariableValuesObject } from './client' ;
25
+ import { NotReadyReason , OnReadyResult , ReactSDKClient , VariableValuesObject } from './client' ;
26
26
import { useExperiment , useFeature , useDecision , useTrackEvent , hooksLogger } from './hooks' ;
27
27
import { OptimizelyDecision } from './utils' ;
28
28
const defaultDecision : OptimizelyDecision = {
@@ -62,7 +62,7 @@ const mockFeatureVariables: VariableValuesObject = {
62
62
foo : 'bar' ,
63
63
} ;
64
64
65
- describe . skip ( 'hooks' , ( ) => {
65
+ describe ( 'hooks' , ( ) => {
66
66
let activateMock : jest . Mock ;
67
67
let featureVariables : VariableValuesObject ;
68
68
let getOnReadyPromise : any ;
@@ -176,52 +176,79 @@ describe.skip('hooks', () => {
176
176
it ( 'should return a variation when activate returns a variation' , async ( ) => {
177
177
activateMock . mockReturnValue ( '12345' ) ;
178
178
179
- const { container } = render (
179
+ render (
180
180
< OptimizelyProvider optimizely = { optimizelyMock } >
181
181
< MyExperimentComponent />
182
182
</ OptimizelyProvider >
183
183
) ;
184
- await optimizelyMock . onReady ( ) ;
185
184
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( '12345|true|false' ) ) ;
186
185
} ) ;
187
186
188
187
it ( 'should return null when activate returns null' , async ( ) => {
189
188
activateMock . mockReturnValue ( null ) ;
190
189
featureVariables = { } ;
191
- const { container } = render (
190
+ render (
192
191
< OptimizelyProvider optimizely = { optimizelyMock } >
193
192
< MyExperimentComponent />
194
193
</ OptimizelyProvider >
195
194
) ;
196
- await optimizelyMock . onReady ( ) ;
197
195
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|true|false' ) ) ;
198
196
} ) ;
199
197
200
198
it ( 'should respect the timeout option passed' , async ( ) => {
201
199
activateMock . mockReturnValue ( null ) ;
200
+ mockDelay = 100 ;
202
201
readySuccess = false ;
202
+ // Todo: getOnReadyPromise might be moved in the top later
203
+ getOnReadyPromise = ( { timeout = 0 } : any ) : Promise < OnReadyResult > => {
204
+ const timeoutPromise = new Promise < OnReadyResult > ( ( resolve ) => {
205
+ setTimeout (
206
+ ( ) => {
207
+ resolve ( {
208
+ success : false ,
209
+ reason : NotReadyReason . TIMEOUT ,
210
+ dataReadyPromise : new Promise ( ( r ) =>
211
+ setTimeout (
212
+ ( ) =>
213
+ r ( {
214
+ success : readySuccess ,
215
+ } ) ,
216
+ mockDelay
217
+ )
218
+ ) ,
219
+ } ) ;
220
+ } ,
221
+ timeout || mockDelay + 1
222
+ ) ;
223
+ } ) ;
224
+
225
+ const clientAndUserReadyPromise = new Promise < OnReadyResult > ( ( resolve ) => {
226
+ setTimeout ( ( ) => {
227
+ resolve ( {
228
+ success : readySuccess ,
229
+ } ) ;
230
+ } , mockDelay ) ;
231
+ } ) ;
232
+
233
+ return Promise . race ( [ clientAndUserReadyPromise , timeoutPromise ] ) ;
234
+ } ;
203
235
204
236
render (
205
237
< OptimizelyProvider optimizely = { optimizelyMock } >
206
- < MyExperimentComponent options = { { timeout : mockDelay } } />
238
+ < MyExperimentComponent options = { { timeout : mockDelay - 10 } } />
207
239
</ OptimizelyProvider >
208
240
) ;
209
-
210
- await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|false|false' ) ) ; // initial render
211
-
212
- await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|false|true' ) ) ; // when didTimeout
213
-
214
- // Simulate datafile fetch completing after timeout has already passed
215
- // Activate now returns a variation
241
+ expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|false|false' ) ; // initial render
242
+ readySuccess = true ;
216
243
activateMock . mockReturnValue ( '12345' ) ;
217
- await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( '12345|true|true' ) ) ; // when clientReady
244
+ // When timeout is reached, but dataReadyPromise is resolved later with the variation
245
+ await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( '12345|true|true' ) ) ;
218
246
} ) ;
219
247
220
248
it ( 'should gracefully handle the client promise rejecting after timeout' , async ( ) => {
221
- jest . useFakeTimers ( ) ;
222
-
223
249
readySuccess = false ;
224
250
activateMock . mockReturnValue ( '12345' ) ;
251
+
225
252
getOnReadyPromise = ( ) : Promise < void > =>
226
253
new Promise ( ( _ , rej ) => setTimeout ( ( ) => rej ( REJECTION_REASON ) , mockDelay ) ) ;
227
254
@@ -231,11 +258,7 @@ describe.skip('hooks', () => {
231
258
</ OptimizelyProvider >
232
259
) ;
233
260
234
- jest . advanceTimersByTime ( mockDelay + 1 ) ;
235
-
236
261
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|false|false' ) ) ;
237
-
238
- jest . useRealTimers ( ) ;
239
262
} ) ;
240
263
241
264
it ( 'should re-render when the user attributes change using autoUpdate' , async ( ) => {
@@ -249,16 +272,14 @@ describe.skip('hooks', () => {
249
272
250
273
// TODO - Wrap this with async act() once we upgrade to React 16.9
251
274
// See https://github.com/facebook/react/issues/15379
252
- await optimizelyMock . onReady ( ) ;
253
275
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|true|false' ) ) ;
254
276
255
277
activateMock . mockReturnValue ( '12345' ) ;
256
278
// Simulate the user object changing
257
279
await act ( async ( ) => {
258
280
userUpdateCallbacks . forEach ( ( fn ) => fn ( ) ) ;
259
281
} ) ;
260
- // component.update();
261
- // await waitFor(() => expect(screen.getByTestId('result')).toHaveTextContent('12345|true|false');
282
+
262
283
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( '12345|true|false' ) ) ;
263
284
} ) ;
264
285
@@ -272,7 +293,6 @@ describe.skip('hooks', () => {
272
293
273
294
// // TODO - Wrap this with async act() once we upgrade to React 16.9
274
295
// // See https://github.com/facebook/react/issues/15379
275
- await optimizelyMock . onReady ( ) ;
276
296
await waitFor ( ( ) => expect ( screen . getByTestId ( 'result' ) ) . toHaveTextContent ( 'null|true|false' ) ) ;
277
297
278
298
activateMock . mockReturnValue ( '12345' ) ;
@@ -425,7 +445,7 @@ describe.skip('hooks', () => {
425
445
} ) ;
426
446
} ) ;
427
447
428
- describe ( 'useFeature' , ( ) => {
448
+ describe . skip ( 'useFeature' , ( ) => {
429
449
it ( 'should render true when the feature is enabled' , async ( ) => {
430
450
isFeatureEnabledMock . mockReturnValue ( true ) ;
431
451
@@ -676,7 +696,7 @@ describe.skip('hooks', () => {
676
696
} ) ;
677
697
} ) ;
678
698
679
- describe ( 'useDecision' , ( ) => {
699
+ describe . skip ( 'useDecision' , ( ) => {
680
700
it ( 'should render true when the flag is enabled' , async ( ) => {
681
701
decideMock . mockReturnValue ( {
682
702
...defaultDecision ,
0 commit comments