DevTools temporarily disable prepareStackTrace before creating custom component stacks (#18717)
Brian Vaughn committed
Apr 23, 2020 at 09:02 UTC
b9fc3d8d59b0de5e4cec1619a3645494af169bae
2 files changed
+54
packages/react-devtools-shared/src/__tests__/console-test.js
+47
@@ -346,4 +346,51 @@ describe('console', () => {
346
'\n in Child (at **)',
347
);
348
});
349
+
350
+ it('should be resilient to prepareStackTrace', () => {
351
+ Error.prepareStackTrace = function(error, callsites) {
352
+ const stack = ['An error occurred:', error.message];
353
+ for (let i = 0; i < callsites.length; i++) {
354
+ const callsite = callsites[i];
355
+ stack.push(
356
+ '\t' + callsite.getFunctionName(),
357
+ '\t\tat ' + callsite.getFileName(),
358
+ '\t\ton line ' + callsite.getLineNumber(),
359
+ );
360
+ }
361
+
362
+ return stack.join('\n');
363
+ };
364
+
365
+ const Intermediate = ({children}) => children;
366
+ const Parent = ({children}) => (
367
+ <Intermediate>
368
+ <Child />
369
+ </Intermediate>
370
+ );
371
+ const Child = ({children}) => {
372
+ fakeConsole.error('error');
373
+ fakeConsole.log('log');
374
+ fakeConsole.warn('warn');
375
+ return null;
376
+ };
377
+
378
+ act(() => ReactDOM.render(<Parent />, document.createElement('div')));
379
+
380
+ expect(mockLog).toHaveBeenCalledTimes(1);
381
+ expect(mockLog.mock.calls[0]).toHaveLength(1);
382
+ expect(mockLog.mock.calls[0][0]).toBe('log');
383
+ expect(mockWarn).toHaveBeenCalledTimes(1);
384
+ expect(mockWarn.mock.calls[0]).toHaveLength(2);
385
+ expect(mockWarn.mock.calls[0][0]).toBe('warn');
386
+ expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual(
387
+ '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
388
+ );
389
+ expect(mockError).toHaveBeenCalledTimes(1);
390
+ expect(mockError.mock.calls[0]).toHaveLength(2);
391
+ expect(mockError.mock.calls[0][0]).toBe('error');
392
+ expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe(
393
+ '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
394
+ );
395
+ });
396
});
packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js
+7
@@ -80,6 +80,10 @@ export function describeNativeComponentFrame(
80
81
let control;
82
83
+ const previousPrepareStackTrace = Error.prepareStackTrace;
84
+ // $FlowFixMe It does accept undefined.
85
+ Error.prepareStackTrace = undefined;
86
+
87
reentry = true;
88
let previousDispatcher;
89
if (__DEV__) {
@@ -181,6 +185,9 @@ export function describeNativeComponentFrame(
185
}
186
} finally {
187
reentry = false;
188
+
189
+ Error.prepareStackTrace = previousPrepareStackTrace;
190
+
191
if (__DEV__) {
192
currentDispatcherRef.current = previousDispatcher;
193
reenableLogs();