@@ -1701,4 +1701,282 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1701
1701
1702
1702
expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading A...' ) ] ) ;
1703
1703
} ) ;
1704
+
1705
+ describe ( 'delays transitions when there a suspense config is supplied' , ( ) => {
1706
+ const SUSPENSE_CONFIG = {
1707
+ timeoutMs : 2000 ,
1708
+ } ;
1709
+
1710
+ it ( 'top level render' , async ( ) => {
1711
+ function App ( { page} ) {
1712
+ return (
1713
+ < Suspense fallback = { < Text text = "Loading..." /> } >
1714
+ < AsyncText text = { page } ms = { 5000 } />
1715
+ </ Suspense >
1716
+ ) ;
1717
+ }
1718
+
1719
+ // Initial render.
1720
+ React . unstable_withSuspenseConfig (
1721
+ ( ) => ReactNoop . render ( < App page = "A" /> ) ,
1722
+ SUSPENSE_CONFIG ,
1723
+ ) ;
1724
+
1725
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
1726
+ // Only a short time is needed to unsuspend the initial loading state.
1727
+ Scheduler . advanceTime ( 400 ) ;
1728
+ await advanceTimers ( 400 ) ;
1729
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
1730
+
1731
+ // Later we load the data.
1732
+ Scheduler . advanceTime ( 5000 ) ;
1733
+ await advanceTimers ( 5000 ) ;
1734
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
1735
+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
1736
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1737
+
1738
+ // Start transition.
1739
+ React . unstable_withSuspenseConfig (
1740
+ ( ) => ReactNoop . render ( < App page = "B" /> ) ,
1741
+ SUSPENSE_CONFIG ,
1742
+ ) ;
1743
+
1744
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
1745
+ Scheduler . advanceTime ( 1000 ) ;
1746
+ await advanceTimers ( 1000 ) ;
1747
+ // Even after a second, we have still not yet flushed the loading state.
1748
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1749
+ Scheduler . advanceTime ( 1100 ) ;
1750
+ await advanceTimers ( 1100 ) ;
1751
+ // After the timeout, we do show the loading state.
1752
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
1753
+ hiddenSpan ( 'A' ) ,
1754
+ span ( 'Loading...' ) ,
1755
+ ] ) ;
1756
+ // Later we load the data.
1757
+ Scheduler . advanceTime ( 3000 ) ;
1758
+ await advanceTimers ( 3000 ) ;
1759
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
1760
+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
1761
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1762
+ } ) ;
1763
+
1764
+ it ( 'hooks' , async ( ) => {
1765
+ let transitionToPage ;
1766
+ function App ( ) {
1767
+ let [ page , setPage ] = React . useState ( 'none' ) ;
1768
+ transitionToPage = setPage ;
1769
+ if ( page === 'none' ) {
1770
+ return null ;
1771
+ }
1772
+ return (
1773
+ < Suspense fallback = { < Text text = "Loading..." /> } >
1774
+ < AsyncText text = { page } ms = { 5000 } />
1775
+ </ Suspense >
1776
+ ) ;
1777
+ }
1778
+
1779
+ ReactNoop . render ( < App /> ) ;
1780
+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
1781
+
1782
+ // Initial render.
1783
+ await ReactNoop . act ( async ( ) => {
1784
+ React . unstable_withSuspenseConfig (
1785
+ ( ) => transitionToPage ( 'A' ) ,
1786
+ SUSPENSE_CONFIG ,
1787
+ ) ;
1788
+
1789
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
1790
+ // Only a short time is needed to unsuspend the initial loading state.
1791
+ Scheduler . advanceTime ( 400 ) ;
1792
+ await advanceTimers ( 400 ) ;
1793
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
1794
+ } ) ;
1795
+
1796
+ // Later we load the data.
1797
+ Scheduler . advanceTime ( 5000 ) ;
1798
+ await advanceTimers ( 5000 ) ;
1799
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
1800
+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
1801
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1802
+
1803
+ // Start transition.
1804
+ await ReactNoop . act ( async ( ) => {
1805
+ React . unstable_withSuspenseConfig (
1806
+ ( ) => transitionToPage ( 'B' ) ,
1807
+ SUSPENSE_CONFIG ,
1808
+ ) ;
1809
+
1810
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
1811
+ Scheduler . advanceTime ( 1000 ) ;
1812
+ await advanceTimers ( 1000 ) ;
1813
+ // Even after a second, we have still not yet flushed the loading state.
1814
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1815
+ Scheduler . advanceTime ( 1100 ) ;
1816
+ await advanceTimers ( 1100 ) ;
1817
+ // After the timeout, we do show the loading state.
1818
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
1819
+ hiddenSpan ( 'A' ) ,
1820
+ span ( 'Loading...' ) ,
1821
+ ] ) ;
1822
+ } ) ;
1823
+ // Later we load the data.
1824
+ Scheduler . advanceTime ( 3000 ) ;
1825
+ await advanceTimers ( 3000 ) ;
1826
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
1827
+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
1828
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1829
+ } ) ;
1830
+
1831
+ it ( 'classes' , async ( ) => {
1832
+ let transitionToPage ;
1833
+ class App extends React . Component {
1834
+ state = { page : 'none' } ;
1835
+ render ( ) {
1836
+ transitionToPage = page => this . setState ( { page} ) ;
1837
+ let page = this . state . page ;
1838
+ if ( page === 'none' ) {
1839
+ return null ;
1840
+ }
1841
+ return (
1842
+ < Suspense fallback = { < Text text = "Loading..." /> } >
1843
+ < AsyncText text = { page } ms = { 5000 } />
1844
+ </ Suspense >
1845
+ ) ;
1846
+ }
1847
+ }
1848
+
1849
+ ReactNoop . render ( < App /> ) ;
1850
+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
1851
+
1852
+ // Initial render.
1853
+ await ReactNoop . act ( async ( ) => {
1854
+ React . unstable_withSuspenseConfig (
1855
+ ( ) => transitionToPage ( 'A' ) ,
1856
+ SUSPENSE_CONFIG ,
1857
+ ) ;
1858
+
1859
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
1860
+ // Only a short time is needed to unsuspend the initial loading state.
1861
+ Scheduler . advanceTime ( 400 ) ;
1862
+ await advanceTimers ( 400 ) ;
1863
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'Loading...' ) ] ) ;
1864
+ } ) ;
1865
+
1866
+ // Later we load the data.
1867
+ Scheduler . advanceTime ( 5000 ) ;
1868
+ await advanceTimers ( 5000 ) ;
1869
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
1870
+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
1871
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1872
+
1873
+ // Start transition.
1874
+ await ReactNoop . act ( async ( ) => {
1875
+ React . unstable_withSuspenseConfig (
1876
+ ( ) => transitionToPage ( 'B' ) ,
1877
+ SUSPENSE_CONFIG ,
1878
+ ) ;
1879
+
1880
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
1881
+ Scheduler . advanceTime ( 1000 ) ;
1882
+ await advanceTimers ( 1000 ) ;
1883
+ // Even after a second, we have still not yet flushed the loading state.
1884
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1885
+ Scheduler . advanceTime ( 1100 ) ;
1886
+ await advanceTimers ( 1100 ) ;
1887
+ // After the timeout, we do show the loading state.
1888
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
1889
+ hiddenSpan ( 'A' ) ,
1890
+ span ( 'Loading...' ) ,
1891
+ ] ) ;
1892
+ } ) ;
1893
+ // Later we load the data.
1894
+ Scheduler . advanceTime ( 3000 ) ;
1895
+ await advanceTimers ( 3000 ) ;
1896
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
1897
+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
1898
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1899
+ } ) ;
1900
+ } ) ;
1901
+
1902
+ it ( 'disables suspense config when nothing is passed to withSuspenseConfig' , async ( ) => {
1903
+ function App ( { page} ) {
1904
+ return (
1905
+ < Fragment >
1906
+ < Suspense fallback = { < Text text = "Loading..." /> } >
1907
+ < AsyncText text = { page } ms = { 2000 } />
1908
+ </ Suspense >
1909
+ </ Fragment >
1910
+ ) ;
1911
+ }
1912
+
1913
+ // Initial render.
1914
+ ReactNoop . render ( < App page = "A" /> ) ;
1915
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [A]' , 'Loading...' ] ) ;
1916
+ Scheduler . advanceTime ( 2000 ) ;
1917
+ await advanceTimers ( 2000 ) ;
1918
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [A]' ] ) ;
1919
+ expect ( Scheduler ) . toFlushAndYield ( [ 'A' ] ) ;
1920
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1921
+
1922
+ // Start transition.
1923
+ React . unstable_withSuspenseConfig (
1924
+ ( ) => {
1925
+ // When we schedule an inner transition without a suspense config
1926
+ // so it should only suspend for a short time.
1927
+ React . unstable_withSuspenseConfig ( ( ) =>
1928
+ ReactNoop . render ( < App page = "B" /> ) ,
1929
+ ) ;
1930
+ } ,
1931
+ { timeoutMs : 2000 } ,
1932
+ ) ;
1933
+
1934
+ expect ( Scheduler ) . toFlushAndYield ( [ 'Suspend! [B]' , 'Loading...' ] ) ;
1935
+ // Suspended
1936
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'A' ) ] ) ;
1937
+ Scheduler . advanceTime ( 500 ) ;
1938
+ await advanceTimers ( 500 ) ;
1939
+ // Committed loading state.
1940
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
1941
+ hiddenSpan ( 'A' ) ,
1942
+ span ( 'Loading...' ) ,
1943
+ ] ) ;
1944
+
1945
+ Scheduler . advanceTime ( 2000 ) ;
1946
+ await advanceTimers ( 2000 ) ;
1947
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
1948
+ expect ( Scheduler ) . toFlushAndYield ( [ 'B' ] ) ;
1949
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1950
+
1951
+ React . unstable_withSuspenseConfig (
1952
+ ( ) => {
1953
+ // First we schedule an inner unrelated update.
1954
+ React . unstable_withSuspenseConfig ( ( ) =>
1955
+ ReactNoop . render ( < App page = "B" unrelated = { true } /> ) ,
1956
+ ) ;
1957
+ // Then we schedule another transition to a slow page,
1958
+ // but at this scope we should suspend for longer.
1959
+ Scheduler . unstable_next ( ( ) => ReactNoop . render ( < App page = "C" /> ) ) ;
1960
+ } ,
1961
+ { timeoutMs : 2000 } ,
1962
+ ) ;
1963
+ expect ( Scheduler ) . toFlushAndYield ( [
1964
+ 'Suspend! [C]' ,
1965
+ 'Loading...' ,
1966
+ 'Suspend! [C]' ,
1967
+ 'Loading...' ,
1968
+ ] ) ;
1969
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1970
+ Scheduler . advanceTime ( 1200 ) ;
1971
+ await advanceTimers ( 1200 ) ;
1972
+ // Even after a second, we have still not yet flushed the loading state.
1973
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ span ( 'B' ) ] ) ;
1974
+ Scheduler . advanceTime ( 1200 ) ;
1975
+ await advanceTimers ( 1200 ) ;
1976
+ // After the two second timeout we show the loading state.
1977
+ expect ( ReactNoop . getChildren ( ) ) . toEqual ( [
1978
+ hiddenSpan ( 'B' ) ,
1979
+ span ( 'Loading...' ) ,
1980
+ ] ) ;
1981
+ } ) ;
1704
1982
} ) ;
0 commit comments