[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);