@samitouri / QOS-React-2 / commits / ee4699f5a1

[noop] Fail tests on unasserted recoverable errors (#35948)

Sebastian "Sebbie" Silbermann committed Mar 4, 2026 at 13:41 UTC ee4699f5a1833bd12701d21556f36376d6ebad8b
4 files changed +34 -7
packages/react-noop-renderer/src/createReactNoop.js
+3 -3
@@ -1151,9 +1151,9 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1151 }
1152 }
1153
1154 - function onRecoverableError(error) {
1155 - // TODO: Turn this on once tests are fixed
1156 - // console.error(error);
1154 + function onRecoverableError(error: mixed): void {
1155 + // eslint-disable-next-line react-internal/warning-args, react-internal/no-production-logging -- renderer is only used for testing.
1156 + console.error(error);
1157 }
1158 function onDefaultTransitionIndicator(): void | (() => void) {}
1159
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+16
@@ -287,6 +287,10 @@ describe('ReactIncrementalErrorHandling', () => {
287 'commit',
288 'commit',
289 ]);
290 + assertConsoleErrorDev([
291 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
292 + '\n in <stack>',
293 + ]);
294 expect(ReactNoop).toMatchRenderedOutput(
295 <span prop="Everything is fine." />,
296 );
@@ -339,6 +343,10 @@ describe('ReactIncrementalErrorHandling', () => {
343 'commit',
344 'commit',
345 ]);
346 + assertConsoleErrorDev([
347 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
348 + '\n in <stack>',
349 + ]);
350 // This should not include the offscreen content
351 expect(ReactNoop).toMatchRenderedOutput(
352 <>
@@ -1786,6 +1794,10 @@ describe('ReactIncrementalErrorHandling', () => {
1794 });
1795
1796 // Should finish without throwing.
1797 + assertConsoleErrorDev([
1798 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
1799 + '\n in <stack>',
1800 + ]);
1801 expect(root).toMatchRenderedOutput('Everything is fine.');
1802 });
1803
@@ -1832,6 +1844,10 @@ describe('ReactIncrementalErrorHandling', () => {
1844 });
1845 // Should render the final state without throwing the error.
1846 assertLog(['Everything is fine.']);
1847 + assertConsoleErrorDev([
1848 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
1849 + '\n in <stack>',
1850 + ]);
1851 expect(root).toMatchRenderedOutput('Everything is fine.');
1852 });
1853
packages/react-reconciler/src/__tests__/ReactIncrementalErrorReplay-test.js
+6
@@ -12,6 +12,7 @@
12
13 let React;
14 let ReactNoop;
15 +let assertConsoleErrorDev;
16 let waitForAll;
17 let waitForThrow;
18
@@ -22,6 +23,7 @@ describe('ReactIncrementalErrorReplay', () => {
23 ReactNoop = require('react-noop-renderer');
24
25 const InternalTestUtils = require('internal-test-utils');
26 + assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
27 waitForAll = InternalTestUtils.waitForAll;
28 waitForThrow = InternalTestUtils.waitForThrow;
29 });
@@ -50,5 +52,9 @@ describe('ReactIncrementalErrorReplay', () => {
52 }
53 ReactNoop.render(<App />);
54 await waitForAll([]);
55 + assertConsoleErrorDev([
56 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
57 + '\n in <stack>',
58 + ]);
59 });
60 });
packages/react-reconciler/src/__tests__/useMemoCache-test.js
+9 -4
@@ -12,6 +12,7 @@ let React;
12 let ReactNoop;
13 let Scheduler;
14 let act;
15 +let assertConsoleErrorDev;
16 let assertLog;
17 let useMemo;
18 let useState;
@@ -26,8 +27,10 @@ describe('useMemoCache()', () => {
27 React = require('react');
28 ReactNoop = require('react-noop-renderer');
29 Scheduler = require('scheduler');
29 - act = require('internal-test-utils').act;
30 - assertLog = require('internal-test-utils').assertLog;
30 + const InternalTestUtils = require('internal-test-utils');
31 + act = InternalTestUtils.act;
32 + assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
33 + assertLog = InternalTestUtils.assertLog;
34 useMemo = React.useMemo;
35 useMemoCache = require('react/compiler-runtime').c;
36 useState = React.useState;
@@ -256,8 +259,6 @@ describe('useMemoCache()', () => {
259 return `${data.text} (n=${props.n})`;
260 });
261
259 - spyOnDev(console, 'error');
260 -
262 const root = ReactNoop.createRoot();
263 await act(() => {
264 root.render(
@@ -274,6 +275,10 @@ describe('useMemoCache()', () => {
275 // this triggers a throw.
276 setN(1);
277 });
278 + assertConsoleErrorDev([
279 + 'Error: There was an error during concurrent rendering but React was able to recover by instead synchronously rendering the entire root.' +
280 + '\n in <stack>',
281 + ]);
282 expect(root).toMatchRenderedOutput('Count 0 (n=1)');
283 expect(Text).toBeCalledTimes(2);
284 expect(data).toBe(data0);