@@ -2514,6 +2514,215 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2514
2514
} ) ;
2515
2515
} ) ;
2516
2516
2517
+ describe ( '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
+
2517
2726
// @gate experimental
2518
2727
it ( 'disables suspense config when nothing is passed to withSuspenseConfig' , async ( ) => {
2519
2728
function App ( { page} ) {
0 commit comments