From cfc078d36d7e4afdea6039ca1a4a18ee135c5533 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Wed, 20 Apr 2022 11:22:30 -0700 Subject: [PATCH] move tests back to ReactDOMFizzServer-test --- .../src/__tests__/ReactDOMFizzServer-test.js | 79 ++++++++ ...actDOMFizzSuppressHydrationWarning-test.js | 183 ------------------ 2 files changed, 79 insertions(+), 183 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index b7a4271e18bc2..3eb3085cb5c03 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -2962,4 +2962,83 @@ describe('ReactDOMFizzServer', () => { expect(Scheduler).toFlushAndYield([]); }); + + // @gate experimental && enableClientRenderFallbackOnTextMismatch && enableClientRenderFallbackOnHydrationMismatch + it('only warns once on hydration mismatch while within a suspense boundary', async () => { + const originalConsoleError = console.error; + const mockError = jest.fn(); + console.error = (...args) => { + mockError(...args.map(normalizeCodeLocInfo)); + }; + + const App = ({text}) => { + return ( +
+ Loading...}> +

{text}

+

{text}

+

{text}

+
+
+ ); + }; + + try { + await act(async () => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream( + , + ); + pipe(writable); + }); + + expect(getVisibleChildren(container)).toEqual( +
+

initial

+

initial

+

initial

+
, + ); + + ReactDOMClient.hydrateRoot(container, , { + onRecoverableError(error) { + Scheduler.unstable_yieldValue( + 'Logged recoverable error: ' + error.message, + ); + }, + }); + expect(Scheduler).toFlushAndYield([ + 'Logged recoverable error: Text content does not match server-rendered HTML.', + 'Logged recoverable error: Text content does not match server-rendered HTML.', + 'Logged recoverable error: Text content does not match server-rendered HTML.', + 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.', + ]); + + expect(getVisibleChildren(container)).toEqual( +
+

replaced

+

replaced

+

replaced

+
, + ); + + expect(Scheduler).toFlushAndYield([]); + if (__DEV__) { + expect(mockError.mock.calls.length).toBe(1); + expect(mockError.mock.calls[0]).toEqual([ + 'Warning: Text content did not match. Server: "%s" Client: "%s"%s', + 'initial', + 'replaced', + '\n' + + ' in h2 (at **)\n' + + ' in Suspense (at **)\n' + + ' in div (at **)\n' + + ' in App (at **)', + ]); + } else { + expect(mockError.mock.calls.length).toBe(0); + } + } finally { + console.error = originalConsoleError; + } + }); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js index 69819314823e5..4f65ecf241c80 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js @@ -12,7 +12,6 @@ let JSDOM; let Stream; let Scheduler; -let Suspense; let React; let ReactDOMClient; let ReactDOMFizzServer; @@ -29,7 +28,6 @@ describe('ReactDOMFizzServerHydrationWarning', () => { JSDOM = require('jsdom').JSDOM; Scheduler = require('scheduler'); React = require('react'); - Suspense = React.Suspense; ReactDOMClient = require('react-dom/client'); if (__EXPERIMENTAL__) { ReactDOMFizzServer = require('react-dom/server'); @@ -60,18 +58,6 @@ describe('ReactDOMFizzServerHydrationWarning', () => { }); }); - function normalizeCodeLocInfo(strOrErr) { - if (strOrErr && strOrErr.replace) { - return strOrErr.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function( - m, - name, - ) { - return '\n in ' + name + ' (at **)'; - }); - } - return strOrErr; - } - async function act(callback) { await callback(); // Await one turn around the event loop. @@ -716,173 +702,4 @@ describe('ReactDOMFizzServerHydrationWarning', () => { , ); }); - - // @gate experimental && enableClientRenderFallbackOnTextMismatch && enableClientRenderFallbackOnHydrationMismatch - it('#24384: Suspending should halt hydration warnings while still allowing siblings to warm up', async () => { - const makeApp = () => { - let resolve, resolved; - const promise = new Promise(r => { - resolve = () => { - resolved = true; - return r(); - }; - }); - function ComponentThatSuspends() { - if (!resolved) { - throw promise; - } - return

A

; - } - - const App = ({text}) => { - return ( -
- Loading...}> - -

{text}

-
-
- ); - }; - - return [App, resolve]; - }; - - const [ServerApp, serverResolve] = makeApp(); - await act(async () => { - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( - , - ); - pipe(writable); - }); - await act(() => { - serverResolve(); - }); - - expect(getVisibleChildren(container)).toEqual( -
-

A

-

initial

-
, - ); - - // the client app is rendered with an intentionally incorrect text. The still Suspended component causes - // hydration to fail silently (allowing for cache warming but otherwise skipping this boundary) until it - // resolves. - const [ClientApp, clientResolve] = makeApp(); - ReactDOMClient.hydrateRoot(container, , { - onRecoverableError(error) { - Scheduler.unstable_yieldValue( - 'Logged recoverable error: ' + error.message, - ); - }, - }); - Scheduler.unstable_flushAll(); - - expect(getVisibleChildren(container)).toEqual( -
-

A

-

initial

-
, - ); - - // Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring - // client-side rendering. - await clientResolve(); - expect(() => { - expect(Scheduler).toFlushAndYield([ - 'Logged recoverable error: Text content does not match server-rendered HTML.', - 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.', - ]); - }).toErrorDev( - 'Warning: Prop `name` did not match. Server: "initial" Client: "replaced"', - ); - expect(getVisibleChildren(container)).toEqual( -
-

A

-

replaced

-
, - ); - - expect(Scheduler).toFlushAndYield([]); - }); - - // @gate experimental && enableClientRenderFallbackOnTextMismatch && enableClientRenderFallbackOnHydrationMismatch - it('only warns once on hydration mismatch while within a suspense boundary', async () => { - const originalConsoleError = console.error; - const mockError = jest.fn(); - console.error = (...args) => { - mockError(...args.map(normalizeCodeLocInfo)); - }; - - const App = ({text}) => { - return ( -
- Loading...}> -

{text}

-

{text}

-

{text}

-
-
- ); - }; - - try { - await act(async () => { - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( - , - ); - pipe(writable); - }); - - expect(getVisibleChildren(container)).toEqual( -
-

initial

-

initial

-

initial

-
, - ); - - ReactDOMClient.hydrateRoot(container, , { - onRecoverableError(error) { - Scheduler.unstable_yieldValue( - 'Logged recoverable error: ' + error.message, - ); - }, - }); - expect(Scheduler).toFlushAndYield([ - 'Logged recoverable error: Text content does not match server-rendered HTML.', - 'Logged recoverable error: Text content does not match server-rendered HTML.', - 'Logged recoverable error: Text content does not match server-rendered HTML.', - 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.', - ]); - - expect(getVisibleChildren(container)).toEqual( -
-

replaced

-

replaced

-

replaced

-
, - ); - - expect(Scheduler).toFlushAndYield([]); - if (__DEV__) { - expect(mockError.mock.calls.length).toBe(1); - expect(mockError.mock.calls[0]).toEqual([ - 'Warning: Text content did not match. Server: "%s" Client: "%s"%s', - 'initial', - 'replaced', - '\n' + - ' in h2 (at **)\n' + - ' in Suspense (at **)\n' + - ' in div (at **)\n' + - ' in App (at **)', - ]); - } else { - expect(mockError.mock.calls.length).toBe(0); - } - } finally { - console.error = originalConsoleError; - } - }); });