Files
react/packages/react-devtools-shared/src/__tests__/componentStacks-test.js
T
Sebastian MarkbågeandRuslan Lesiutin e2cac67533 [Flight] Prefix owner stacks added to the console.log with the current stack (#30427)
The current stack is available in the native UI but that's hidden by
default so you don't see the actual current component on the stack.

This is unlike the native async stacks UI where they're all together.

So we prefix the stack with the current stack first.

<img width="279" alt="Screenshot 2024-07-22 at 10 05 13 PM"
src="https://github.com/user-attachments/assets/8f568fda-6493-416d-a0be-661caf44d808">

---------

Co-authored-by: Ruslan Lesiutin <rdlesyutin@gmail.com>
2024-07-23 16:48:32 -04:00

140 lines
3.9 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';
describe('component stack', () => {
let React;
let act;
let mockError;
let mockWarn;
let supportsOwnerStacks;
beforeEach(() => {
// Intercept native console methods before DevTools bootstraps.
// Normalize component stack locations.
mockError = jest.fn();
mockWarn = jest.fn();
console.error = (...args) => {
mockError(...args.map(normalizeCodeLocInfo));
};
console.warn = (...args) => {
mockWarn(...args.map(normalizeCodeLocInfo));
};
const utils = require('./utils');
act = utils.act;
React = require('react');
if (
React.version.startsWith('19') &&
React.version.includes('experimental')
) {
supportsOwnerStacks = true;
}
});
const {render} = getVersionedRenderImplementation();
// @reactVersion >=16.9
it('should log the current component stack along with an error or warning', () => {
const Grandparent = () => <Parent />;
const Parent = () => <Child />;
const Child = () => {
console.error('Test error.');
console.warn('Test warning.');
return null;
};
act(() => render(<Grandparent />));
expect(mockError).toHaveBeenCalledWith(
'Test error.',
'\n in Child (at **)' +
'\n in Parent (at **)' +
'\n in Grandparent (at **)',
);
expect(mockWarn).toHaveBeenCalledWith(
'Test warning.',
'\n in Child (at **)' +
'\n in Parent (at **)' +
'\n in Grandparent (at **)',
);
});
// This test should have caught #19911
// but didn't because both DevTools and ReactDOM are running in the same memory space,
// so the case we're testing against (DevTools prod build and React DEV build) doesn't exist.
// It would be nice to figure out a way to test this combination at some point...
// eslint-disable-next-line jest/no-disabled-tests
it.skip('should disable the current dispatcher before shallow rendering so no effects get scheduled', () => {
let useEffectCount = 0;
const Example = props => {
React.useEffect(() => {
useEffectCount++;
expect(props).toBeDefined();
}, [props]);
console.warn('Warning to trigger appended component stacks.');
return null;
};
act(() => render(<Example test="abc" />));
expect(useEffectCount).toBe(1);
expect(mockWarn).toHaveBeenCalledWith(
'Warning to trigger appended component stacks.',
'\n in Example (at **)',
);
});
// @reactVersion >=18.3
it('should log the current component stack with debug info from promises', () => {
const Child = () => {
console.error('Test error.');
console.warn('Test warning.');
return null;
};
const ChildPromise = Promise.resolve(<Child />);
ChildPromise.status = 'fulfilled';
ChildPromise.value = <Child />;
ChildPromise._debugInfo = [
{
name: 'ServerComponent',
env: 'Server',
owner: null,
},
];
const Parent = () => ChildPromise;
const Grandparent = () => <Parent />;
act(() => render(<Grandparent />));
expect(mockError).toHaveBeenCalledWith(
'Test error.',
supportsOwnerStacks
? '\n in Child (at **)'
: '\n in Child (at **)' +
'\n in ServerComponent (at **)' +
'\n in Parent (at **)' +
'\n in Grandparent (at **)',
);
expect(mockWarn).toHaveBeenCalledWith(
'Test warning.',
supportsOwnerStacks
? '\n in Child (at **)'
: '\n in Child (at **)' +
'\n in ServerComponent (at **)' +
'\n in Parent (at **)' +
'\n in Grandparent (at **)',
);
});
});