mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Remove ReactDOM.render tests in ReactDOMConsoleErrorReporting-test (#28053)
Each it block here was duplicated to cover ReactDOM.render and ReactDOMClient.createRoot. Here we delete the ReactDOM.render coverage. Co-authored-by: Jack Pope <jackpope@meta.com>
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
describe('ReactDOMConsoleErrorReporting', () => {
|
||||
let act;
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMClient;
|
||||
|
||||
let ErrorBoundary;
|
||||
@@ -23,7 +22,6 @@ describe('ReactDOMConsoleErrorReporting', () => {
|
||||
jest.resetModules();
|
||||
act = require('internal-test-utils').act;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMClient = require('react-dom/client');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
@@ -607,537 +605,4 @@ describe('ReactDOMConsoleErrorReporting', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ReactDOM.render', () => {
|
||||
it('logs errors during event handlers', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
throw Error('Boom');
|
||||
}}>
|
||||
click me
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
});
|
||||
|
||||
await act(() => {
|
||||
container.firstChild.dispatchEvent(
|
||||
new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// This one is jsdom-only. Real browser deduplicates it.
|
||||
// (In DEV, we have a nested event due to guarded callback.)
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// This one is jsdom-only. Real browser deduplicates it.
|
||||
// (In DEV, we have a nested event due to guarded callback.)
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs render errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
throw Error('Boom');
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
}).toThrow('Boom');
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs render errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
throw Error('Boom');
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs layout effect errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useLayoutEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
}).toThrow('Boom');
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs layout effect errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useLayoutEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs passive effect errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
await waitForThrow('Boom');
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs passive effect errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
// Reported due to guarded callback:
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+589
@@ -0,0 +1,589 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('ReactDOMConsoleErrorReporting', () => {
|
||||
let act;
|
||||
let React;
|
||||
let ReactDOM;
|
||||
|
||||
let ErrorBoundary;
|
||||
let NoError;
|
||||
let container;
|
||||
let windowOnError;
|
||||
let waitForThrow;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
act = require('internal-test-utils').act;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
|
||||
ErrorBoundary = class extends React.Component {
|
||||
state = {error: null};
|
||||
static getDerivedStateFromError(error) {
|
||||
return {error};
|
||||
}
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return <h1>Caught: {this.state.error.message}</h1>;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
};
|
||||
NoError = function () {
|
||||
return <h1>OK</h1>;
|
||||
};
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
windowOnError = jest.fn();
|
||||
window.addEventListener('error', windowOnError);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(container);
|
||||
window.removeEventListener('error', windowOnError);
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('ReactDOM.render', () => {
|
||||
it('logs errors during event handlers', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
throw Error('Boom');
|
||||
}}>
|
||||
click me
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
});
|
||||
|
||||
await act(() => {
|
||||
container.firstChild.dispatchEvent(
|
||||
new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// This one is jsdom-only. Real browser deduplicates it.
|
||||
// (In DEV, we have a nested event due to guarded callback.)
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// This one is jsdom-only. Real browser deduplicates it.
|
||||
// (In DEV, we have a nested event due to guarded callback.)
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported because we're in a browser click event:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs render errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
throw Error('Boom');
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
}).toThrow('Boom');
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs render errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
throw Error('Boom');
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs layout effect errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useLayoutEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
}).toThrow('Boom');
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs layout effect errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useLayoutEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs passive effect errors without an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
await waitForThrow('Boom');
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
// Reported due to guarded callback:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('logs passive effect errors with an error boundary', async () => {
|
||||
spyOnDevAndProd(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
React.useEffect(() => {
|
||||
throw Error('Boom');
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
await act(() => {
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Foo />
|
||||
</ErrorBoundary>,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
// Reported due to guarded callback:
|
||||
expect(windowOnError.mock.calls).toEqual([
|
||||
[
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
[
|
||||
// Reported by jsdom due to the guarded callback:
|
||||
expect.objectContaining({
|
||||
detail: expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
type: 'unhandled exception',
|
||||
}),
|
||||
],
|
||||
[
|
||||
// Addendum by React:
|
||||
expect.stringContaining(
|
||||
'The above error occurred in the <Foo> component',
|
||||
),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
// The top-level error was caught with try/catch, and there's no guarded callback,
|
||||
// so in production we don't see an error event.
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[
|
||||
// Reported by React with no extra message:
|
||||
expect.objectContaining({
|
||||
message: 'Boom',
|
||||
}),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Check next render doesn't throw.
|
||||
windowOnError.mockReset();
|
||||
console.error.mockReset();
|
||||
await act(() => {
|
||||
ReactDOM.render(<NoError />, container);
|
||||
});
|
||||
expect(container.textContent).toBe('OK');
|
||||
expect(windowOnError.mock.calls).toEqual([]);
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls).toEqual([
|
||||
[expect.stringContaining('ReactDOM.render is no longer supported')],
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user