diff --git a/packages/react-devtools-shared/src/__tests__/console-test.js b/packages/react-devtools-shared/src/__tests__/console-test.js index 74e9fed9ff..710499ce39 100644 --- a/packages/react-devtools-shared/src/__tests__/console-test.js +++ b/packages/react-devtools-shared/src/__tests__/console-test.js @@ -346,4 +346,51 @@ describe('console', () => { '\n in Child (at **)', ); }); + + it('should be resilient to prepareStackTrace', () => { + 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}) => ( + + + + ); + const Child = ({children}) => { + fakeConsole.error('error'); + fakeConsole.log('log'); + fakeConsole.warn('warn'); + return null; + }; + + act(() => ReactDOM.render(, document.createElement('div'))); + + 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 **)', + ); + }); }); diff --git a/packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js b/packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js index f4aab13ece..b3b306a111 100644 --- a/packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js +++ b/packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js @@ -80,6 +80,10 @@ export function describeNativeComponentFrame( let control; + const previousPrepareStackTrace = Error.prepareStackTrace; + // $FlowFixMe It does accept undefined. + Error.prepareStackTrace = undefined; + reentry = true; let previousDispatcher; if (__DEV__) { @@ -181,6 +185,9 @@ export function describeNativeComponentFrame( } } finally { reentry = false; + + Error.prepareStackTrace = previousPrepareStackTrace; + if (__DEV__) { currentDispatcherRef.current = previousDispatcher; reenableLogs();