@@ -2514,6 +2514,215 @@ describe('ReactSuspenseWithNoopRenderer', () => {
25142514 } ) ;
25152515 } ) ;
25162516
2517+ describe . only ( 'delays transitions when using React.startTranistion' , ( ) => {
2518+ // @gate experimental
2519+ it ( 'top level render' , async ( ) => {
2520+ function App ( { page} ) {
2521+ return (
2522+ < Suspense fallback = { < Text text = "Loading..." /> } >
2523+ < AsyncText text = { page } ms = { 5000 } />
2524+ </ Suspense >
2525+ ) ;
2526+ }
2527+
2528+ // Initial render.
2529+ React . unstable_startTransition ( ( ) => ReactNoop . render ( < App page = "A" /> ) ) ;
2530+
2531+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
2532+ // Only a short time is needed to unsuspend the initial loading state.
2533+ Scheduler . unstable_advanceTime ( 400 ) ;
2534+ await advanceTimers ( 400 ) ;
2535+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
2536+
2537+ // Later we load the data.
2538+ Scheduler . unstable_advanceTime ( 5000 ) ;
2539+ await advanceTimers ( 5000 ) ;
2540+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
2541+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
2542+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2543+
2544+ // Start transition.
2545+ React . unstable_startTransition ( ( ) => ReactNoop . render ( < App page = "B" /> ) ) ;
2546+
2547+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
2548+ Scheduler . unstable_advanceTime ( 2999 ) ;
2549+ await advanceTimers ( 2999 ) ;
2550+ // Since the timeout is infinite (or effectively infinite),
2551+ // we have still not yet flushed the loading state.
2552+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2553+
2554+ // Later we load the data.
2555+ Scheduler . unstable_advanceTime ( 3000 ) ;
2556+ await advanceTimers ( 3000 ) ;
2557+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
2558+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
2559+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
2560+
2561+ // Start a long (infinite) transition.
2562+ React . unstable_startTransition ( ( ) => ReactNoop . render ( < App page = "C" /> ) ) ;
2563+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [C]' , 'Loading...' ] ) ;
2564+
2565+ // Advance past the current (effectively) infinite timeout.
2566+ // This is enforcing temporary behavior until it's truly infinite.
2567+ Scheduler . unstable_advanceTime ( 100000 ) ;
2568+ await advanceTimers ( 100000 ) ;
2569+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
2570+ hiddenSpan ( 'B' ) ,
2571+ span ( 'Loading...' ) ,
2572+ ] ) ;
2573+ } ) ;
2574+
2575+ // @gate experimental
2576+ it ( 'hooks' , async ( ) => {
2577+ let transitionToPage ;
2578+ function App ( ) {
2579+ const [ page , setPage ] = React . useState ( 'none' ) ;
2580+ transitionToPage = setPage ;
2581+ if ( page === 'none' ) {
2582+ return null ;
2583+ }
2584+ return (
2585+ < Suspense fallback = { < Text text = "Loading..." /> } >
2586+ < AsyncText text = { page } ms = { 5000 } />
2587+ </ Suspense >
2588+ ) ;
2589+ }
2590+
2591+ ReactNoop . render ( < App /> ) ;
2592+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
2593+
2594+ // Initial render.
2595+ await ReactNoop . act ( async ( ) => {
2596+ React . unstable_startTransition ( ( ) => transitionToPage ( 'A' ) ) ;
2597+
2598+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
2599+ // Only a short time is needed to unsuspend the initial loading state.
2600+ Scheduler . unstable_advanceTime ( 400 ) ;
2601+ await advanceTimers ( 400 ) ;
2602+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
2603+ } ) ;
2604+
2605+ // Later we load the data.
2606+ Scheduler . unstable_advanceTime ( 5000 ) ;
2607+ await advanceTimers ( 5000 ) ;
2608+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
2609+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
2610+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2611+
2612+ // Start transition.
2613+ await ReactNoop . act ( async ( ) => {
2614+ React . unstable_startTransition ( ( ) => transitionToPage ( 'B' ) ) ;
2615+
2616+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
2617+
2618+ Scheduler . unstable_advanceTime ( 2999 ) ;
2619+ await advanceTimers ( 2999 ) ;
2620+ // Since the timeout is infinite (or effectively infinite),
2621+ // we have still not yet flushed the loading state.
2622+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2623+ } ) ;
2624+
2625+ // Later we load the data.
2626+ Scheduler . unstable_advanceTime ( 3000 ) ;
2627+ await advanceTimers ( 3000 ) ;
2628+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
2629+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
2630+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
2631+
2632+ // Start a long (infinite) transition.
2633+ await ReactNoop . act ( async ( ) => {
2634+ React . unstable_startTransition ( ( ) => transitionToPage ( 'C' ) ) ;
2635+
2636+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [C]' , 'Loading...' ] ) ;
2637+
2638+ // Advance past the current effectively infinite timeout.
2639+ // This is enforcing temporary behavior until it's truly infinite.
2640+ Scheduler . unstable_advanceTime ( 100000 ) ;
2641+ await advanceTimers ( 100000 ) ;
2642+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
2643+ hiddenSpan ( 'B' ) ,
2644+ span ( 'Loading...' ) ,
2645+ ] ) ;
2646+ } ) ;
2647+ } ) ;
2648+
2649+ // @gate experimental
2650+ it ( 'classes' , async ( ) => {
2651+ let transitionToPage ;
2652+ class App extends React . Component {
2653+ state = { page : 'none' } ;
2654+ render ( ) {
2655+ transitionToPage = page => this . setState ( { page} ) ;
2656+ const page = this . state . page ;
2657+ if ( page === 'none' ) {
2658+ return null ;
2659+ }
2660+ return (
2661+ < Suspense fallback = { < Text text = "Loading..." /> } >
2662+ < AsyncText text = { page } ms = { 5000 } />
2663+ </ Suspense >
2664+ ) ;
2665+ }
2666+ }
2667+
2668+ ReactNoop . render ( < App /> ) ;
2669+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
2670+
2671+ // Initial render.
2672+ await ReactNoop . act ( async ( ) => {
2673+ React . unstable_startTransition ( ( ) => transitionToPage ( 'A' ) ) ;
2674+
2675+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
2676+ // Only a short time is needed to unsuspend the initial loading state.
2677+ Scheduler . unstable_advanceTime ( 400 ) ;
2678+ await advanceTimers ( 400 ) ;
2679+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
2680+ } ) ;
2681+
2682+ // Later we load the data.
2683+ Scheduler . unstable_advanceTime ( 5000 ) ;
2684+ await advanceTimers ( 5000 ) ;
2685+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
2686+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
2687+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2688+
2689+ // Start transition.
2690+ await ReactNoop . act ( async ( ) => {
2691+ React . unstable_startTransition ( ( ) => transitionToPage ( 'B' ) ) ;
2692+
2693+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
2694+ Scheduler . unstable_advanceTime ( 2999 ) ;
2695+ await advanceTimers ( 2999 ) ;
2696+ // Since the timeout is infinite (or effectively infinite),
2697+ // we have still not yet flushed the loading state.
2698+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
2699+ } ) ;
2700+
2701+ // Later we load the data.
2702+ Scheduler . unstable_advanceTime ( 3000 ) ;
2703+ await advanceTimers ( 3000 ) ;
2704+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
2705+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
2706+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
2707+
2708+ // Start a long (infinite) transition.
2709+ await ReactNoop . act ( async ( ) => {
2710+ React . unstable_startTransition ( ( ) => transitionToPage ( 'C' ) ) ;
2711+
2712+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [C]' , 'Loading...' ] ) ;
2713+
2714+ // Advance past the current effectively infinite timeout.
2715+ // This is enforcing temporary behavior until it's truly infinite.
2716+ Scheduler . unstable_advanceTime ( 100000 ) ;
2717+ await advanceTimers ( 100000 ) ;
2718+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
2719+ hiddenSpan ( 'B' ) ,
2720+ span ( 'Loading...' ) ,
2721+ ] ) ;
2722+ } ) ;
2723+ } ) ;
2724+ } ) ;
2725+
25172726 // @gate experimental
25182727 it ( 'disables suspense config when nothing is passed to withSuspenseConfig' , async ( ) => {
25192728 function App ( { page} ) {
0 commit comments