[DevTools] Throw error in console without interfering with logs (#22175)

This commit is contained in:
Luna Ruan 2021-08-30 14:37:49 -07:00 committed by GitHub
parent 36f0005b99
commit 597ecd6a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 12 deletions

View File

@ -6,20 +6,19 @@
*
* @flow
*/
let React;
let ReactDOM;
let act;
let fakeConsole;
let legacyRender;
let mockError;
let mockInfo;
let mockLog;
let mockWarn;
let patchConsole;
let unpatchConsole;
describe('console', () => {
let React;
let ReactDOM;
let act;
let fakeConsole;
let legacyRender;
let mockError;
let mockInfo;
let mockLog;
let mockWarn;
let patchConsole;
let unpatchConsole;
beforeEach(() => {
jest.resetModules();
@ -553,3 +552,92 @@ describe('console', () => {
expect(mockError.mock.calls[0][0]).toBe('error');
});
});
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();
mockLog = jest.fn();
mockWarn = jest.fn();
fakeConsole = {
error: mockError,
info: mockInfo,
log: mockLog,
warn: mockWarn,
};
Console.dangerous_setTargetConsoleForTesting(fakeConsole);
// Note the Console module only patches once,
// so it's important to patch the test console before injection.
patchConsole({
appendComponentStack: true,
breakOnWarn: false,
showInlineWarningsAndErrors: false,
hideDoubleLogsInStrictLegacy: false,
});
const inject = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject;
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = internals => {
internals.getIsStrictMode = () => {
throw Error('foo');
};
inject(internals);
Console.registerRenderer(internals);
};
React = require('react');
ReactDOM = require('react-dom');
const utils = require('./utils');
act = utils.act;
legacyRender = utils.legacyRender;
});
it('error in console log throws without interfering with logging', () => {
const container = document.createElement('div');
const root = ReactDOM.createRoot(container);
function App() {
fakeConsole.log('log');
fakeConsole.warn('warn');
fakeConsole.error('error');
return <div />;
}
patchConsole({
appendComponentStack: true,
breakOnWarn: false,
showInlineWarningsAndErrors: false,
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');
});
});

View File

@ -222,6 +222,9 @@ export function patch({
}
} catch (error) {
// Don't let a DevTools or React internal error interfere with logging.
setTimeout(() => {
throw error;
}, 0);
} finally {
break;
}