mirror of
https://github.com/facebook/react.git
synced 2026-02-22 03:42:05 +00:00
Before: <img width="844" alt="Screenshot 2024-07-04 at 3 20 34 PM" src="https://github.com/facebook/react/assets/63648/0fd8a53f-538a-4429-a4cf-c22f85a09aa8"> After: <img width="845" alt="Screenshot 2024-07-05 at 6 08 28 PM" src="https://github.com/facebook/react/assets/63648/7b9da13a-fa97-4581-9899-06de6fface65"> Firefox: <img width="1338" alt="Screenshot 2024-07-05 at 6 09 50 PM" src="https://github.com/facebook/react/assets/63648/f2eb9f2a-2251-408f-86d0-b081279ba378"> The first log doesn't get a stack because it's logged before DevTools boots up and connects which is unfortunate. The second log already has a stack printed by React (this is on stable) it gets replaced by our object now. The third and following logs don't have a stack and get one appended. I only turn the stack into an error object if it matches what we would emit from DevTools anyway. Otherwise we assume it's not React. Since I had to change the format slightly to make this work, I first normalize the stack slightly before doing a comparison since it won't be 1:1.
1108 lines
36 KiB
JavaScript
1108 lines
36 KiB
JavaScript
/**
|
|
* 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.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import {getVersionedRenderImplementation, normalizeCodeLocInfo} from './utils';
|
|
|
|
let React;
|
|
let ReactDOMClient;
|
|
let act;
|
|
let fakeConsole;
|
|
let mockError;
|
|
let mockInfo;
|
|
let mockGroup;
|
|
let mockGroupCollapsed;
|
|
let mockLog;
|
|
let mockWarn;
|
|
let patchConsole;
|
|
let unpatchConsole;
|
|
let rendererID;
|
|
|
|
describe('console', () => {
|
|
beforeEach(() => {
|
|
const Console = require('react-devtools-shared/src/backend/console');
|
|
|
|
patchConsole = Console.patch;
|
|
unpatchConsole = Console.unpatch;
|
|
|
|
// Patch a fake console so we can verify with tests below.
|
|
// Patching the real console is too complicated,
|
|
// because Jest itself has hooks into it as does our test env setup.
|
|
mockError = jest.fn();
|
|
mockInfo = jest.fn();
|
|
mockGroup = jest.fn();
|
|
mockGroupCollapsed = jest.fn();
|
|
mockLog = jest.fn();
|
|
mockWarn = jest.fn();
|
|
fakeConsole = {
|
|
error: mockError,
|
|
info: mockInfo,
|
|
log: mockLog,
|
|
warn: mockWarn,
|
|
group: mockGroup,
|
|
groupCollapsed: mockGroupCollapsed,
|
|
};
|
|
|
|
Console.dangerous_setTargetConsoleForTesting(fakeConsole);
|
|
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.dangerous_setTargetConsoleForTesting(
|
|
fakeConsole,
|
|
);
|
|
|
|
const inject = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject;
|
|
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = internals => {
|
|
rendererID = inject(internals);
|
|
|
|
Console.registerRenderer(internals);
|
|
return rendererID;
|
|
};
|
|
|
|
React = require('react');
|
|
ReactDOMClient = require('react-dom/client');
|
|
|
|
const utils = require('./utils');
|
|
act = utils.act;
|
|
});
|
|
|
|
const {render} = getVersionedRenderImplementation();
|
|
|
|
// @reactVersion >=18.0
|
|
it('should not patch console methods that are not explicitly overridden', () => {
|
|
expect(fakeConsole.error).not.toBe(mockError);
|
|
expect(fakeConsole.info).toBe(mockInfo);
|
|
expect(fakeConsole.log).toBe(mockLog);
|
|
expect(fakeConsole.warn).not.toBe(mockWarn);
|
|
expect(fakeConsole.group).toBe(mockGroup);
|
|
expect(fakeConsole.groupCollapsed).toBe(mockGroupCollapsed);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should patch the console when appendComponentStack is enabled', () => {
|
|
unpatchConsole();
|
|
|
|
expect(fakeConsole.error).toBe(mockError);
|
|
expect(fakeConsole.warn).toBe(mockWarn);
|
|
|
|
patchConsole({
|
|
appendComponentStack: true,
|
|
breakOnConsoleErrors: false,
|
|
showInlineWarningsAndErrors: false,
|
|
});
|
|
|
|
expect(fakeConsole.error).not.toBe(mockError);
|
|
expect(fakeConsole.warn).not.toBe(mockWarn);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should patch the console when breakOnConsoleErrors is enabled', () => {
|
|
unpatchConsole();
|
|
|
|
expect(fakeConsole.error).toBe(mockError);
|
|
expect(fakeConsole.warn).toBe(mockWarn);
|
|
|
|
patchConsole({
|
|
appendComponentStack: false,
|
|
breakOnConsoleErrors: true,
|
|
showInlineWarningsAndErrors: false,
|
|
});
|
|
|
|
expect(fakeConsole.error).not.toBe(mockError);
|
|
expect(fakeConsole.warn).not.toBe(mockWarn);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should patch the console when showInlineWarningsAndErrors is enabled', () => {
|
|
unpatchConsole();
|
|
|
|
expect(fakeConsole.error).toBe(mockError);
|
|
expect(fakeConsole.warn).toBe(mockWarn);
|
|
|
|
patchConsole({
|
|
appendComponentStack: false,
|
|
breakOnConsoleErrors: false,
|
|
showInlineWarningsAndErrors: true,
|
|
});
|
|
|
|
expect(fakeConsole.error).not.toBe(mockError);
|
|
expect(fakeConsole.warn).not.toBe(mockWarn);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should only patch the console once', () => {
|
|
const {error, warn} = fakeConsole;
|
|
|
|
patchConsole({
|
|
appendComponentStack: true,
|
|
breakOnConsoleErrors: false,
|
|
showInlineWarningsAndErrors: false,
|
|
});
|
|
|
|
expect(fakeConsole.error).toBe(error);
|
|
expect(fakeConsole.warn).toBe(warn);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should un-patch when requested', () => {
|
|
expect(fakeConsole.error).not.toBe(mockError);
|
|
expect(fakeConsole.warn).not.toBe(mockWarn);
|
|
|
|
unpatchConsole();
|
|
|
|
expect(fakeConsole.error).toBe(mockError);
|
|
expect(fakeConsole.warn).toBe(mockWarn);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should pass through logs when there is no current fiber', () => {
|
|
expect(mockLog).toHaveBeenCalledTimes(0);
|
|
expect(mockWarn).toHaveBeenCalledTimes(0);
|
|
expect(mockError).toHaveBeenCalledTimes(0);
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should not append multiple stacks', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
|
|
|
|
const Child = ({children}) => {
|
|
fakeConsole.warn('warn\n in Child (at fake.js:123)');
|
|
fakeConsole.error('error', '\n in Child (at fake.js:123)');
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Child />));
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe(
|
|
'warn\n in Child (at fake.js:123)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(mockError.mock.calls[0][1]).toBe('\n in Child (at fake.js:123)');
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should append component stacks to errors and warnings logged during render', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
|
|
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
const Child = ({children}) => {
|
|
fakeConsole.error('error');
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Parent />));
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should append component stacks to errors and warnings logged from effects', () => {
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
const Child = ({children}) => {
|
|
React.useLayoutEffect(() => {
|
|
fakeConsole.error('active error');
|
|
fakeConsole.log('active log');
|
|
fakeConsole.warn('active warn');
|
|
});
|
|
React.useEffect(() => {
|
|
fakeConsole.error('passive error');
|
|
fakeConsole.log('passive log');
|
|
fakeConsole.warn('passive warn');
|
|
});
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Parent />));
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(2);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('active log');
|
|
expect(mockLog.mock.calls[1]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[1][0]).toBe('passive log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('active warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1][0]).toBe('passive warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('active error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1][0]).toBe('passive error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should append component stacks to errors and warnings logged from commit hooks', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
|
|
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
class Child extends React.Component<any> {
|
|
componentDidMount() {
|
|
fakeConsole.error('didMount error');
|
|
fakeConsole.log('didMount log');
|
|
fakeConsole.warn('didMount warn');
|
|
}
|
|
componentDidUpdate() {
|
|
fakeConsole.error('didUpdate error');
|
|
fakeConsole.log('didUpdate log');
|
|
fakeConsole.warn('didUpdate warn');
|
|
}
|
|
render() {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
act(() => render(<Parent />));
|
|
act(() => render(<Parent />));
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(2);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('didMount log');
|
|
expect(mockLog.mock.calls[1]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[1][0]).toBe('didUpdate log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('didMount warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1][0]).toBe('didUpdate warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('didMount error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1][0]).toBe('didUpdate error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should append component stacks to errors and warnings logged from gDSFP', () => {
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
class Child extends React.Component<any, any> {
|
|
state = {};
|
|
static getDerivedStateFromProps() {
|
|
fakeConsole.error('error');
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
return null;
|
|
}
|
|
render() {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
act(() => render(<Parent />));
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should append stacks after being uninstalled and reinstalled', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
|
|
const Child = ({children}) => {
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Child />));
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
|
|
patchConsole({
|
|
appendComponentStack: true,
|
|
breakOnConsoleErrors: false,
|
|
showInlineWarningsAndErrors: false,
|
|
});
|
|
act(() => render(<Child />));
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1][0]).toBe('warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual(
|
|
'\n in Child (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1][0]).toBe('error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe(
|
|
'\n in Child (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should be resilient to prepareStackTrace', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
|
|
|
|
Error.prepareStackTrace = function (error, callsites) {
|
|
const stack = ['An error occurred:', error.message];
|
|
for (let i = 0; i < callsites.length; i++) {
|
|
const callsite = callsites[i];
|
|
stack.push(
|
|
'\t' + callsite.getFunctionName(),
|
|
'\t\tat ' + callsite.getFileName(),
|
|
'\t\ton line ' + callsite.getLineNumber(),
|
|
);
|
|
}
|
|
|
|
return stack.join('\n');
|
|
};
|
|
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
const Child = ({children}) => {
|
|
fakeConsole.error('error');
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Parent />));
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('should correctly log Symbols', () => {
|
|
const Component = ({children}) => {
|
|
fakeConsole.warn('Symbol:', Symbol(''));
|
|
return null;
|
|
};
|
|
|
|
act(() => render(<Component />));
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('Symbol:');
|
|
});
|
|
|
|
it('should double log if hideConsoleLogsInStrictMode is disabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
fakeConsole.info('info');
|
|
fakeConsole.group('group');
|
|
fakeConsole.groupCollapsed('groupCollapsed');
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockLog.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'log',
|
|
]);
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'warn',
|
|
]);
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'error',
|
|
]);
|
|
|
|
expect(mockInfo).toHaveBeenCalledTimes(2);
|
|
expect(mockInfo.mock.calls[0]).toHaveLength(1);
|
|
expect(mockInfo.mock.calls[0][0]).toBe('info');
|
|
expect(mockInfo.mock.calls[1]).toHaveLength(2);
|
|
expect(mockInfo.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'info',
|
|
]);
|
|
|
|
expect(mockGroup).toHaveBeenCalledTimes(2);
|
|
expect(mockGroup.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroup.mock.calls[0][0]).toBe('group');
|
|
expect(mockGroup.mock.calls[1]).toHaveLength(2);
|
|
expect(mockGroup.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'group',
|
|
]);
|
|
|
|
expect(mockGroupCollapsed).toHaveBeenCalledTimes(2);
|
|
expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed');
|
|
expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2);
|
|
expect(mockGroupCollapsed.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'groupCollapsed',
|
|
]);
|
|
});
|
|
|
|
it('should not double log if hideConsoleLogsInStrictMode is enabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
console.log(
|
|
'CALL',
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__,
|
|
);
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
fakeConsole.info('info');
|
|
fakeConsole.group('group');
|
|
fakeConsole.groupCollapsed('groupCollapsed');
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
|
|
expect(mockInfo).toHaveBeenCalledTimes(1);
|
|
expect(mockInfo.mock.calls[0]).toHaveLength(1);
|
|
expect(mockInfo.mock.calls[0][0]).toBe('info');
|
|
|
|
expect(mockGroup).toHaveBeenCalledTimes(1);
|
|
expect(mockGroup.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroup.mock.calls[0][0]).toBe('group');
|
|
|
|
expect(mockGroupCollapsed).toHaveBeenCalledTimes(1);
|
|
expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed');
|
|
});
|
|
|
|
it('should double log from Effects if hideConsoleLogsInStrictMode is disabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
React.useEffect(() => {
|
|
fakeConsole.log('log effect create');
|
|
fakeConsole.warn('warn effect create');
|
|
fakeConsole.error('error effect create');
|
|
fakeConsole.info('info effect create');
|
|
fakeConsole.group('group effect create');
|
|
fakeConsole.groupCollapsed('groupCollapsed effect create');
|
|
|
|
return () => {
|
|
fakeConsole.log('log effect cleanup');
|
|
fakeConsole.warn('warn effect cleanup');
|
|
fakeConsole.error('error effect cleanup');
|
|
fakeConsole.info('info effect cleanup');
|
|
fakeConsole.group('group effect cleanup');
|
|
fakeConsole.groupCollapsed('groupCollapsed effect cleanup');
|
|
};
|
|
});
|
|
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
expect(mockLog.mock.calls).toEqual([
|
|
['log effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect create'],
|
|
]);
|
|
expect(mockWarn.mock.calls).toEqual([
|
|
['warn effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect create'],
|
|
]);
|
|
expect(mockError.mock.calls).toEqual([
|
|
['error effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect create'],
|
|
]);
|
|
expect(mockInfo.mock.calls).toEqual([
|
|
['info effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect create'],
|
|
]);
|
|
expect(mockGroup.mock.calls).toEqual([
|
|
['group effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect create'],
|
|
]);
|
|
expect(mockGroupCollapsed.mock.calls).toEqual([
|
|
['groupCollapsed effect create'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect cleanup'],
|
|
['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect create'],
|
|
]);
|
|
});
|
|
|
|
it('should not double log from Effects if hideConsoleLogsInStrictMode is enabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
React.useEffect(() => {
|
|
fakeConsole.log('log effect create');
|
|
fakeConsole.warn('warn effect create');
|
|
fakeConsole.error('error effect create');
|
|
fakeConsole.info('info effect create');
|
|
fakeConsole.group('group effect create');
|
|
fakeConsole.groupCollapsed('groupCollapsed effect create');
|
|
|
|
return () => {
|
|
fakeConsole.log('log effect cleanup');
|
|
fakeConsole.warn('warn effect cleanup');
|
|
fakeConsole.error('error effect cleanup');
|
|
fakeConsole.info('info effect cleanup');
|
|
fakeConsole.group('group effect cleanup');
|
|
fakeConsole.groupCollapsed('groupCollapsed effect cleanup');
|
|
};
|
|
});
|
|
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
expect(mockLog.mock.calls).toEqual([['log effect create']]);
|
|
expect(mockWarn.mock.calls).toEqual([['warn effect create']]);
|
|
expect(mockError.mock.calls).toEqual([['error effect create']]);
|
|
expect(mockInfo.mock.calls).toEqual([['info effect create']]);
|
|
expect(mockGroup.mock.calls).toEqual([['group effect create']]);
|
|
expect(mockGroupCollapsed.mock.calls).toEqual([
|
|
['groupCollapsed effect create'],
|
|
]);
|
|
});
|
|
|
|
it('should double log from useMemo if hideConsoleLogsInStrictMode is disabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
React.useMemo(() => {
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
fakeConsole.info('info');
|
|
fakeConsole.group('group');
|
|
fakeConsole.groupCollapsed('groupCollapsed');
|
|
}, []);
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockLog.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'log',
|
|
]);
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'warn',
|
|
]);
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'error',
|
|
]);
|
|
|
|
expect(mockInfo).toHaveBeenCalledTimes(2);
|
|
expect(mockInfo.mock.calls[0]).toHaveLength(1);
|
|
expect(mockInfo.mock.calls[0][0]).toBe('info');
|
|
expect(mockInfo.mock.calls[1]).toHaveLength(2);
|
|
expect(mockInfo.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'info',
|
|
]);
|
|
|
|
expect(mockGroup).toHaveBeenCalledTimes(2);
|
|
expect(mockGroup.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroup.mock.calls[0][0]).toBe('group');
|
|
expect(mockGroup.mock.calls[1]).toHaveLength(2);
|
|
expect(mockGroup.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'group',
|
|
]);
|
|
|
|
expect(mockGroupCollapsed).toHaveBeenCalledTimes(2);
|
|
expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed');
|
|
expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2);
|
|
expect(mockGroupCollapsed.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'groupCollapsed',
|
|
]);
|
|
});
|
|
|
|
it('should not double log from useMemo fns if hideConsoleLogsInStrictMode is enabled in Strict mode', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
React.useMemo(() => {
|
|
console.log(
|
|
'CALL',
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__,
|
|
);
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
fakeConsole.info('info');
|
|
fakeConsole.group('group');
|
|
fakeConsole.groupCollapsed('groupCollapsed');
|
|
}, []);
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
|
|
expect(mockInfo).toHaveBeenCalledTimes(1);
|
|
expect(mockInfo.mock.calls[0]).toHaveLength(1);
|
|
expect(mockInfo.mock.calls[0][0]).toBe('info');
|
|
|
|
expect(mockGroup).toHaveBeenCalledTimes(1);
|
|
expect(mockGroup.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroup.mock.calls[0][0]).toBe('group');
|
|
|
|
expect(mockGroupCollapsed).toHaveBeenCalledTimes(1);
|
|
expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1);
|
|
expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed');
|
|
});
|
|
|
|
it('should double log in Strict mode initial render for extension', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
|
|
|
|
// This simulates a render that happens before React DevTools have finished
|
|
// their handshake to attach the React DOM renderer functions to DevTools
|
|
// In this case, we should still be able to mock the console in Strict mode
|
|
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.set(
|
|
rendererID,
|
|
null,
|
|
);
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(2);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
expect(mockLog.mock.calls[1]).toHaveLength(2);
|
|
expect(mockLog.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'log',
|
|
]);
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(2);
|
|
expect(mockWarn.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'warn',
|
|
]);
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
expect(mockError.mock.calls[1]).toHaveLength(2);
|
|
expect(mockError.mock.calls[1]).toEqual([
|
|
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
|
|
'error',
|
|
]);
|
|
});
|
|
|
|
it('should not double log in Strict mode initial render for extension', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
|
|
|
|
// This simulates a render that happens before React DevTools have finished
|
|
// their handshake to attach the React DOM renderer functions to DevTools
|
|
// In this case, we should still be able to mock the console in Strict mode
|
|
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.set(
|
|
rendererID,
|
|
null,
|
|
);
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
return <div />;
|
|
}
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
});
|
|
|
|
it('should properly dim component stacks during strict mode double log', () => {
|
|
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
|
|
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
|
|
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
const Intermediate = ({children}) => children;
|
|
const Parent = ({children}) => (
|
|
<Intermediate>
|
|
<Child />
|
|
</Intermediate>
|
|
);
|
|
const Child = ({children}) => {
|
|
fakeConsole.error('error');
|
|
fakeConsole.warn('warn');
|
|
return null;
|
|
};
|
|
|
|
act(() =>
|
|
root.render(
|
|
<React.StrictMode>
|
|
<Parent />
|
|
</React.StrictMode>,
|
|
),
|
|
);
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(2);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(2);
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockWarn.mock.calls[1]).toHaveLength(3);
|
|
expect(mockWarn.mock.calls[1][0]).toEqual(
|
|
'\x1b[2;38;2;124;124;124m%s %o\x1b[0m',
|
|
);
|
|
expect(mockWarn.mock.calls[1][1]).toMatch('warn');
|
|
expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][2]).trim()).toEqual(
|
|
'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(2);
|
|
expect(mockError.mock.calls[0]).toHaveLength(2);
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toEqual(
|
|
'\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
expect(mockError.mock.calls[1]).toHaveLength(3);
|
|
expect(mockError.mock.calls[1][0]).toEqual(
|
|
'\x1b[2;38;2;124;124;124m%s %o\x1b[0m',
|
|
);
|
|
expect(mockError.mock.calls[1][1]).toEqual('error');
|
|
expect(normalizeCodeLocInfo(mockError.mock.calls[1][2]).trim()).toEqual(
|
|
'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('console error', () => {
|
|
beforeEach(() => {
|
|
jest.resetModules();
|
|
|
|
const Console = require('react-devtools-shared/src/backend/console');
|
|
patchConsole = Console.patch;
|
|
unpatchConsole = Console.unpatch;
|
|
|
|
// Patch a fake console so we can verify with tests below.
|
|
// Patching the real console is too complicated,
|
|
// because Jest itself has hooks into it as does our test env setup.
|
|
mockError = jest.fn();
|
|
mockInfo = jest.fn();
|
|
mockGroup = jest.fn();
|
|
mockGroupCollapsed = jest.fn();
|
|
mockLog = jest.fn();
|
|
mockWarn = jest.fn();
|
|
fakeConsole = {
|
|
error: mockError,
|
|
info: mockInfo,
|
|
log: mockLog,
|
|
warn: mockWarn,
|
|
group: mockGroup,
|
|
groupCollapsed: mockGroupCollapsed,
|
|
};
|
|
|
|
Console.dangerous_setTargetConsoleForTesting(fakeConsole);
|
|
|
|
const inject = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject;
|
|
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = internals => {
|
|
inject(internals);
|
|
|
|
Console.registerRenderer(internals, () => {
|
|
throw Error('foo');
|
|
});
|
|
};
|
|
|
|
React = require('react');
|
|
ReactDOMClient = require('react-dom/client');
|
|
|
|
const utils = require('./utils');
|
|
act = utils.act;
|
|
});
|
|
|
|
// @reactVersion >=18.0
|
|
it('error in console log throws without interfering with logging', () => {
|
|
const container = document.createElement('div');
|
|
const root = ReactDOMClient.createRoot(container);
|
|
|
|
function App() {
|
|
fakeConsole.log('log');
|
|
fakeConsole.warn('warn');
|
|
fakeConsole.error('error');
|
|
return <div />;
|
|
}
|
|
|
|
patchConsole({
|
|
appendComponentStack: true,
|
|
breakOnConsoleErrors: false,
|
|
showInlineWarningsAndErrors: true,
|
|
hideConsoleLogsInStrictMode: false,
|
|
});
|
|
|
|
expect(() => {
|
|
act(() => {
|
|
root.render(<App />);
|
|
});
|
|
}).toThrowError('foo');
|
|
|
|
expect(mockLog).toHaveBeenCalledTimes(1);
|
|
expect(mockLog.mock.calls[0]).toHaveLength(1);
|
|
expect(mockLog.mock.calls[0][0]).toBe('log');
|
|
|
|
expect(mockWarn).toHaveBeenCalledTimes(1);
|
|
expect(mockWarn.mock.calls[0]).toHaveLength(1);
|
|
expect(mockWarn.mock.calls[0][0]).toBe('warn');
|
|
|
|
expect(mockError).toHaveBeenCalledTimes(1);
|
|
expect(mockError.mock.calls[0]).toHaveLength(1);
|
|
expect(mockError.mock.calls[0][0]).toBe('error');
|
|
});
|
|
});
|