@@ -14,13 +14,18 @@ describe('React hooks DevTools integration', () => {
14
14
let React ;
15
15
let ReactDebugTools ;
16
16
let ReactTestRenderer ;
17
+ let Scheduler ;
17
18
let act ;
18
19
let overrideHookState ;
20
+ let scheduleUpdate ;
21
+ let setSuspenseHandler ;
19
22
20
23
beforeEach ( ( ) => {
21
24
global . __REACT_DEVTOOLS_GLOBAL_HOOK__ = {
22
25
inject : injected => {
23
26
overrideHookState = injected . overrideHookState ;
27
+ scheduleUpdate = injected . scheduleUpdate ;
28
+ setSuspenseHandler = injected . setSuspenseHandler ;
24
29
} ,
25
30
supportsFiber : true ,
26
31
onCommitFiberRoot : ( ) => { } ,
@@ -32,6 +37,7 @@ describe('React hooks DevTools integration', () => {
32
37
React = require ( 'react' ) ;
33
38
ReactDebugTools = require ( 'react-debug-tools' ) ;
34
39
ReactTestRenderer = require ( 'react-test-renderer' ) ;
40
+ Scheduler = require ( 'scheduler' ) ;
35
41
36
42
act = ReactTestRenderer . act ;
37
43
} ) ;
@@ -173,4 +179,112 @@ describe('React hooks DevTools integration', () => {
173
179
} ) ;
174
180
}
175
181
} ) ;
182
+
183
+ it ( 'should support overriding suspense in sync mode' , ( ) => {
184
+ if ( __DEV__ ) {
185
+ // Lock the first render
186
+ setSuspenseHandler ( ( ) => true ) ;
187
+ }
188
+
189
+ function MyComponent ( ) {
190
+ return 'Done' ;
191
+ }
192
+
193
+ const renderer = ReactTestRenderer . create (
194
+ < div >
195
+ < React . Suspense fallback = { 'Loading' } >
196
+ < MyComponent />
197
+ </ React . Suspense >
198
+ </ div > ,
199
+ ) ;
200
+ const fiber = renderer . root . _currentFiber ( ) . child ;
201
+ if ( __DEV__ ) {
202
+ // First render was locked
203
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
204
+ scheduleUpdate ( fiber ) ; // Re-render
205
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
206
+
207
+ // Release the lock
208
+ setSuspenseHandler ( ( ) => false ) ;
209
+ scheduleUpdate ( fiber ) ; // Re-render
210
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
211
+ scheduleUpdate ( fiber ) ; // Re-render
212
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
213
+
214
+ // Lock again
215
+ setSuspenseHandler ( ( ) => true ) ;
216
+ scheduleUpdate ( fiber ) ; // Re-render
217
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
218
+
219
+ // Release the lock again
220
+ setSuspenseHandler ( ( ) => false ) ;
221
+ scheduleUpdate ( fiber ) ; // Re-render
222
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
223
+
224
+ // Ensure it checks specific fibers.
225
+ setSuspenseHandler ( f => f === fiber || f === fiber . alternate ) ;
226
+ scheduleUpdate ( fiber ) ; // Re-render
227
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
228
+ setSuspenseHandler ( f => f !== fiber && f !== fiber . alternate ) ;
229
+ scheduleUpdate ( fiber ) ; // Re-render
230
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
231
+ } else {
232
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
233
+ }
234
+ } ) ;
235
+
236
+ it ( 'should support overriding suspense in concurrent mode' , ( ) => {
237
+ if ( __DEV__ ) {
238
+ // Lock the first render
239
+ setSuspenseHandler ( ( ) => true ) ;
240
+ }
241
+
242
+ function MyComponent ( ) {
243
+ return 'Done' ;
244
+ }
245
+
246
+ const renderer = ReactTestRenderer . create (
247
+ < div >
248
+ < React . Suspense fallback = { 'Loading' } >
249
+ < MyComponent />
250
+ </ React . Suspense >
251
+ </ div > ,
252
+ { unstable_isConcurrent : true } ,
253
+ ) ;
254
+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
255
+ const fiber = renderer . root . _currentFiber ( ) . child ;
256
+ if ( __DEV__ ) {
257
+ // First render was locked
258
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
259
+ scheduleUpdate ( fiber ) ; // Re-render
260
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
261
+
262
+ // Release the lock
263
+ setSuspenseHandler ( ( ) => false ) ;
264
+ scheduleUpdate ( fiber ) ; // Re-render
265
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
266
+ scheduleUpdate ( fiber ) ; // Re-render
267
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
268
+
269
+ // Lock again
270
+ setSuspenseHandler ( ( ) => true ) ;
271
+ scheduleUpdate ( fiber ) ; // Re-render
272
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
273
+
274
+ // Release the lock again
275
+ setSuspenseHandler ( ( ) => false ) ;
276
+ scheduleUpdate ( fiber ) ; // Re-render
277
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
278
+
279
+ // Ensure it checks specific fibers.
280
+ setSuspenseHandler ( f => f === fiber || f === fiber . alternate ) ;
281
+ scheduleUpdate ( fiber ) ; // Re-render
282
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Loading' ] ) ;
283
+ setSuspenseHandler ( f => f !== fiber && f !== fiber . alternate ) ;
284
+ scheduleUpdate ( fiber ) ; // Re-render
285
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
286
+ } else {
287
+ expect ( renderer . toJSON ( ) . children ) . toEqual ( [ 'Done' ] ) ;
288
+ }
289
+ } ) ;
176
290
} ) ;
0 commit comments