diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index 0320272b9cbb4..f895bbd55e71b 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -1812,83 +1812,59 @@ describe('ReactDOMFizzServer', () => {
);
}
- // We can't use the toErrorDev helper here because this is an async act.
- const originalConsoleError = console.error;
- const mockError = jest.fn();
- console.error = (...args) => {
- mockError(...args.map(normalizeCodeLocInfo));
- };
-
- try {
- await act(() => {
- const {pipe} = renderToPipeableStream();
- pipe(writable);
- });
+ await act(() => {
+ const {pipe} = renderToPipeableStream();
+ pipe(writable);
+ });
- expect(getVisibleChildren(container)).toEqual(
-
@@ -4701,45 +4671,40 @@ describe('ReactDOMFizzServer', () => {
);
};
- try {
- await act(() => {
- const {pipe} = renderToPipeableStream(
);
- pipe(writable);
- });
+ await act(() => {
+ const {pipe} = renderToPipeableStream(
);
+ pipe(writable);
+ });
- expect(getVisibleChildren(container)).toEqual(
-
-
initial
- initial
- initial
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
initial
+ initial
+ initial
+ ,
+ );
- ReactDOMClient.hydrateRoot(container,
, {
- onRecoverableError(error) {
- Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
- if (error.cause) {
- Scheduler.log('Cause: ' + normalizeError(error.cause.message));
- }
- },
- });
- await waitForAll([
- "onRecoverableError: Hydration failed because the server rendered HTML didn't match the client.",
- ]);
+ ReactDOMClient.hydrateRoot(container,
, {
+ onRecoverableError(error) {
+ Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
+ if (error.cause) {
+ Scheduler.log('Cause: ' + normalizeError(error.cause.message));
+ }
+ },
+ });
+ await waitForAll([
+ "onRecoverableError: Hydration failed because the server rendered HTML didn't match the client.",
+ ]);
- expect(getVisibleChildren(container)).toEqual(
-
-
replaced
- replaced
- replaced
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
replaced
+ replaced
+ replaced
+ ,
+ );
- await waitForAll([]);
- expect(mockError.mock.calls.length).toBe(0);
- } finally {
- console.error = originalConsoleError;
- }
+ await waitForAll([]);
});
it('supresses hydration warnings when an error occurs within a Suspense boundary', async () => {
@@ -4815,18 +4780,6 @@ describe('ReactDOMFizzServer', () => {
});
it('does not log for errors after the first hydration error', async () => {
- // We can't use the toErrorDev helper here because this is async.
- const originalConsoleError = console.error;
- const mockError = jest.fn();
- console.error = (...args) => {
- if (args.length > 1) {
- if (typeof args[1] === 'object') {
- mockError(args[0].split('\n')[0]);
- return;
- }
- }
- mockError(...args.map(normalizeCodeLocInfo));
- };
let isClient = false;
function ThrowWhenHydrating({children, message}) {
@@ -4864,69 +4817,50 @@ describe('ReactDOMFizzServer', () => {
);
};
- try {
- await act(() => {
- const {pipe} = renderToPipeableStream(
);
- pipe(writable);
- });
+ await act(() => {
+ const {pipe} = renderToPipeableStream(
);
+ pipe(writable);
+ });
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
- isClient = true;
+ isClient = true;
- ReactDOMClient.hydrateRoot(container,
, {
- onRecoverableError(error) {
- Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
- if (error.cause) {
- Scheduler.log('Cause: ' + normalizeError(error.cause.message));
- }
- },
- });
- await waitForAll([
- 'throwing: first error',
+ ReactDOMClient.hydrateRoot(container,
, {
+ onRecoverableError(error) {
+ Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
+ if (error.cause) {
+ Scheduler.log('Cause: ' + normalizeError(error.cause.message));
+ }
+ },
+ });
+ await waitForAll([
+ 'throwing: first error',
- // onRecoverableError because the UI recovered without surfacing the
- // error to the user.
- 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
- 'Cause: first error',
- ]);
- expect(mockError.mock.calls).toEqual([]);
- mockError.mockClear();
+ // onRecoverableError because the UI recovered without surfacing the
+ // error to the user.
+ 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
+ 'Cause: first error',
+ ]);
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
- await waitForAll([]);
- expect(mockError.mock.calls).toEqual([]);
- } finally {
- console.error = originalConsoleError;
- }
+ await waitForAll([]);
});
it('does not log for errors after a preceding fiber suspends', async () => {
- // We can't use the toErrorDev helper here because this is async.
- const originalConsoleError = console.error;
- const mockError = jest.fn();
- console.error = (...args) => {
- if (args.length > 1) {
- if (typeof args[1] === 'object') {
- mockError(args[0].split('\n')[0]);
- return;
- }
- }
- mockError(...args.map(normalizeCodeLocInfo));
- };
let isClient = false;
let promise = null;
let unsuspend = null;
@@ -4984,56 +4918,51 @@ describe('ReactDOMFizzServer', () => {
);
};
- try {
- await act(() => {
- const {pipe} = renderToPipeableStream(
);
- pipe(writable);
- });
+ await act(() => {
+ const {pipe} = renderToPipeableStream(
);
+ pipe(writable);
+ });
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
- isClient = true;
+ isClient = true;
- ReactDOMClient.hydrateRoot(container,
, {
- onRecoverableError(error) {
- Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
- if (error.cause) {
- Scheduler.log('Cause: ' + normalizeError(error.cause.message));
- }
- },
- });
- await waitForAll(['suspending']);
- expect(mockError.mock.calls).toEqual([]);
+ ReactDOMClient.hydrateRoot(container,
, {
+ onRecoverableError(error) {
+ Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
+ if (error.cause) {
+ Scheduler.log('Cause: ' + normalizeError(error.cause.message));
+ }
+ },
+ });
+ await waitForAll(['suspending']);
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
- await unsuspend();
- await waitForAll([
- 'throwing: first error',
- 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
- 'Cause: first error',
- ]);
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
- } finally {
- console.error = originalConsoleError;
- }
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
+ await unsuspend();
+ await waitForAll([
+ 'throwing: first error',
+ 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
+ 'Cause: first error',
+ ]);
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
});
it('(outdated behavior) suspending after erroring will cause errors previously queued to be silenced until the boundary resolves', async () => {
@@ -5042,18 +4971,6 @@ describe('ReactDOMFizzServer', () => {
// stack and revert to client rendering. I've kept the test around just to
// demonstrate what actually happens in this sequence of events.
- // We can't use the toErrorDev helper here because this is async.
- const originalConsoleError = console.error;
- const mockError = jest.fn();
- console.error = (...args) => {
- if (args.length > 1) {
- if (typeof args[1] === 'object') {
- mockError(args[0].split('\n')[0]);
- return;
- }
- }
- mockError(...args.map(normalizeCodeLocInfo));
- };
let isClient = false;
let promise = null;
let unsuspend = null;
@@ -5111,60 +5028,53 @@ describe('ReactDOMFizzServer', () => {
);
};
- try {
- await act(() => {
- const {pipe} = renderToPipeableStream(
);
- pipe(writable);
- });
+ await act(() => {
+ const {pipe} = renderToPipeableStream(
);
+ pipe(writable);
+ });
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
- isClient = true;
+ isClient = true;
- ReactDOMClient.hydrateRoot(container,
, {
- onRecoverableError(error) {
- Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
- if (error.cause) {
- Scheduler.log('Cause: ' + normalizeError(error.cause.message));
- }
- },
- });
- await waitForAll([
- 'throwing: first error',
- 'suspending',
- 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
- 'Cause: first error',
- ]);
- expect(mockError.mock.calls).toEqual([]);
- mockError.mockClear();
+ ReactDOMClient.hydrateRoot(container,
, {
+ onRecoverableError(error) {
+ Scheduler.log('onRecoverableError: ' + normalizeError(error.message));
+ if (error.cause) {
+ Scheduler.log('Cause: ' + normalizeError(error.cause.message));
+ }
+ },
+ });
+ await waitForAll([
+ 'throwing: first error',
+ 'suspending',
+ 'onRecoverableError: There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.',
+ 'Cause: first error',
+ ]);
- expect(getVisibleChildren(container)).toEqual(
-
-
Loading...
- ,
- );
- await clientAct(() => unsuspend());
- // Since our client components only throw on the very first render there are no
- // new throws in this pass
- assertLog([]);
- expect(mockError.mock.calls).toEqual([]);
+ expect(getVisibleChildren(container)).toEqual(
+
+
Loading...
+ ,
+ );
+ await clientAct(() => unsuspend());
+ // Since our client components only throw on the very first render there are no
+ // new throws in this pass
+ assertLog([]);
- expect(getVisibleChildren(container)).toEqual(
-
-
one
- two
- three
- ,
- );
- } finally {
- console.error = originalConsoleError;
- }
+ expect(getVisibleChildren(container)).toEqual(
+
+
one
+ two
+ three
+ ,
+ );
});
it('#24578 Hydration errors caused by a suspending component should not become recoverable when nested in an ancestor Suspense that is showing primary content', async () => {
@@ -6541,11 +6451,6 @@ describe('ReactDOMFizzServer', () => {
function MyScript() {
return 'bar();';
}
- const originalConsoleError = console.error;
- const mockError = jest.fn();
- console.error = (...args) => {
- mockError(...args.map(normalizeCodeLocInfo));
- };
function App() {
return (
@@ -6563,47 +6468,31 @@ describe('ReactDOMFizzServer', () => {
);
}
- try {
- await act(async () => {
- const {pipe} = renderToPipeableStream(
);
- pipe(writable);
- });
+ await act(async () => {
+ const {pipe} = renderToPipeableStream(
);
+ pipe(writable);
+ });
- if (__DEV__) {
- expect(mockError.mock.calls.length).toBe(3);
- expect(mockError.mock.calls[0]).toEqual([
- 'A script element was rendered with %s. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.%s',
- 'a number for children',
- componentStack(
- gate(flags => flags.enableOwnerStacks)
- ? ['script', 'App']
- : ['script', 'body', 'html', 'App'],
- ),
- ]);
- expect(mockError.mock.calls[1]).toEqual([
- 'A script element was rendered with %s. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.%s',
- 'an array for children',
- componentStack(
- gate(flags => flags.enableOwnerStacks)
- ? ['script', 'App']
- : ['script', 'body', 'html', 'App'],
- ),
- ]);
- expect(mockError.mock.calls[2]).toEqual([
- 'A script element was rendered with %s. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.%s',
- 'something unexpected for children',
- componentStack(
- gate(flags => flags.enableOwnerStacks)
- ? ['script', 'App']
- : ['script', 'body', 'html', 'App'],
- ),
- ]);
- } else {
- expect(mockError.mock.calls.length).toBe(0);
- }
- } finally {
- console.error = originalConsoleError;
- }
+ assertConsoleErrorDev([
+ 'A script element was rendered with a number for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
+ componentStack(
+ gate(flags => flags.enableOwnerStacks)
+ ? ['script', 'App']
+ : ['script', 'body', 'html', 'App'],
+ ),
+ 'A script element was rendered with an array for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
+ componentStack(
+ gate(flags => flags.enableOwnerStacks)
+ ? ['script', 'App']
+ : ['script', 'body', 'html', 'App'],
+ ),
+ 'A script element was rendered with something unexpected for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
+ componentStack(
+ gate(flags => flags.enableOwnerStacks)
+ ? ['script', 'App']
+ : ['script', 'body', 'html', 'App'],
+ ),
+ ]);
});
// @gate enablePostpone
diff --git a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js b/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
index c96c381a617a0..98303dc4603fd 100644
--- a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
@@ -7,6 +7,7 @@ let useState;
let useEffect;
let startTransition;
let assertLog;
+let assertConsoleErrorDev;
let waitForPaint;
// TODO: Migrate tests to React DOM instead of React Noop
@@ -26,6 +27,7 @@ describe('ReactFlushSync', () => {
const InternalTestUtils = require('internal-test-utils');
assertLog = InternalTestUtils.assertLog;
+ assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
waitForPaint = InternalTestUtils.waitForPaint;
});
@@ -77,8 +79,6 @@ describe('ReactFlushSync', () => {
}
it('changes priority of updates in useEffect', async () => {
- spyOnDev(console, 'error').mockImplementation(() => {});
-
function App() {
const [syncState, setSyncState] = useState(0);
const [state, setState] = useState(0);
@@ -107,18 +107,15 @@ describe('ReactFlushSync', () => {
// The remaining update is not sync
ReactDOM.flushSync();
assertLog([]);
+ assertConsoleErrorDev([
+ 'flushSync was called from inside a lifecycle method. React ' +
+ 'cannot flush when React is already rendering. Consider moving this ' +
+ 'call to a scheduler task or micro task.',
+ ]);
await waitForPaint([]);
});
expect(getVisibleChildren(container)).toEqual('1, 1');
-
- if (__DEV__) {
- expect(console.error.mock.calls[0][0]).toContain(
- 'flushSync was called from inside a lifecycle method. React ' +
- 'cannot flush when React is already rendering. Consider moving this ' +
- 'call to a scheduler task or micro task.%s',
- );
- }
});
it('supports nested flushSync with startTransition', async () => {