@@ -14,13 +14,18 @@ describe('React hooks DevTools integration', () => {
1414 let React ;
1515 let ReactDebugTools ;
1616 let ReactTestRenderer ;
17+ let Scheduler ;
1718 let act ;
1819 let overrideHookState ;
20+ let scheduleUpdate ;
21+ let setSuspenseHandler ;
1922
2023 beforeEach ( ( ) => {
2124 global . __REACT_DEVTOOLS_GLOBAL_HOOK__ = {
2225 inject : injected => {
2326 overrideHookState = injected . overrideHookState ;
27+ scheduleUpdate = injected . scheduleUpdate ;
28+ setSuspenseHandler = injected . setSuspenseHandler ;
2429 } ,
2530 supportsFiber : true ,
2631 onCommitFiberRoot : ( ) => { } ,
@@ -32,6 +37,7 @@ describe('React hooks DevTools integration', () => {
3237 React = require ( 'react' ) ;
3338 ReactDebugTools = require ( 'react-debug-tools' ) ;
3439 ReactTestRenderer = require ( 'react-test-renderer' ) ;
40+ Scheduler = require ( 'scheduler' ) ;
3541
3642 act = ReactTestRenderer . act ;
3743 } ) ;
@@ -173,4 +179,112 @@ describe('React hooks DevTools integration', () => {
173179 } ) ;
174180 }
175181 } ) ;
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+ } ) ;
176290} ) ;
0 commit comments