Skip to content

Commit

Permalink
[DevTools] Throw error in console without interfering with logs (#22175)
Browse files Browse the repository at this point in the history
  • Loading branch information
lunaruan authored Aug 30, 2021
1 parent 36f0005 commit 597ecd6
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 12 deletions.
112 changes: 100 additions & 12 deletions packages/react-devtools-shared/src/__tests__/console-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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');
});
});
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/backend/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 597ecd6

Please sign in to comment.