main
js 78 lines 2.08 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @emails react-core
8 * @jest-environment node
9 */
10
11 // This is a regression test for https://github.com/facebook/react/issues/13188.
12 // It reproduces a combination of conditions that led to a problem.
13
14 if (global.window) {
15 throw new Error('This test must run in a Node environment.');
16 }
17
18 // The issue only reproduced when React was loaded before JSDOM.
19 const React = require('react');
20 const ReactDOMClient = require('react-dom/client');
21 const Scheduler = require('scheduler');
22
23 // Initialize JSDOM separately.
24 // We don't use our normal JSDOM setup because we want to load React first.
25 const {JSDOM} = require('jsdom');
26 global.requestAnimationFrame = setTimeout;
27 global.cancelAnimationFrame = clearTimeout;
28 const jsdom = new JSDOM(`<div id="app-root"></div>`);
29 global.window = jsdom.window;
30 global.document = jsdom.window.document;
31 global.navigator = jsdom.window.navigator;
32
33 class Bad extends React.Component {
34 componentDidUpdate() {
35 throw new Error('no');
36 }
37 render() {
38 return null;
39 }
40 }
41
42 async function fakeAct(cb) {
43 // We don't use act/waitForThrow here because we want to observe how errors are reported for real.
44 await cb();
45 Scheduler.unstable_flushAll();
46 }
47
48 describe('ReactErrorLoggingRecovery', () => {
49 const originalConsoleError = console.error;
50
51 beforeEach(() => {
52 console.error = error => {
53 throw new Error('Buggy console.error');
54 };
55 });
56
57 afterEach(() => {
58 console.error = originalConsoleError;
59 });
60
61 it('should recover from errors in console.error', async function () {
62 const div = document.createElement('div');
63 const root = ReactDOMClient.createRoot(div);
64 await fakeAct(() => {
65 root.render(<Bad />);
66 });
67 await fakeAct(() => {
68 root.render(<Bad />);
69 });
70
71 expect(() => jest.runAllTimers()).toThrow('');
72
73 await fakeAct(() => {
74 root.render(<span>Hello</span>);
75 });
76 expect(div.firstChild.textContent).toBe('Hello');
77 });
78 });