1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. describe('StoreStress (Legacy Mode)', () => {
    
  11.   let React;
    
  12.   let ReactDOM;
    
  13.   let act;
    
  14.   let bridge;
    
  15.   let store;
    
  16.   let print;
    
  17.   let legacyRender;
    
  18. 
    
  19.   beforeEach(() => {
    
  20.     bridge = global.bridge;
    
  21.     store = global.store;
    
  22.     store.collapseNodesByDefault = false;
    
  23. 
    
  24.     React = require('react');
    
  25.     ReactDOM = require('react-dom');
    
  26. 
    
  27.     const utils = require('./utils');
    
  28.     act = utils.act;
    
  29.     legacyRender = utils.legacyRender;
    
  30. 
    
  31.     print = require('./__serializers__/storeSerializer').print;
    
  32.   });
    
  33. 
    
  34.   // This is a stress test for the tree mount/update/unmount traversal.
    
  35.   // It renders different trees that should produce the same output.
    
  36.   // @reactVersion >= 16.9
    
  37.   it('should handle a stress test with different tree operations (Legacy Mode)', () => {
    
  38.     let setShowX;
    
  39.     const A = () => 'a';
    
  40.     const B = () => 'b';
    
  41.     const C = () => {
    
  42.       // We'll be manually flipping this component back and forth in the test.
    
  43.       // We only do this for a single node in order to verify that DevTools
    
  44.       // can handle a subtree switching alternates while other subtrees are memoized.
    
  45.       const [showX, _setShowX] = React.useState(false);
    
  46.       setShowX = _setShowX;
    
  47.       return showX ? <X /> : 'c';
    
  48.     };
    
  49.     const D = () => 'd';
    
  50.     const E = () => 'e';
    
  51.     const X = () => 'x';
    
  52.     const a = <A key="a" />;
    
  53.     const b = <B key="b" />;
    
  54.     const c = <C key="c" />;
    
  55.     const d = <D key="d" />;
    
  56.     const e = <E key="e" />;
    
  57. 
    
  58.     function Parent({children}) {
    
  59.       return children;
    
  60.     }
    
  61. 
    
  62.     // 1. Render a normal version of [a, b, c, d, e].
    
  63.     let container = document.createElement('div');
    
  64.     act(() => legacyRender(<Parent>{[a, b, c, d, e]}</Parent>, container));
    
  65.     expect(store).toMatchInlineSnapshot(`
    
  66.       [root]
    
  67.         ▾ <Parent>
    
  68.             <A key="a">
    
  69.             <B key="b">
    
  70.             <C key="c">
    
  71.             <D key="d">
    
  72.             <E key="e">
    
  73.     `);
    
  74.     expect(container.textContent).toMatch('abcde');
    
  75.     const snapshotForABCDE = print(store);
    
  76. 
    
  77.     // 2. Render a version where <C /> renders an <X /> child instead of 'c'.
    
  78.     // This is how we'll test an update to a single component.
    
  79.     act(() => {
    
  80.       setShowX(true);
    
  81.     });
    
  82.     expect(store).toMatchInlineSnapshot(`
    
  83.       [root]
    
  84.         ▾ <Parent>
    
  85.             <A key="a">
    
  86.             <B key="b">
    
  87.           ▾ <C key="c">
    
  88.               <X>
    
  89.             <D key="d">
    
  90.             <E key="e">
    
  91.     `);
    
  92.     expect(container.textContent).toMatch('abxde');
    
  93.     const snapshotForABXDE = print(store);
    
  94. 
    
  95.     // 3. Verify flipping it back produces the original result.
    
  96.     act(() => {
    
  97.       setShowX(false);
    
  98.     });
    
  99.     expect(container.textContent).toMatch('abcde');
    
  100.     expect(print(store)).toBe(snapshotForABCDE);
    
  101. 
    
  102.     // 4. Clean up.
    
  103.     act(() => ReactDOM.unmountComponentAtNode(container));
    
  104.     expect(print(store)).toBe('');
    
  105. 
    
  106.     // Now comes the interesting part.
    
  107.     // All of these cases are equivalent to [a, b, c, d, e] in output.
    
  108.     // We'll verify that DevTools produces the same snapshots for them.
    
  109.     // These cases are picked so that rendering them sequentially in the same
    
  110.     // container results in a combination of mounts, updates, unmounts, and reorders.
    
  111.     // prettier-ignore
    
  112.     const cases = [
    
  113.       [a, b, c, d, e],
    
  114.       [[a], b, c, d, e],
    
  115.       [[a, b], c, d, e],
    
  116.       [[a, b], c, [d, e]],
    
  117.       [[a, b], c, [d, '', e]],
    
  118.       [[a], b, c, d, [e]],
    
  119.       [a, b, [[c]], d, e],
    
  120.       [[a, ''], [b], [c], [d], [e]],
    
  121.       [a, b, [c, [d, ['', e]]]],
    
  122.       [a, b, c, d, e],
    
  123.       [<div key="0">{a}</div>, b, c, d, e],
    
  124.       [<div key="0">{a}{b}</div>, c, d, e],
    
  125.       [<div key="0">{a}{b}</div>, c, <div key="1">{d}{e}</div>],
    
  126.       [<div key="1">{a}{b}</div>, c, <div key="0">{d}{e}</div>],
    
  127.       [<div key="0">{a}{b}</div>, c, <div key="1">{d}{e}</div>],
    
  128.       [<div key="2">{a}{b}</div>, c, <div key="3">{d}{e}</div>],
    
  129.       [<span key="0">{a}</span>, b, c, d, [e]],
    
  130.       [a, b, <span key="0"><span>{c}</span></span>, d, e],
    
  131.       [<div key="0">{a}</div>, [b], <span key="1">{c}</span>, [d], <div key="2">{e}</div>],
    
  132.       [a, b, [c, <div key="0">{d}<span>{e}</span></div>], ''],
    
  133.       [a, [[]], b, c, [d, [[]], e]],
    
  134.       [[[a, b, c, d], e]],
    
  135.       [a, b, c, d, e],
    
  136.     ];
    
  137. 
    
  138.     // 5. Test fresh mount for each case.
    
  139.     for (let i = 0; i < cases.length; i++) {
    
  140.       // Ensure fresh mount.
    
  141.       container = document.createElement('div');
    
  142. 
    
  143.       // Verify mounting 'abcde'.
    
  144.       act(() => legacyRender(<Parent>{cases[i]}</Parent>, container));
    
  145.       expect(container.textContent).toMatch('abcde');
    
  146.       expect(print(store)).toEqual(snapshotForABCDE);
    
  147. 
    
  148.       // Verify switching to 'abxde'.
    
  149.       act(() => {
    
  150.         setShowX(true);
    
  151.       });
    
  152.       expect(container.textContent).toMatch('abxde');
    
  153.       expect(print(store)).toBe(snapshotForABXDE);
    
  154. 
    
  155.       // Verify switching back to 'abcde'.
    
  156.       act(() => {
    
  157.         setShowX(false);
    
  158.       });
    
  159.       expect(container.textContent).toMatch('abcde');
    
  160.       expect(print(store)).toBe(snapshotForABCDE);
    
  161. 
    
  162.       // Clean up.
    
  163.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  164.       expect(print(store)).toBe('');
    
  165.     }
    
  166. 
    
  167.     // 6. Verify *updates* by reusing the container between iterations.
    
  168.     // There'll be no unmounting until the very end.
    
  169.     container = document.createElement('div');
    
  170.     for (let i = 0; i < cases.length; i++) {
    
  171.       // Verify mounting 'abcde'.
    
  172.       act(() => legacyRender(<Parent>{cases[i]}</Parent>, container));
    
  173.       expect(container.textContent).toMatch('abcde');
    
  174.       expect(print(store)).toEqual(snapshotForABCDE);
    
  175. 
    
  176.       // Verify switching to 'abxde'.
    
  177.       act(() => {
    
  178.         setShowX(true);
    
  179.       });
    
  180.       expect(container.textContent).toMatch('abxde');
    
  181.       expect(print(store)).toBe(snapshotForABXDE);
    
  182. 
    
  183.       // Verify switching back to 'abcde'.
    
  184.       act(() => {
    
  185.         setShowX(false);
    
  186.       });
    
  187.       expect(container.textContent).toMatch('abcde');
    
  188.       expect(print(store)).toBe(snapshotForABCDE);
    
  189.       // Don't unmount. Reuse the container between iterations.
    
  190.     }
    
  191.     act(() => ReactDOM.unmountComponentAtNode(container));
    
  192.     expect(print(store)).toBe('');
    
  193.   });
    
  194. 
    
  195.   // @reactVersion >= 16.9
    
  196.   it('should handle stress test with reordering (Legacy Mode)', () => {
    
  197.     const A = () => 'a';
    
  198.     const B = () => 'b';
    
  199.     const C = () => 'c';
    
  200.     const D = () => 'd';
    
  201.     const E = () => 'e';
    
  202.     const a = <A key="a" />;
    
  203.     const b = <B key="b" />;
    
  204.     const c = <C key="c" />;
    
  205.     const d = <D key="d" />;
    
  206.     const e = <E key="e" />;
    
  207. 
    
  208.     // prettier-ignore
    
  209.     const steps = [
    
  210.       a,
    
  211.       b,
    
  212.       c,
    
  213.       d,
    
  214.       e,
    
  215.       [a],
    
  216.       [b],
    
  217.       [c],
    
  218.       [d],
    
  219.       [e],
    
  220.       [a, b],
    
  221.       [b, a],
    
  222.       [b, c],
    
  223.       [c, b],
    
  224.       [a, c],
    
  225.       [c, a],
    
  226.     ];
    
  227. 
    
  228.     const stepsSnapshot = [
    
  229.       `
    
  230.       [root]
    
  231.         ▾ <Root>
    
  232.             <A key="a">
    
  233.     `,
    
  234.       `
    
  235.       [root]
    
  236.         ▾ <Root>
    
  237.             <B key="b">
    
  238.     `,
    
  239.       `
    
  240.       [root]
    
  241.         ▾ <Root>
    
  242.             <C key="c">
    
  243.     `,
    
  244.       `
    
  245.       [root]
    
  246.         ▾ <Root>
    
  247.             <D key="d">
    
  248.       `,
    
  249.       `
    
  250.       [root]
    
  251.         ▾ <Root>
    
  252.             <E key="e">
    
  253.       `,
    
  254.       `
    
  255.       [root]
    
  256.         ▾ <Root>
    
  257.             <A key="a">
    
  258.       `,
    
  259.       `
    
  260.       [root]
    
  261.         ▾ <Root>
    
  262.             <B key="b">
    
  263.       `,
    
  264.       `
    
  265.       [root]
    
  266.         ▾ <Root>
    
  267.             <C key="c">
    
  268.       `,
    
  269.       `
    
  270.       [root]
    
  271.         ▾ <Root>
    
  272.             <D key="d">
    
  273.       `,
    
  274.       `
    
  275.       [root]
    
  276.         ▾ <Root>
    
  277.             <E key="e">
    
  278.       `,
    
  279.       `
    
  280.       [root]
    
  281.         ▾ <Root>
    
  282.             <A key="a">
    
  283.             <B key="b">
    
  284.       `,
    
  285.       `
    
  286.       [root]
    
  287.         ▾ <Root>
    
  288.             <B key="b">
    
  289.             <A key="a">
    
  290.       `,
    
  291.       `
    
  292.       [root]
    
  293.         ▾ <Root>
    
  294.             <B key="b">
    
  295.             <C key="c">
    
  296.       `,
    
  297.       `
    
  298.       [root]
    
  299.         ▾ <Root>
    
  300.             <C key="c">
    
  301.             <B key="b">
    
  302.       `,
    
  303.       `
    
  304.       [root]
    
  305.         ▾ <Root>
    
  306.             <A key="a">
    
  307.             <C key="c">
    
  308.       `,
    
  309.       `
    
  310.       [root]
    
  311.         ▾ <Root>
    
  312.             <C key="c">
    
  313.             <A key="a">
    
  314.       `,
    
  315.     ];
    
  316. 
    
  317.     const Root = ({children}) => {
    
  318.       return children;
    
  319.     };
    
  320. 
    
  321.     // 1. Capture the expected render result.
    
  322.     const snapshots = [];
    
  323.     let container = document.createElement('div');
    
  324.     for (let i = 0; i < steps.length; i++) {
    
  325.       act(() => legacyRender(<Root>{steps[i]}</Root>, container));
    
  326.       // We snapshot each step once so it doesn't regress.
    
  327.       expect(store).toMatchInlineSnapshot(stepsSnapshot[i]);
    
  328.       snapshots.push(print(store));
    
  329.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  330.       expect(print(store)).toBe('');
    
  331.     }
    
  332. 
    
  333.     // 2. Verify that we can update from every step to every other step and back.
    
  334.     for (let i = 0; i < steps.length; i++) {
    
  335.       for (let j = 0; j < steps.length; j++) {
    
  336.         container = document.createElement('div');
    
  337.         act(() => legacyRender(<Root>{steps[i]}</Root>, container));
    
  338.         expect(print(store)).toMatch(snapshots[i]);
    
  339.         act(() => legacyRender(<Root>{steps[j]}</Root>, container));
    
  340.         expect(print(store)).toMatch(snapshots[j]);
    
  341.         act(() => legacyRender(<Root>{steps[i]}</Root>, container));
    
  342.         expect(print(store)).toMatch(snapshots[i]);
    
  343.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  344.         expect(print(store)).toBe('');
    
  345.       }
    
  346.     }
    
  347. 
    
  348.     // 3. Same test as above, but this time we wrap children in a host component.
    
  349.     for (let i = 0; i < steps.length; i++) {
    
  350.       for (let j = 0; j < steps.length; j++) {
    
  351.         container = document.createElement('div');
    
  352.         act(() =>
    
  353.           legacyRender(
    
  354.             <Root>
    
  355.               <div>{steps[i]}</div>
    
  356.             </Root>,
    
  357.             container,
    
  358.           ),
    
  359.         );
    
  360.         expect(print(store)).toMatch(snapshots[i]);
    
  361.         act(() =>
    
  362.           legacyRender(
    
  363.             <Root>
    
  364.               <div>{steps[j]}</div>
    
  365.             </Root>,
    
  366.             container,
    
  367.           ),
    
  368.         );
    
  369.         expect(print(store)).toMatch(snapshots[j]);
    
  370.         act(() =>
    
  371.           legacyRender(
    
  372.             <Root>
    
  373.               <div>{steps[i]}</div>
    
  374.             </Root>,
    
  375.             container,
    
  376.           ),
    
  377.         );
    
  378.         expect(print(store)).toMatch(snapshots[i]);
    
  379.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  380.         expect(print(store)).toBe('');
    
  381.       }
    
  382.     }
    
  383.   });
    
  384. 
    
  385.   // @reactVersion >= 18.0
    
  386.   it('should handle a stress test for Suspense (Legacy Mode)', async () => {
    
  387.     const A = () => 'a';
    
  388.     const B = () => 'b';
    
  389.     const C = () => 'c';
    
  390.     const X = () => 'x';
    
  391.     const Y = () => 'y';
    
  392.     const Z = () => 'z';
    
  393.     const a = <A key="a" />;
    
  394.     const b = <B key="b" />;
    
  395.     const c = <C key="c" />;
    
  396.     const z = <Z key="z" />;
    
  397. 
    
  398.     // prettier-ignore
    
  399.     const steps = [
    
  400.       a,
    
  401.       [a],
    
  402.       [a, b, c],
    
  403.       [c, b, a],
    
  404.       [c, null, a],
    
  405.       <React.Fragment>{c}{a}</React.Fragment>,
    
  406.       <div>{c}{a}</div>,
    
  407.       <div><span>{a}</span>{b}</div>,
    
  408.       [[a]],
    
  409.       null,
    
  410.       b,
    
  411.       a,
    
  412.     ];
    
  413. 
    
  414.     const stepsSnapshot = [
    
  415.       `
    
  416.         [root]
    
  417.           ▾ <Root>
    
  418.               <X>
    
  419.             ▾ <Suspense>
    
  420.                 <A key="a">
    
  421.               <Y>
    
  422.       `,
    
  423.       `
    
  424.         [root]
    
  425.           ▾ <Root>
    
  426.               <X>
    
  427.             ▾ <Suspense>
    
  428.                 <A key="a">
    
  429.               <Y>
    
  430.       `,
    
  431.       `
    
  432.         [root]
    
  433.           ▾ <Root>
    
  434.               <X>
    
  435.             ▾ <Suspense>
    
  436.                 <A key="a">
    
  437.                 <B key="b">
    
  438.                 <C key="c">
    
  439.               <Y>
    
  440.       `,
    
  441.       `
    
  442.         [root]
    
  443.           ▾ <Root>
    
  444.               <X>
    
  445.             ▾ <Suspense>
    
  446.                 <C key="c">
    
  447.                 <B key="b">
    
  448.                 <A key="a">
    
  449.               <Y>
    
  450.       `,
    
  451.       `
    
  452.         [root]
    
  453.           ▾ <Root>
    
  454.               <X>
    
  455.             ▾ <Suspense>
    
  456.                 <C key="c">
    
  457.                 <A key="a">
    
  458.               <Y>
    
  459.       `,
    
  460.       `
    
  461.         [root]
    
  462.           ▾ <Root>
    
  463.               <X>
    
  464.             ▾ <Suspense>
    
  465.                 <C key="c">
    
  466.                 <A key="a">
    
  467.               <Y>
    
  468.       `,
    
  469.       `
    
  470.         [root]
    
  471.           ▾ <Root>
    
  472.               <X>
    
  473.             ▾ <Suspense>
    
  474.                 <C key="c">
    
  475.                 <A key="a">
    
  476.               <Y>
    
  477.       `,
    
  478.       `
    
  479.         [root]
    
  480.           ▾ <Root>
    
  481.               <X>
    
  482.             ▾ <Suspense>
    
  483.                 <A key="a">
    
  484.                 <B key="b">
    
  485.               <Y>
    
  486.       `,
    
  487.       `
    
  488.         [root]
    
  489.           ▾ <Root>
    
  490.               <X>
    
  491.             ▾ <Suspense>
    
  492.                 <A key="a">
    
  493.               <Y>
    
  494.       `,
    
  495.       `
    
  496.         [root]
    
  497.           ▾ <Root>
    
  498.               <X>
    
  499.               <Suspense>
    
  500.               <Y>
    
  501.       `,
    
  502.       `
    
  503.         [root]
    
  504.           ▾ <Root>
    
  505.               <X>
    
  506.             ▾ <Suspense>
    
  507.                 <B key="b">
    
  508.               <Y>
    
  509.       `,
    
  510.       `
    
  511.         [root]
    
  512.           ▾ <Root>
    
  513.               <X>
    
  514.             ▾ <Suspense>
    
  515.                 <A key="a">
    
  516.               <Y>
    
  517.       `,
    
  518.     ];
    
  519. 
    
  520.     const Never = () => {
    
  521.       throw new Promise(() => {});
    
  522.     };
    
  523. 
    
  524.     const Root = ({children}) => {
    
  525.       return children;
    
  526.     };
    
  527. 
    
  528.     // 1. For each step, check Suspense can render them as initial primary content.
    
  529.     // This is the only step where we use Jest snapshots.
    
  530.     const snapshots = [];
    
  531.     let container = document.createElement('div');
    
  532.     for (let i = 0; i < steps.length; i++) {
    
  533.       act(() =>
    
  534.         legacyRender(
    
  535.           <Root>
    
  536.             <X />
    
  537.             <React.Suspense fallback={z}>{steps[i]}</React.Suspense>
    
  538.             <Y />
    
  539.           </Root>,
    
  540.           container,
    
  541.         ),
    
  542.       );
    
  543.       // We snapshot each step once so it doesn't regress.
    
  544.       expect(store).toMatchInlineSnapshot(stepsSnapshot[i]);
    
  545.       snapshots.push(print(store));
    
  546.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  547.       expect(print(store)).toBe('');
    
  548.     }
    
  549. 
    
  550.     // 2. Verify check Suspense can render same steps as initial fallback content.
    
  551.     for (let i = 0; i < steps.length; i++) {
    
  552.       act(() =>
    
  553.         legacyRender(
    
  554.           <Root>
    
  555.             <X />
    
  556.             <React.Suspense fallback={steps[i]}>
    
  557.               <Z />
    
  558.               <Never />
    
  559.               <Z />
    
  560.             </React.Suspense>
    
  561.             <Y />
    
  562.           </Root>,
    
  563.           container,
    
  564.         ),
    
  565.       );
    
  566.       expect(print(store)).toEqual(snapshots[i]);
    
  567.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  568.       expect(print(store)).toBe('');
    
  569.     }
    
  570. 
    
  571.     // 3. Verify we can update from each step to each step in primary mode.
    
  572.     for (let i = 0; i < steps.length; i++) {
    
  573.       for (let j = 0; j < steps.length; j++) {
    
  574.         // Always start with a fresh container and steps[i].
    
  575.         container = document.createElement('div');
    
  576.         act(() =>
    
  577.           legacyRender(
    
  578.             <Root>
    
  579.               <X />
    
  580.               <React.Suspense fallback={z}>{steps[i]}</React.Suspense>
    
  581.               <Y />
    
  582.             </Root>,
    
  583.             container,
    
  584.           ),
    
  585.         );
    
  586.         expect(print(store)).toEqual(snapshots[i]);
    
  587.         // Re-render with steps[j].
    
  588.         act(() =>
    
  589.           legacyRender(
    
  590.             <Root>
    
  591.               <X />
    
  592.               <React.Suspense fallback={z}>{steps[j]}</React.Suspense>
    
  593.               <Y />
    
  594.             </Root>,
    
  595.             container,
    
  596.           ),
    
  597.         );
    
  598.         // Verify the successful transition to steps[j].
    
  599.         expect(print(store)).toEqual(snapshots[j]);
    
  600.         // Check that we can transition back again.
    
  601.         act(() =>
    
  602.           legacyRender(
    
  603.             <Root>
    
  604.               <X />
    
  605.               <React.Suspense fallback={z}>{steps[i]}</React.Suspense>
    
  606.               <Y />
    
  607.             </Root>,
    
  608.             container,
    
  609.           ),
    
  610.         );
    
  611.         expect(print(store)).toEqual(snapshots[i]);
    
  612.         // Clean up after every iteration.
    
  613.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  614.         expect(print(store)).toBe('');
    
  615.       }
    
  616.     }
    
  617. 
    
  618.     // 4. Verify we can update from each step to each step in fallback mode.
    
  619.     for (let i = 0; i < steps.length; i++) {
    
  620.       for (let j = 0; j < steps.length; j++) {
    
  621.         // Always start with a fresh container and steps[i].
    
  622.         container = document.createElement('div');
    
  623.         act(() =>
    
  624.           legacyRender(
    
  625.             <Root>
    
  626.               <X />
    
  627.               <React.Suspense fallback={steps[i]}>
    
  628.                 <Z />
    
  629.                 <Never />
    
  630.                 <Z />
    
  631.               </React.Suspense>
    
  632.               <Y />
    
  633.             </Root>,
    
  634.             container,
    
  635.           ),
    
  636.         );
    
  637.         expect(print(store)).toEqual(snapshots[i]);
    
  638.         // Re-render with steps[j].
    
  639.         act(() =>
    
  640.           legacyRender(
    
  641.             <Root>
    
  642.               <X />
    
  643.               <React.Suspense fallback={steps[j]}>
    
  644.                 <Z />
    
  645.                 <Never />
    
  646.                 <Z />
    
  647.               </React.Suspense>
    
  648.               <Y />
    
  649.             </Root>,
    
  650.             container,
    
  651.           ),
    
  652.         );
    
  653.         // Verify the successful transition to steps[j].
    
  654.         expect(print(store)).toEqual(snapshots[j]);
    
  655.         // Check that we can transition back again.
    
  656.         act(() =>
    
  657.           legacyRender(
    
  658.             <Root>
    
  659.               <X />
    
  660.               <React.Suspense fallback={steps[i]}>
    
  661.                 <Z />
    
  662.                 <Never />
    
  663.                 <Z />
    
  664.               </React.Suspense>
    
  665.               <Y />
    
  666.             </Root>,
    
  667.             container,
    
  668.           ),
    
  669.         );
    
  670.         expect(print(store)).toEqual(snapshots[i]);
    
  671.         // Clean up after every iteration.
    
  672.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  673.         expect(print(store)).toBe('');
    
  674.       }
    
  675.     }
    
  676. 
    
  677.     // 5. Verify we can update from each step to each step when moving primary -> fallback.
    
  678.     for (let i = 0; i < steps.length; i++) {
    
  679.       for (let j = 0; j < steps.length; j++) {
    
  680.         // Always start with a fresh container and steps[i].
    
  681.         container = document.createElement('div');
    
  682.         act(() =>
    
  683.           legacyRender(
    
  684.             <Root>
    
  685.               <X />
    
  686.               <React.Suspense fallback={z}>{steps[i]}</React.Suspense>
    
  687.               <Y />
    
  688.             </Root>,
    
  689.             container,
    
  690.           ),
    
  691.         );
    
  692.         expect(print(store)).toEqual(snapshots[i]);
    
  693.         // Re-render with steps[j].
    
  694.         act(() =>
    
  695.           legacyRender(
    
  696.             <Root>
    
  697.               <X />
    
  698.               <React.Suspense fallback={steps[j]}>
    
  699.                 <Z />
    
  700.                 <Never />
    
  701.                 <Z />
    
  702.               </React.Suspense>
    
  703.               <Y />
    
  704.             </Root>,
    
  705.             container,
    
  706.           ),
    
  707.         );
    
  708.         // Verify the successful transition to steps[j].
    
  709.         expect(print(store)).toEqual(snapshots[j]);
    
  710.         // Check that we can transition back again.
    
  711.         act(() =>
    
  712.           legacyRender(
    
  713.             <Root>
    
  714.               <X />
    
  715.               <React.Suspense fallback={z}>{steps[i]}</React.Suspense>
    
  716.               <Y />
    
  717.             </Root>,
    
  718.             container,
    
  719.           ),
    
  720.         );
    
  721.         expect(print(store)).toEqual(snapshots[i]);
    
  722.         // Clean up after every iteration.
    
  723.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  724.         expect(print(store)).toBe('');
    
  725.       }
    
  726.     }
    
  727. 
    
  728.     // 6. Verify we can update from each step to each step when moving fallback -> primary.
    
  729.     for (let i = 0; i < steps.length; i++) {
    
  730.       for (let j = 0; j < steps.length; j++) {
    
  731.         // Always start with a fresh container and steps[i].
    
  732.         container = document.createElement('div');
    
  733.         act(() =>
    
  734.           legacyRender(
    
  735.             <Root>
    
  736.               <X />
    
  737.               <React.Suspense fallback={steps[i]}>
    
  738.                 <Z />
    
  739.                 <Never />
    
  740.                 <Z />
    
  741.               </React.Suspense>
    
  742.               <Y />
    
  743.             </Root>,
    
  744.             container,
    
  745.           ),
    
  746.         );
    
  747.         expect(print(store)).toEqual(snapshots[i]);
    
  748.         // Re-render with steps[j].
    
  749.         act(() =>
    
  750.           legacyRender(
    
  751.             <Root>
    
  752.               <X />
    
  753.               <React.Suspense fallback={z}>{steps[j]}</React.Suspense>
    
  754.               <Y />
    
  755.             </Root>,
    
  756.             container,
    
  757.           ),
    
  758.         );
    
  759.         // Verify the successful transition to steps[j].
    
  760.         expect(print(store)).toEqual(snapshots[j]);
    
  761.         // Check that we can transition back again.
    
  762.         act(() =>
    
  763.           legacyRender(
    
  764.             <Root>
    
  765.               <X />
    
  766.               <React.Suspense fallback={steps[i]}>
    
  767.                 <Z />
    
  768.                 <Never />
    
  769.                 <Z />
    
  770.               </React.Suspense>
    
  771.               <Y />
    
  772.             </Root>,
    
  773.             container,
    
  774.           ),
    
  775.         );
    
  776.         expect(print(store)).toEqual(snapshots[i]);
    
  777.         // Clean up after every iteration.
    
  778.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  779.         expect(print(store)).toBe('');
    
  780.       }
    
  781.     }
    
  782. 
    
  783.     // 7. Verify we can update from each step to each step when toggling Suspense.
    
  784.     for (let i = 0; i < steps.length; i++) {
    
  785.       for (let j = 0; j < steps.length; j++) {
    
  786.         // Always start with a fresh container and steps[i].
    
  787.         container = document.createElement('div');
    
  788.         act(() =>
    
  789.           legacyRender(
    
  790.             <Root>
    
  791.               <X />
    
  792.               <React.Suspense fallback={steps[j]}>{steps[i]}</React.Suspense>
    
  793.               <Y />
    
  794.             </Root>,
    
  795.             container,
    
  796.           ),
    
  797.         );
    
  798. 
    
  799.         // We get ID from the index in the tree above:
    
  800.         // Root, X, Suspense, ...
    
  801.         //          ^ (index is 2)
    
  802.         const suspenseID = store.getElementIDAtIndex(2);
    
  803. 
    
  804.         // Force fallback.
    
  805.         expect(print(store)).toEqual(snapshots[i]);
    
  806.         act(() => {
    
  807.           bridge.send('overrideSuspense', {
    
  808.             id: suspenseID,
    
  809.             rendererID: store.getRendererIDForElement(suspenseID),
    
  810.             forceFallback: true,
    
  811.           });
    
  812.         });
    
  813.         expect(print(store)).toEqual(snapshots[j]);
    
  814. 
    
  815.         // Stop forcing fallback.
    
  816.         act(() => {
    
  817.           bridge.send('overrideSuspense', {
    
  818.             id: suspenseID,
    
  819.             rendererID: store.getRendererIDForElement(suspenseID),
    
  820.             forceFallback: false,
    
  821.           });
    
  822.         });
    
  823.         expect(print(store)).toEqual(snapshots[i]);
    
  824. 
    
  825.         // Trigger actual fallback.
    
  826.         act(() =>
    
  827.           legacyRender(
    
  828.             <Root>
    
  829.               <X />
    
  830.               <React.Suspense fallback={steps[j]}>
    
  831.                 <Z />
    
  832.                 <Never />
    
  833.                 <Z />
    
  834.               </React.Suspense>
    
  835.               <Y />
    
  836.             </Root>,
    
  837.             container,
    
  838.           ),
    
  839.         );
    
  840.         expect(print(store)).toEqual(snapshots[j]);
    
  841. 
    
  842.         // Force fallback while we're in fallback mode.
    
  843.         act(() => {
    
  844.           bridge.send('overrideSuspense', {
    
  845.             id: suspenseID,
    
  846.             rendererID: store.getRendererIDForElement(suspenseID),
    
  847.             forceFallback: true,
    
  848.           });
    
  849.         });
    
  850.         // Keep seeing fallback content.
    
  851.         expect(print(store)).toEqual(snapshots[j]);
    
  852. 
    
  853.         // Switch to primary mode.
    
  854.         act(() =>
    
  855.           legacyRender(
    
  856.             <Root>
    
  857.               <X />
    
  858.               <React.Suspense fallback={steps[j]}>{steps[i]}</React.Suspense>
    
  859.               <Y />
    
  860.             </Root>,
    
  861.             container,
    
  862.           ),
    
  863.         );
    
  864.         // Fallback is still forced though.
    
  865.         expect(print(store)).toEqual(snapshots[j]);
    
  866. 
    
  867.         // Stop forcing fallback. This reverts to primary content.
    
  868.         act(() => {
    
  869.           bridge.send('overrideSuspense', {
    
  870.             id: suspenseID,
    
  871.             rendererID: store.getRendererIDForElement(suspenseID),
    
  872.             forceFallback: false,
    
  873.           });
    
  874.         });
    
  875.         // Now we see primary content.
    
  876.         expect(print(store)).toEqual(snapshots[i]);
    
  877. 
    
  878.         // Clean up after every iteration.
    
  879.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  880.         expect(print(store)).toBe('');
    
  881.       }
    
  882.     }
    
  883.   });
    
  884. 
    
  885.   // @reactVersion >= 18.0
    
  886.   it('should handle a stress test for Suspense without type change (Legacy Mode)', () => {
    
  887.     const A = () => 'a';
    
  888.     const B = () => 'b';
    
  889.     const C = () => 'c';
    
  890.     const X = () => 'x';
    
  891.     const Y = () => 'y';
    
  892.     const Z = () => 'z';
    
  893.     const a = <A key="a" />;
    
  894.     const b = <B key="b" />;
    
  895.     const c = <C key="c" />;
    
  896.     const z = <Z key="z" />;
    
  897. 
    
  898.     // prettier-ignore
    
  899.     const steps = [
    
  900.       a,
    
  901.       [a],
    
  902.       [a, b, c],
    
  903.       [c, b, a],
    
  904.       [c, null, a],
    
  905.       <React.Fragment>{c}{a}</React.Fragment>,
    
  906.       <div>{c}{a}</div>,
    
  907.       <div><span>{a}</span>{b}</div>,
    
  908.       [[a]],
    
  909.       null,
    
  910.       b,
    
  911.       a,
    
  912.     ];
    
  913. 
    
  914.     const stepsSnapshot = [
    
  915.       `
    
  916.         [root]
    
  917.           ▾ <Root>
    
  918.               <X>
    
  919.             ▾ <Suspense>
    
  920.               ▾ <MaybeSuspend>
    
  921.                   <A key="a">
    
  922.                   <Z>
    
  923.               <Y>
    
  924.       `,
    
  925.       `
    
  926.         [root]
    
  927.           ▾ <Root>
    
  928.               <X>
    
  929.             ▾ <Suspense>
    
  930.               ▾ <MaybeSuspend>
    
  931.                   <A key="a">
    
  932.                   <Z>
    
  933.               <Y>
    
  934.       `,
    
  935.       `
    
  936.         [root]
    
  937.           ▾ <Root>
    
  938.               <X>
    
  939.             ▾ <Suspense>
    
  940.               ▾ <MaybeSuspend>
    
  941.                   <A key="a">
    
  942.                   <B key="b">
    
  943.                   <C key="c">
    
  944.                   <Z>
    
  945.               <Y>
    
  946.       `,
    
  947.       `
    
  948.         [root]
    
  949.           ▾ <Root>
    
  950.               <X>
    
  951.             ▾ <Suspense>
    
  952.               ▾ <MaybeSuspend>
    
  953.                   <C key="c">
    
  954.                   <B key="b">
    
  955.                   <A key="a">
    
  956.                   <Z>
    
  957.               <Y>
    
  958.       `,
    
  959.       `
    
  960.         [root]
    
  961.           ▾ <Root>
    
  962.               <X>
    
  963.             ▾ <Suspense>
    
  964.               ▾ <MaybeSuspend>
    
  965.                   <C key="c">
    
  966.                   <A key="a">
    
  967.                   <Z>
    
  968.               <Y>
    
  969.       `,
    
  970.       `
    
  971.         [root]
    
  972.           ▾ <Root>
    
  973.               <X>
    
  974.             ▾ <Suspense>
    
  975.               ▾ <MaybeSuspend>
    
  976.                   <C key="c">
    
  977.                   <A key="a">
    
  978.                   <Z>
    
  979.               <Y>
    
  980.       `,
    
  981.       `
    
  982.         [root]
    
  983.           ▾ <Root>
    
  984.               <X>
    
  985.             ▾ <Suspense>
    
  986.               ▾ <MaybeSuspend>
    
  987.                   <C key="c">
    
  988.                   <A key="a">
    
  989.                   <Z>
    
  990.               <Y>
    
  991.       `,
    
  992.       `
    
  993.         [root]
    
  994.           ▾ <Root>
    
  995.               <X>
    
  996.             ▾ <Suspense>
    
  997.               ▾ <MaybeSuspend>
    
  998.                   <A key="a">
    
  999.                   <B key="b">
    
  1000.                   <Z>
    
  1001.               <Y>
    
  1002.       `,
    
  1003.       `
    
  1004.         [root]
    
  1005.           ▾ <Root>
    
  1006.               <X>
    
  1007.             ▾ <Suspense>
    
  1008.               ▾ <MaybeSuspend>
    
  1009.                   <A key="a">
    
  1010.                   <Z>
    
  1011.               <Y>
    
  1012.       `,
    
  1013.       `
    
  1014.         [root]
    
  1015.           ▾ <Root>
    
  1016.               <X>
    
  1017.             ▾ <Suspense>
    
  1018.               ▾ <MaybeSuspend>
    
  1019.                   <Z>
    
  1020.               <Y>
    
  1021.       `,
    
  1022.       `
    
  1023.         [root]
    
  1024.           ▾ <Root>
    
  1025.               <X>
    
  1026.             ▾ <Suspense>
    
  1027.               ▾ <MaybeSuspend>
    
  1028.                   <B key="b">
    
  1029.                   <Z>
    
  1030.               <Y>
    
  1031.       `,
    
  1032.       `
    
  1033.         [root]
    
  1034.           ▾ <Root>
    
  1035.               <X>
    
  1036.             ▾ <Suspense>
    
  1037.               ▾ <MaybeSuspend>
    
  1038.                   <A key="a">
    
  1039.                   <Z>
    
  1040.               <Y>
    
  1041.       `,
    
  1042.     ];
    
  1043. 
    
  1044.     const stepsSnapshotTwo = [
    
  1045.       `
    
  1046.         [root]
    
  1047.           ▾ <Root>
    
  1048.               <X>
    
  1049.             ▾ <Suspense>
    
  1050.                 <A key="a">
    
  1051.               <Y>
    
  1052.       `,
    
  1053.       `
    
  1054.         [root]
    
  1055.           ▾ <Root>
    
  1056.               <X>
    
  1057.             ▾ <Suspense>
    
  1058.                 <A key="a">
    
  1059.               <Y>
    
  1060.       `,
    
  1061.       `
    
  1062.         [root]
    
  1063.           ▾ <Root>
    
  1064.               <X>
    
  1065.             ▾ <Suspense>
    
  1066.                 <A key="a">
    
  1067.                 <B key="b">
    
  1068.                 <C key="c">
    
  1069.               <Y>
    
  1070.       `,
    
  1071.       `
    
  1072.         [root]
    
  1073.           ▾ <Root>
    
  1074.               <X>
    
  1075.             ▾ <Suspense>
    
  1076.                 <C key="c">
    
  1077.                 <B key="b">
    
  1078.                 <A key="a">
    
  1079.               <Y>
    
  1080.       `,
    
  1081.       `
    
  1082.         [root]
    
  1083.           ▾ <Root>
    
  1084.               <X>
    
  1085.             ▾ <Suspense>
    
  1086.                 <C key="c">
    
  1087.                 <A key="a">
    
  1088.               <Y>
    
  1089.       `,
    
  1090.       `
    
  1091.         [root]
    
  1092.           ▾ <Root>
    
  1093.               <X>
    
  1094.             ▾ <Suspense>
    
  1095.                 <C key="c">
    
  1096.                 <A key="a">
    
  1097.               <Y>
    
  1098.       `,
    
  1099.       `
    
  1100.         [root]
    
  1101.           ▾ <Root>
    
  1102.               <X>
    
  1103.             ▾ <Suspense>
    
  1104.                 <C key="c">
    
  1105.                 <A key="a">
    
  1106.               <Y>
    
  1107.       `,
    
  1108.       `
    
  1109.         [root]
    
  1110.           ▾ <Root>
    
  1111.               <X>
    
  1112.             ▾ <Suspense>
    
  1113.                 <A key="a">
    
  1114.                 <B key="b">
    
  1115.               <Y>
    
  1116.       `,
    
  1117.       `
    
  1118.         [root]
    
  1119.           ▾ <Root>
    
  1120.               <X>
    
  1121.             ▾ <Suspense>
    
  1122.                 <A key="a">
    
  1123.               <Y>
    
  1124.       `,
    
  1125.       `
    
  1126.         [root]
    
  1127.           ▾ <Root>
    
  1128.               <X>
    
  1129.               <Suspense>
    
  1130.               <Y>
    
  1131.       `,
    
  1132.       `
    
  1133.         [root]
    
  1134.           ▾ <Root>
    
  1135.               <X>
    
  1136.             ▾ <Suspense>
    
  1137.                 <B key="b">
    
  1138.               <Y>
    
  1139.       `,
    
  1140.       `
    
  1141.         [root]
    
  1142.           ▾ <Root>
    
  1143.               <X>
    
  1144.             ▾ <Suspense>
    
  1145.                 <A key="a">
    
  1146.               <Y>
    
  1147.       `,
    
  1148.     ];
    
  1149. 
    
  1150.     const Never = () => {
    
  1151.       throw new Promise(() => {});
    
  1152.     };
    
  1153. 
    
  1154.     const MaybeSuspend = ({children, suspend}) => {
    
  1155.       if (suspend) {
    
  1156.         return (
    
  1157.           <div>
    
  1158.             {children}
    
  1159.             <Never />
    
  1160.             <X />
    
  1161.           </div>
    
  1162.         );
    
  1163.       }
    
  1164.       return (
    
  1165.         <div>
    
  1166.           {children}
    
  1167.           <Z />
    
  1168.         </div>
    
  1169.       );
    
  1170.     };
    
  1171. 
    
  1172.     const Root = ({children}) => {
    
  1173.       return children;
    
  1174.     };
    
  1175. 
    
  1176.     // 1. For each step, check Suspense can render them as initial primary content.
    
  1177.     // This is the only step where we use Jest snapshots.
    
  1178.     const snapshots = [];
    
  1179.     let container = document.createElement('div');
    
  1180.     for (let i = 0; i < steps.length; i++) {
    
  1181.       act(() =>
    
  1182.         legacyRender(
    
  1183.           <Root>
    
  1184.             <X />
    
  1185.             <React.Suspense fallback={z}>
    
  1186.               <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1187.             </React.Suspense>
    
  1188.             <Y />
    
  1189.           </Root>,
    
  1190.           container,
    
  1191.         ),
    
  1192.       );
    
  1193.       // We snapshot each step once so it doesn't regress.
    
  1194.       expect(store).toMatchInlineSnapshot(stepsSnapshot[i]);
    
  1195.       snapshots.push(print(store));
    
  1196.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  1197.       expect(print(store)).toBe('');
    
  1198.     }
    
  1199. 
    
  1200.     // 2. Verify check Suspense can render same steps as initial fallback content.
    
  1201.     // We don't actually assert here because the tree includes <MaybeSuspend>
    
  1202.     // which is different from the snapshots above. So we take more snapshots.
    
  1203.     const fallbackSnapshots = [];
    
  1204.     for (let i = 0; i < steps.length; i++) {
    
  1205.       act(() =>
    
  1206.         legacyRender(
    
  1207.           <Root>
    
  1208.             <X />
    
  1209.             <React.Suspense fallback={steps[i]}>
    
  1210.               <Z />
    
  1211.               <MaybeSuspend suspend={true}>{steps[i]}</MaybeSuspend>
    
  1212.               <Z />
    
  1213.             </React.Suspense>
    
  1214.             <Y />
    
  1215.           </Root>,
    
  1216.           container,
    
  1217.         ),
    
  1218.       );
    
  1219.       // We snapshot each step once so it doesn't regress.
    
  1220.       expect(store).toMatchInlineSnapshot(stepsSnapshotTwo[i]);
    
  1221.       fallbackSnapshots.push(print(store));
    
  1222.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  1223.       expect(print(store)).toBe('');
    
  1224.     }
    
  1225. 
    
  1226.     // 3. Verify we can update from each step to each step in primary mode.
    
  1227.     for (let i = 0; i < steps.length; i++) {
    
  1228.       for (let j = 0; j < steps.length; j++) {
    
  1229.         // Always start with a fresh container and steps[i].
    
  1230.         container = document.createElement('div');
    
  1231.         act(() =>
    
  1232.           legacyRender(
    
  1233.             <Root>
    
  1234.               <X />
    
  1235.               <React.Suspense fallback={z}>
    
  1236.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1237.               </React.Suspense>
    
  1238.               <Y />
    
  1239.             </Root>,
    
  1240.             container,
    
  1241.           ),
    
  1242.         );
    
  1243.         expect(print(store)).toEqual(snapshots[i]);
    
  1244.         // Re-render with steps[j].
    
  1245.         act(() =>
    
  1246.           legacyRender(
    
  1247.             <Root>
    
  1248.               <X />
    
  1249.               <React.Suspense fallback={z}>
    
  1250.                 <MaybeSuspend suspend={false}>{steps[j]}</MaybeSuspend>
    
  1251.               </React.Suspense>
    
  1252.               <Y />
    
  1253.             </Root>,
    
  1254.             container,
    
  1255.           ),
    
  1256.         );
    
  1257.         // Verify the successful transition to steps[j].
    
  1258.         expect(print(store)).toEqual(snapshots[j]);
    
  1259.         // Check that we can transition back again.
    
  1260.         act(() =>
    
  1261.           legacyRender(
    
  1262.             <Root>
    
  1263.               <X />
    
  1264.               <React.Suspense fallback={z}>
    
  1265.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1266.               </React.Suspense>
    
  1267.               <Y />
    
  1268.             </Root>,
    
  1269.             container,
    
  1270.           ),
    
  1271.         );
    
  1272.         expect(print(store)).toEqual(snapshots[i]);
    
  1273.         // Clean up after every iteration.
    
  1274.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1275.         expect(print(store)).toBe('');
    
  1276.       }
    
  1277.     }
    
  1278. 
    
  1279.     // 4. Verify we can update from each step to each step in fallback mode.
    
  1280.     for (let i = 0; i < steps.length; i++) {
    
  1281.       for (let j = 0; j < steps.length; j++) {
    
  1282.         // Always start with a fresh container and steps[i].
    
  1283.         container = document.createElement('div');
    
  1284.         act(() =>
    
  1285.           legacyRender(
    
  1286.             <Root>
    
  1287.               <X />
    
  1288.               <React.Suspense fallback={steps[i]}>
    
  1289.                 <Z />
    
  1290.                 <MaybeSuspend suspend={true}>
    
  1291.                   <X />
    
  1292.                   <Y />
    
  1293.                 </MaybeSuspend>
    
  1294.                 <Z />
    
  1295.               </React.Suspense>
    
  1296.               <Y />
    
  1297.             </Root>,
    
  1298.             container,
    
  1299.           ),
    
  1300.         );
    
  1301.         expect(print(store)).toEqual(fallbackSnapshots[i]);
    
  1302.         // Re-render with steps[j].
    
  1303.         act(() =>
    
  1304.           legacyRender(
    
  1305.             <Root>
    
  1306.               <X />
    
  1307.               <React.Suspense fallback={steps[j]}>
    
  1308.                 <Z />
    
  1309.                 <MaybeSuspend suspend={true}>
    
  1310.                   <Y />
    
  1311.                   <X />
    
  1312.                 </MaybeSuspend>
    
  1313.                 <Z />
    
  1314.               </React.Suspense>
    
  1315.               <Y />
    
  1316.             </Root>,
    
  1317.             container,
    
  1318.           ),
    
  1319.         );
    
  1320.         // Verify the successful transition to steps[j].
    
  1321.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1322.         // Check that we can transition back again.
    
  1323.         act(() =>
    
  1324.           legacyRender(
    
  1325.             <Root>
    
  1326.               <X />
    
  1327.               <React.Suspense fallback={steps[i]}>
    
  1328.                 <Z />
    
  1329.                 <MaybeSuspend suspend={true}>
    
  1330.                   <X />
    
  1331.                   <Y />
    
  1332.                 </MaybeSuspend>
    
  1333.                 <Z />
    
  1334.               </React.Suspense>
    
  1335.               <Y />
    
  1336.             </Root>,
    
  1337.             container,
    
  1338.           ),
    
  1339.         );
    
  1340.         expect(print(store)).toEqual(fallbackSnapshots[i]);
    
  1341.         // Clean up after every iteration.
    
  1342.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1343.         expect(print(store)).toBe('');
    
  1344.       }
    
  1345.     }
    
  1346. 
    
  1347.     // 5. Verify we can update from each step to each step when moving primary -> fallback.
    
  1348.     for (let i = 0; i < steps.length; i++) {
    
  1349.       for (let j = 0; j < steps.length; j++) {
    
  1350.         // Always start with a fresh container and steps[i].
    
  1351.         container = document.createElement('div');
    
  1352.         act(() =>
    
  1353.           legacyRender(
    
  1354.             <Root>
    
  1355.               <X />
    
  1356.               <React.Suspense fallback={z}>
    
  1357.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1358.               </React.Suspense>
    
  1359.               <Y />
    
  1360.             </Root>,
    
  1361.             container,
    
  1362.           ),
    
  1363.         );
    
  1364.         expect(print(store)).toEqual(snapshots[i]);
    
  1365.         // Re-render with steps[j].
    
  1366.         act(() =>
    
  1367.           legacyRender(
    
  1368.             <Root>
    
  1369.               <X />
    
  1370.               <React.Suspense fallback={steps[j]}>
    
  1371.                 <MaybeSuspend suspend={true}>{steps[i]}</MaybeSuspend>
    
  1372.               </React.Suspense>
    
  1373.               <Y />
    
  1374.             </Root>,
    
  1375.             container,
    
  1376.           ),
    
  1377.         );
    
  1378.         // Verify the successful transition to steps[j].
    
  1379.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1380.         // Check that we can transition back again.
    
  1381.         act(() =>
    
  1382.           legacyRender(
    
  1383.             <Root>
    
  1384.               <X />
    
  1385.               <React.Suspense fallback={z}>
    
  1386.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1387.               </React.Suspense>
    
  1388.               <Y />
    
  1389.             </Root>,
    
  1390.             container,
    
  1391.           ),
    
  1392.         );
    
  1393.         expect(print(store)).toEqual(snapshots[i]);
    
  1394.         // Clean up after every iteration.
    
  1395.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1396.         expect(print(store)).toBe('');
    
  1397.       }
    
  1398.     }
    
  1399. 
    
  1400.     // 6. Verify we can update from each step to each step when moving fallback -> primary.
    
  1401.     for (let i = 0; i < steps.length; i++) {
    
  1402.       for (let j = 0; j < steps.length; j++) {
    
  1403.         // Always start with a fresh container and steps[i].
    
  1404.         container = document.createElement('div');
    
  1405.         act(() =>
    
  1406.           legacyRender(
    
  1407.             <Root>
    
  1408.               <X />
    
  1409.               <React.Suspense fallback={steps[i]}>
    
  1410.                 <MaybeSuspend suspend={true}>{steps[j]}</MaybeSuspend>
    
  1411.               </React.Suspense>
    
  1412.               <Y />
    
  1413.             </Root>,
    
  1414.             container,
    
  1415.           ),
    
  1416.         );
    
  1417.         expect(print(store)).toEqual(fallbackSnapshots[i]);
    
  1418.         // Re-render with steps[j].
    
  1419.         act(() =>
    
  1420.           legacyRender(
    
  1421.             <Root>
    
  1422.               <X />
    
  1423.               <React.Suspense fallback={steps[i]}>
    
  1424.                 <MaybeSuspend suspend={false}>{steps[j]}</MaybeSuspend>
    
  1425.               </React.Suspense>
    
  1426.               <Y />
    
  1427.             </Root>,
    
  1428.             container,
    
  1429.           ),
    
  1430.         );
    
  1431.         // Verify the successful transition to steps[j].
    
  1432.         expect(print(store)).toEqual(snapshots[j]);
    
  1433.         // Check that we can transition back again.
    
  1434.         act(() =>
    
  1435.           legacyRender(
    
  1436.             <Root>
    
  1437.               <X />
    
  1438.               <React.Suspense fallback={steps[i]}>
    
  1439.                 <MaybeSuspend suspend={true}>{steps[j]}</MaybeSuspend>
    
  1440.               </React.Suspense>
    
  1441.               <Y />
    
  1442.             </Root>,
    
  1443.             container,
    
  1444.           ),
    
  1445.         );
    
  1446.         expect(print(store)).toEqual(fallbackSnapshots[i]);
    
  1447.         // Clean up after every iteration.
    
  1448.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1449.         expect(print(store)).toBe('');
    
  1450.       }
    
  1451.     }
    
  1452. 
    
  1453.     // 7. Verify we can update from each step to each step when toggling Suspense.
    
  1454.     for (let i = 0; i < steps.length; i++) {
    
  1455.       for (let j = 0; j < steps.length; j++) {
    
  1456.         // Always start with a fresh container and steps[i].
    
  1457.         container = document.createElement('div');
    
  1458.         act(() =>
    
  1459.           legacyRender(
    
  1460.             <Root>
    
  1461.               <X />
    
  1462.               <React.Suspense fallback={steps[j]}>
    
  1463.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1464.               </React.Suspense>
    
  1465.               <Y />
    
  1466.             </Root>,
    
  1467.             container,
    
  1468.           ),
    
  1469.         );
    
  1470. 
    
  1471.         // We get ID from the index in the tree above:
    
  1472.         // Root, X, Suspense, ...
    
  1473.         //          ^ (index is 2)
    
  1474.         const suspenseID = store.getElementIDAtIndex(2);
    
  1475. 
    
  1476.         // Force fallback.
    
  1477.         expect(print(store)).toEqual(snapshots[i]);
    
  1478.         act(() => {
    
  1479.           bridge.send('overrideSuspense', {
    
  1480.             id: suspenseID,
    
  1481.             rendererID: store.getRendererIDForElement(suspenseID),
    
  1482.             forceFallback: true,
    
  1483.           });
    
  1484.         });
    
  1485.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1486. 
    
  1487.         // Stop forcing fallback.
    
  1488.         act(() => {
    
  1489.           bridge.send('overrideSuspense', {
    
  1490.             id: suspenseID,
    
  1491.             rendererID: store.getRendererIDForElement(suspenseID),
    
  1492.             forceFallback: false,
    
  1493.           });
    
  1494.         });
    
  1495.         expect(print(store)).toEqual(snapshots[i]);
    
  1496. 
    
  1497.         // Trigger actual fallback.
    
  1498.         act(() =>
    
  1499.           legacyRender(
    
  1500.             <Root>
    
  1501.               <X />
    
  1502.               <React.Suspense fallback={steps[j]}>
    
  1503.                 <MaybeSuspend suspend={true}>{steps[i]}</MaybeSuspend>
    
  1504.               </React.Suspense>
    
  1505.               <Y />
    
  1506.             </Root>,
    
  1507.             container,
    
  1508.           ),
    
  1509.         );
    
  1510.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1511. 
    
  1512.         // Force fallback while we're in fallback mode.
    
  1513.         act(() => {
    
  1514.           bridge.send('overrideSuspense', {
    
  1515.             id: suspenseID,
    
  1516.             rendererID: store.getRendererIDForElement(suspenseID),
    
  1517.             forceFallback: true,
    
  1518.           });
    
  1519.         });
    
  1520.         // Keep seeing fallback content.
    
  1521.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1522. 
    
  1523.         // Switch to primary mode.
    
  1524.         act(() =>
    
  1525.           legacyRender(
    
  1526.             <Root>
    
  1527.               <X />
    
  1528.               <React.Suspense fallback={steps[j]}>
    
  1529.                 <MaybeSuspend suspend={false}>{steps[i]}</MaybeSuspend>
    
  1530.               </React.Suspense>
    
  1531.               <Y />
    
  1532.             </Root>,
    
  1533.             container,
    
  1534.           ),
    
  1535.         );
    
  1536.         // Fallback is still forced though.
    
  1537.         expect(print(store)).toEqual(fallbackSnapshots[j]);
    
  1538. 
    
  1539.         // Stop forcing fallback. This reverts to primary content.
    
  1540.         act(() => {
    
  1541.           bridge.send('overrideSuspense', {
    
  1542.             id: suspenseID,
    
  1543.             rendererID: store.getRendererIDForElement(suspenseID),
    
  1544.             forceFallback: false,
    
  1545.           });
    
  1546.         });
    
  1547.         // Now we see primary content.
    
  1548.         expect(print(store)).toEqual(snapshots[i]);
    
  1549. 
    
  1550.         // Clean up after every iteration.
    
  1551.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1552.         expect(print(store)).toBe('');
    
  1553.       }
    
  1554.     }
    
  1555.   });
    
  1556. });