mirror of
https://github.com/facebook/react.git
synced 2026-02-22 20:01:52 +00:00
This shows the stack trace of the JSX at each level so now you can also jump to the code location for the JSX callsite. The visual is similar to the owner stacks with `createTask` except when you click the `<...>` you jump to the Instance in the Components panel. <img width="593" height="450" alt="Screenshot 2025-08-08 at 12 19 21 AM" src="https://github.com/user-attachments/assets/dac35faf-9d99-46ce-8b41-7c6fe24625d2" /> I'm not sure it's really necessary to have all the JSX stacks of every owner. We could just have it for the current component and then the rest of the owners you could get to if you just click that owner instance. As a bonus, I also use the JSX callsite as the fallback for the "View Source" button. This is primarily useful for built-ins like `<div>` and `<Suspense>` that don't have any implementation to jump to anyway. It's useful to be able to jump to where a boundary was defined.
109 lines
3.0 KiB
JavaScript
109 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
/** @flow */
|
|
|
|
async function clickButton(page, buttonTestName) {
|
|
await page.evaluate(testName => {
|
|
const {createTestNameSelector, findAllNodes} = window.REACT_DOM_DEVTOOLS;
|
|
const container = document.getElementById('devtools');
|
|
|
|
const button = findAllNodes(container, [
|
|
createTestNameSelector(testName),
|
|
])[0];
|
|
button.click();
|
|
}, buttonTestName);
|
|
}
|
|
|
|
async function getElementCount(page, displayName) {
|
|
return await page.evaluate(listItemText => {
|
|
const {createTestNameSelector, createTextSelector, findAllNodes} =
|
|
window.REACT_DOM_DEVTOOLS;
|
|
const container = document.getElementById('devtools');
|
|
const rows = findAllNodes(container, [
|
|
createTestNameSelector('ComponentTreeListItem'),
|
|
createTextSelector(listItemText),
|
|
]);
|
|
return rows.length;
|
|
}, displayName);
|
|
}
|
|
|
|
async function selectElement(
|
|
page,
|
|
displayName,
|
|
waitForOwnersText,
|
|
waitForSourceLoaded = false
|
|
) {
|
|
await page.evaluate(listItemText => {
|
|
const {createTestNameSelector, createTextSelector, findAllNodes} =
|
|
window.REACT_DOM_DEVTOOLS;
|
|
const container = document.getElementById('devtools');
|
|
|
|
const listItem = findAllNodes(container, [
|
|
createTestNameSelector('ComponentTreeListItem'),
|
|
createTextSelector(listItemText),
|
|
])[0];
|
|
|
|
listItem.dispatchEvent(
|
|
new MouseEvent('mousedown', {bubbles: true, cancelable: true})
|
|
);
|
|
}, displayName);
|
|
|
|
if (waitForOwnersText) {
|
|
// Wait for selected element's props to load.
|
|
await page.waitForFunction(
|
|
({titleText, ownersListText}) => {
|
|
const {createTestNameSelector, findAllNodes} =
|
|
window.REACT_DOM_DEVTOOLS;
|
|
const container = document.getElementById('devtools');
|
|
|
|
const title = findAllNodes(container, [
|
|
createTestNameSelector('InspectedElement-Title'),
|
|
])[0];
|
|
|
|
const ownersList = findAllNodes(container, [
|
|
createTestNameSelector('InspectedElementView-Owners'),
|
|
])[0];
|
|
|
|
if (!ownersList) {
|
|
return false;
|
|
}
|
|
|
|
const owners = findAllNodes(ownersList, [
|
|
createTestNameSelector('OwnerView'),
|
|
]);
|
|
|
|
return (
|
|
title &&
|
|
title.innerText.includes(titleText) &&
|
|
owners &&
|
|
owners
|
|
.map(node => node.innerText)
|
|
.join('\n')
|
|
.includes(ownersListText)
|
|
);
|
|
},
|
|
{titleText: displayName, ownersListText: waitForOwnersText}
|
|
);
|
|
}
|
|
|
|
if (waitForSourceLoaded) {
|
|
await page.waitForFunction(() => {
|
|
const {createTestNameSelector, findAllNodes} = window.REACT_DOM_DEVTOOLS;
|
|
const container = document.getElementById('devtools');
|
|
|
|
const sourceStringBlock = findAllNodes(container, [
|
|
createTestNameSelector('InspectedElementView-FormattedSourceString'),
|
|
])[0];
|
|
|
|
// Wait for a new source line to be fetched
|
|
return sourceStringBlock != null && sourceStringBlock.innerText != null;
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
clickButton,
|
|
getElementCount,
|
|
selectElement,
|
|
};
|