Repository: facebook/react
Pull request: Add Promise as a child test to Flight fixture

Adds a test for promise as a child that was fixed by https://github.com/facebook/react/pull/28284. Since the fix only included tests for `React.Children` I also added another regression test based on the original bug report in https://github.com/facebook/react/issues/27247.

## Test plan


I can't repro this in our unit test suite so I use the Flight fixture which fails on any console error.

- [x] Reverting the fix fails CI: https://app.circleci.com/pipelines/github/facebook/react/51990/workflows/d89bc4f1-0ae0-4694-a7ed-a922ec4a7c66/jobs/828188
   ```bash
    Error: expect(received).toEqual(expected) // deep equality

    - Expected  -  1
    + Received  + 38

    - Array []
    + Array [
    +   "Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
    +
    + - A server/client branch `if (typeof window !== 'undefined')`.
    + - Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
    + - Date formatting in a user's locale which doesn't match the server.
    + - External changing data without sending a snapshot of it along with the HTML.
    + - Invalid HTML tag nesting.
    +
    + It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
    +
    + https://react.dev/link/hydration-mismatch
    +
    +   <Shell data={[...]}>
    +     <link>
    +     <App>
    +       <html lang=\"en\">
    +         <head>
    +         <body>
    +           <Container>
    +             <div>
    +               <h1>
    +               <Suspense fallback={null}>
    + +               <div data-testid=\"promise-as-a-child-test\">
    + -               Promise as a child hydrates without errors: 
    +               ...
    +
    +     at throwOnHydrationMismatch (http://localhost:3000/static/js/bundle.js:20903:19)
    +     at tryToClaimNextHydratableInstance (http://localhost:3000/static/js/bundle.js:20948:9)
    +     at updateHostComponent$1 (http://localhost:3000/static/js/bundle.js:30288:9)
    +     at beginWork (http://localhost:3000/static/js/bundle.js:31858:18)
    +     at replaySuspendedUnitOfWork (http://localhost:3000/static/js/bundle.js:38668:20)
    +     at renderRootConcurrent (http://localhost:3000/static/js/bundle.js:38366:21)
    +     at performConcurrentWorkOnRoot (http://localhost:3000/static/js/bundle.js:37342:42)
    +     at workLoop (http://localhost:3000/static/js/bundle.js:49707:38)
    +     at flushWork (http://localhost:3000/static/js/bundle.js:49677:18)
    +     at MessagePort.performWorkUntilDeadline (http://localhost:3000/static/js/bundle.js:49975:25)",
    + ]

      19 |
      20 |   await expect(consoleErrors).toEqual([]);
    > 21 |   await expect(pageErrors).toEqual([]);
   ```

Changed files:
filename: fixtures/flight/__tests__/__e2e__/smoke.test.js
patch: @@ -13,7 +13,9 @@ test('smoke test', async ({page}) => {
     pageErrors.push(error.stack);
   });
   await page.goto('/');
-  await expect(page.locator('h1')).toHaveText('Hello World');
+  await expect(page.getByTestId('promise-as-a-child-test')).toHaveText(
+    'Promise as a child hydrates without errors: deferred text'
+  );
 
   await expect(consoleErrors).toEqual([]);
   await expect(pageErrors).toEqual([]);

filename: fixtures/flight/src/App.js
patch: @@ -19,6 +19,10 @@ import {like, greet, increment} from './actions.js';
 
 import {getServerState} from './ServerState.js';
 
+const promisedText = new Promise(resolve =>
+  setTimeout(() => resolve('deferred text'), 100)
+);
+
 export default async function App() {
   const res = await fetch('http://localhost:3001/todos');
   const todos = await res.json();
@@ -32,6 +36,11 @@ export default async function App() {
       <body>
         <Container>
           <h1>{getServerState()}</h1>
+          <React.Suspense fallback={null}>
+            <div data-testid="promise-as-a-child-test">
+              Promise as a child hydrates without errors: {promisedText}
+            </div>
+          </React.Suspense>
           <Counter incrementAction={increment} />
           <Counter2 incrementAction={increment} />
           <Counter3 incrementAction={increment} />