is unrecognized in this browser.');
const e = await render(Text);
@@ -833,15 +843,21 @@ describe('ReactDOMServerIntegration', () => {
'an element with one text child with special characters',
async render => {
const e = await render({'foo\rbar\r\nbaz\nqux\u0000'}
);
- if (render === serverRender || render === streamRender) {
+ if (
+ render === serverRender ||
+ render === streamRender ||
+ (render === clientRenderOnServerString &&
+ ReactFeatureFlags.enableClientRenderFallbackOnTextMismatch)
+ ) {
expect(e.childNodes.length).toBe(1);
- // Everything becomes LF when parsed from server HTML.
+ // Everything becomes LF when parsed from server HTML or hydrated if enableClientRenderFallbackOnTextMismatch is on.
// Null character is ignored.
expectNode(e.childNodes[0], TEXT_NODE_TYPE, 'foo\nbar\nbaz\nqux');
} else {
expect(e.childNodes.length).toBe(1);
- // Client rendering (or hydration) uses JS value with CR.
+ // Client rendering (or hydration without enableClientRenderFallbackOnTextMismatch) uses JS value with CR.
// Null character stays.
+
expectNode(
e.childNodes[0],
TEXT_NODE_TYPE,
@@ -860,17 +876,23 @@ describe('ReactDOMServerIntegration', () => {
{'\r\nbaz\nqux\u0000'}
,
);
- if (render === serverRender || render === streamRender) {
+ if (
+ render === serverRender ||
+ render === streamRender ||
+ (render === clientRenderOnServerString &&
+ ReactFeatureFlags.enableClientRenderFallbackOnTextMismatch)
+ ) {
// We have three nodes because there is a comment between them.
expect(e.childNodes.length).toBe(3);
- // Everything becomes LF when parsed from server HTML.
+ // Everything becomes LF when parsed from server HTML or hydrated if enableClientRenderFallbackOnTextMismatch is on.
// Null character is ignored.
expectNode(e.childNodes[0], TEXT_NODE_TYPE, 'foo\nbar');
expectNode(e.childNodes[2], TEXT_NODE_TYPE, '\nbaz\nqux');
} else if (render === clientRenderOnServerString) {
// We have three nodes because there is a comment between them.
expect(e.childNodes.length).toBe(3);
- // Hydration uses JS value with CR and null character.
+ // Hydration without enableClientRenderFallbackOnTextMismatch uses JS value with CR and null character.
+
expectNode(e.childNodes[0], TEXT_NODE_TYPE, 'foo\rbar');
expectNode(e.childNodes[2], TEXT_NODE_TYPE, '\r\nbaz\nqux\u0000');
} else {
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
index 680f283b6dbf2..8e8fc2aa8fe27 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
@@ -13,7 +13,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -21,13 +21,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
index afbbf28a41ecb..54780dae52cdb 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
@@ -15,7 +15,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
const {disableInputAttributeSyncing} = require('shared/ReactFeatureFlags');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -23,13 +23,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
index e551a72b9ace4..99cf33b821f17 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
@@ -13,7 +13,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -21,13 +21,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
index 76da3e92c82ad..e5564d3d9348c 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
@@ -12,7 +12,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -20,13 +20,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
index f3a8b869ad818..8ea1c9d53baee 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
@@ -13,7 +13,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
let forwardRef;
@@ -26,7 +26,7 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
forwardRef = React.forwardRef;
@@ -44,7 +44,7 @@ function initModules() {
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
index 697ec7f340d88..dd19385e62c56 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
@@ -13,7 +13,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -21,13 +21,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
index b335b03b01d38..bc5980f23dda2 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
@@ -12,7 +12,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -20,13 +20,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js b/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
index b949e0ab522f9..cf51eff4aced3 100644
--- a/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
@@ -13,7 +13,7 @@
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
-let ReactDOM;
+let ReactDOMClient;
let ReactDOMServer;
let ReactTestUtils;
@@ -21,13 +21,13 @@ function initModules() {
// Reset warning cache.
jest.resetModules();
React = require('react');
- ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
- ReactDOM,
+ ReactDOMClient,
ReactDOMServer,
ReactTestUtils,
};
diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
index 8392b57af03cf..e9c4479b028fb 100644
--- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
+++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
@@ -14,11 +14,12 @@ const shouldIgnoreConsoleError = require('../../../../../scripts/jest/shouldIgno
module.exports = function (initModules) {
let ReactDOM;
+ let ReactDOMClient;
let ReactDOMServer;
let act;
function resetModules() {
- ({ReactDOM, ReactDOMServer} = initModules());
+ ({ReactDOM, ReactDOMClient, ReactDOMServer} = initModules());
act = require('internal-test-utils').act;
}
@@ -51,11 +52,24 @@ module.exports = function (initModules) {
async function asyncReactDOMRender(reactElement, domElement, forceHydrate) {
if (forceHydrate) {
await act(() => {
- ReactDOM.hydrate(reactElement, domElement);
+ if (ReactDOMClient) {
+ ReactDOMClient.hydrateRoot(domElement, reactElement, {
+ onRecoverableError: () => {
+ // TODO: assert on recoverable error count.
+ },
+ });
+ } else {
+ ReactDOM.hydrate(reactElement, domElement);
+ }
});
} else {
await act(() => {
- ReactDOM.render(reactElement, domElement);
+ if (ReactDOMClient) {
+ const root = ReactDOMClient.createRoot(domElement);
+ root.render(reactElement);
+ } else {
+ ReactDOM.render(reactElement, domElement);
+ }
});
}
}
@@ -80,7 +94,11 @@ module.exports = function (initModules) {
for (let i = 0; i < console.error.mock.calls.length; i++) {
const args = console.error.mock.calls[i];
const [format, ...rest] = args;
- if (!shouldIgnoreConsoleError(format, rest)) {
+ if (
+ !shouldIgnoreConsoleError(format, rest, {
+ TODO_ignoreHydrationErrors: true,
+ })
+ ) {
filteredWarnings.push(args);
}
}
diff --git a/scripts/jest/shouldIgnoreConsoleError.js b/scripts/jest/shouldIgnoreConsoleError.js
index 42aae220debed..79ec7fc2ad7d6 100644
--- a/scripts/jest/shouldIgnoreConsoleError.js
+++ b/scripts/jest/shouldIgnoreConsoleError.js
@@ -1,6 +1,10 @@
'use strict';
-module.exports = function shouldIgnoreConsoleError(format, args) {
+module.exports = function shouldIgnoreConsoleError(
+ format,
+ args,
+ {TODO_ignoreHydrationErrors} = {TODO_ignoreHydrationErrors: false}
+) {
if (__DEV__) {
if (typeof format === 'string') {
if (format.indexOf('Error: Uncaught [') === 0) {
@@ -23,6 +27,15 @@ module.exports = function shouldIgnoreConsoleError(format, args) {
// We haven't finished migrating our tests to use createRoot.
return true;
}
+ if (
+ TODO_ignoreHydrationErrors &&
+ format.indexOf(
+ 'An error occurred during hydration. The server HTML was replaced with client content in'
+ ) !== -1
+ ) {
+ // This also gets logged by onRecoverableError, so we can ignore it.
+ return true;
+ }
} else if (
format != null &&
typeof format.message === 'string' &&