mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: implement project filter (#21402)
This commit is contained in:
parent
ec056a6312
commit
d8d410db6e
@ -27,20 +27,19 @@ import './watchMode.css';
|
|||||||
import { ToolbarButton } from '@web/components/toolbarButton';
|
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||||
import { Toolbar } from '@web/components/toolbar';
|
import { Toolbar } from '@web/components/toolbar';
|
||||||
|
|
||||||
let rootSuite: Suite | undefined;
|
let updateRootSuite: (rootSuite: Suite) => void = () => {};
|
||||||
|
|
||||||
let updateList: () => void = () => {};
|
|
||||||
let updateProgress: () => void = () => {};
|
let updateProgress: () => void = () => {};
|
||||||
let runWatchedTests = () => {};
|
let runWatchedTests = () => {};
|
||||||
const expandedItems = new Map<string, boolean | undefined>();
|
|
||||||
|
|
||||||
export const WatchModeView: React.FC<{}> = ({
|
export const WatchModeView: React.FC<{}> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [updateCounter, setUpdateCounter] = React.useState(0);
|
const [rootSuite, setRootSuite] = React.useState<{ value: Suite | undefined }>({ value: undefined });
|
||||||
updateList = () => setUpdateCounter(updateCounter + 1);
|
updateRootSuite = (rootSuite: Suite) => setRootSuite({ value: rootSuite });
|
||||||
const [selectedTreeItemId, setSelectedTreeItemId] = React.useState<string | undefined>();
|
const [selectedTreeItemId, setSelectedTreeItemId] = React.useState<string | undefined>();
|
||||||
const [isRunningTest, setIsRunningTest] = React.useState<boolean>(false);
|
const [isRunningTest, setIsRunningTest] = React.useState<boolean>(false);
|
||||||
const [filterText, setFilterText] = React.useState<string>('');
|
const [filterText, setFilterText] = React.useState<string>('');
|
||||||
|
const [projectNames, setProjectNames] = React.useState<string[]>([]);
|
||||||
|
const [expandedItems, setExpandedItems] = React.useState<Map<string, boolean>>(new Map());
|
||||||
|
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
@ -49,10 +48,13 @@ export const WatchModeView: React.FC<{}> = ({
|
|||||||
sendMessageNoReply('list');
|
sendMessageNoReply('list');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { treeItemMap, visibleTestIds, listItems } = React.useMemo(() => {
|
React.useEffect(() => {
|
||||||
// updateCounter is used to trigger the compute.
|
if (projectNames.length === 0 && rootSuite.value?.suites.length)
|
||||||
noop(updateCounter);
|
setProjectNames([rootSuite.value?.suites[0].title]);
|
||||||
const treeItems = createTree(rootSuite);
|
}, [projectNames, rootSuite]);
|
||||||
|
|
||||||
|
const { filteredItems, treeItemMap, visibleTestIds } = React.useMemo(() => {
|
||||||
|
const treeItems = createTree(rootSuite.value, projectNames);
|
||||||
const filteredItems = filterTree(treeItems, filterText);
|
const filteredItems = filterTree(treeItems, filterText);
|
||||||
|
|
||||||
const treeItemMap = new Map<string, TreeItem>();
|
const treeItemMap = new Map<string, TreeItem>();
|
||||||
@ -64,9 +66,14 @@ export const WatchModeView: React.FC<{}> = ({
|
|||||||
treeItemMap.set(treeItem.id, treeItem);
|
treeItemMap.set(treeItem.id, treeItem);
|
||||||
};
|
};
|
||||||
filteredItems.forEach(visit);
|
filteredItems.forEach(visit);
|
||||||
|
return { treeItemMap, visibleTestIds, filteredItems };
|
||||||
|
}, [filterText, rootSuite, projectNames]);
|
||||||
|
|
||||||
|
|
||||||
|
const { listItems } = React.useMemo(() => {
|
||||||
const listItems = flattenTree(filteredItems, expandedItems, !!filterText.trim());
|
const listItems = flattenTree(filteredItems, expandedItems, !!filterText.trim());
|
||||||
return { treeItemMap, visibleTestIds, listItems };
|
return { listItems };
|
||||||
}, [filterText, updateCounter]);
|
}, [filteredItems, filterText, expandedItems]);
|
||||||
|
|
||||||
const selectedTreeItem = selectedTreeItemId ? treeItemMap.get(selectedTreeItemId) : undefined;
|
const selectedTreeItem = selectedTreeItemId ? treeItemMap.get(selectedTreeItemId) : undefined;
|
||||||
|
|
||||||
@ -136,16 +143,19 @@ export const WatchModeView: React.FC<{}> = ({
|
|||||||
selectedItem={selectedTreeItem}
|
selectedItem={selectedTreeItem}
|
||||||
onAccepted={runTreeItem}
|
onAccepted={runTreeItem}
|
||||||
onLeftArrow={(treeItem: TreeItem) => {
|
onLeftArrow={(treeItem: TreeItem) => {
|
||||||
if (treeItem.children && treeItem.expanded)
|
if (treeItem.children && treeItem.expanded) {
|
||||||
expandedItems.set(treeItem.id, false);
|
expandedItems.set(treeItem.id, false);
|
||||||
else
|
setExpandedItems(new Map(expandedItems));
|
||||||
|
} else {
|
||||||
setSelectedTreeItemId(treeItem.parent?.id);
|
setSelectedTreeItemId(treeItem.parent?.id);
|
||||||
updateList();
|
}
|
||||||
}}
|
}}
|
||||||
onRightArrow={(treeItem: TreeItem) => {
|
onRightArrow={(treeItem: TreeItem) => {
|
||||||
if (treeItem.children)
|
if (treeItem.children) {
|
||||||
expandedItems.set(treeItem.id, true);
|
expandedItems.set(treeItem.id, true);
|
||||||
updateList();
|
setExpandedItems(new Map(expandedItems));
|
||||||
|
}
|
||||||
|
setRootSuite({ ...rootSuite });
|
||||||
}}
|
}}
|
||||||
onSelected={(treeItem: TreeItem) => {
|
onSelected={(treeItem: TreeItem) => {
|
||||||
setSelectedTreeItemId(treeItem.id);
|
setSelectedTreeItemId(treeItem.id);
|
||||||
@ -157,9 +167,25 @@ export const WatchModeView: React.FC<{}> = ({
|
|||||||
expandedItems.set(treeItem.id, false);
|
expandedItems.set(treeItem.id, false);
|
||||||
else
|
else
|
||||||
expandedItems.set(treeItem.id, true);
|
expandedItems.set(treeItem.id, true);
|
||||||
updateList();
|
setExpandedItems(new Map(expandedItems));
|
||||||
}}
|
}}
|
||||||
showNoItemsMessage={true}></ListView>
|
showNoItemsMessage={true}></ListView>
|
||||||
|
{(rootSuite.value?.suites.length || 0) > 1 && <div style={{ flex: 'none', borderTop: '1px solid var(--vscode-panel-border)' }}>
|
||||||
|
<ListView
|
||||||
|
items={rootSuite.value!.suites}
|
||||||
|
onSelected={(suite: Suite) => {
|
||||||
|
const copy = [...projectNames];
|
||||||
|
copy.includes(suite.title) ? copy.splice(copy.indexOf(suite.title), 1) : copy.push(suite.title);
|
||||||
|
setProjectNames(copy);
|
||||||
|
}}
|
||||||
|
itemRender={(suite: Suite) => {
|
||||||
|
return <label style={{ display: 'flex', pointerEvents: 'none' }}>
|
||||||
|
<input type='checkbox' checked={projectNames.includes(suite.title)} />
|
||||||
|
{suite.title}
|
||||||
|
</label>;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
</SplitView>;
|
</SplitView>;
|
||||||
};
|
};
|
||||||
@ -229,19 +255,21 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let rootSuite: Suite;
|
||||||
const receiver = new TeleReporterReceiver({
|
const receiver = new TeleReporterReceiver({
|
||||||
onBegin: (config: FullConfig, suite: Suite) => {
|
onBegin: (config: FullConfig, suite: Suite) => {
|
||||||
if (!rootSuite)
|
if (!rootSuite)
|
||||||
rootSuite = suite;
|
rootSuite = suite;
|
||||||
updateList();
|
updateRootSuite(rootSuite);
|
||||||
},
|
},
|
||||||
|
|
||||||
onTestBegin: () => {
|
onTestBegin: () => {
|
||||||
updateList();
|
updateRootSuite(rootSuite);
|
||||||
},
|
},
|
||||||
|
|
||||||
onTestEnd: () => {
|
onTestEnd: () => {
|
||||||
updateList();
|
updateRootSuite(rootSuite);
|
||||||
},
|
},
|
||||||
|
|
||||||
onStepBegin: () => {
|
onStepBegin: () => {
|
||||||
@ -260,6 +288,7 @@ const receiver = new TeleReporterReceiver({
|
|||||||
else
|
else
|
||||||
receiver.dispatch(message);
|
receiver.dispatch(message);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const sendMessage = async (method: string, params: any) => {
|
const sendMessage = async (method: string, params: any) => {
|
||||||
await (window as any).sendMessage({ method, params });
|
await (window as any).sendMessage({ method, params });
|
||||||
@ -318,9 +347,11 @@ type TestItem = TreeItemBase & {
|
|||||||
|
|
||||||
type TreeItem = FileItem | TestCaseItem | TestItem;
|
type TreeItem = FileItem | TestCaseItem | TestItem;
|
||||||
|
|
||||||
function createTree(rootSuite?: Suite): FileItem[] {
|
function createTree(rootSuite: Suite | undefined, projectNames: string[]): FileItem[] {
|
||||||
const fileItems = new Map<string, FileItem>();
|
const fileItems = new Map<string, FileItem>();
|
||||||
for (const projectSuite of rootSuite?.suites || []) {
|
for (const projectSuite of rootSuite?.suites || []) {
|
||||||
|
if (!projectNames.includes(projectSuite.title))
|
||||||
|
continue;
|
||||||
for (const fileSuite of projectSuite.suites) {
|
for (const fileSuite of projectSuite.suites) {
|
||||||
const file = fileSuite.location!.file;
|
const file = fileSuite.location!.file;
|
||||||
|
|
||||||
@ -391,8 +422,8 @@ function flattenTree(fileItems: FileItem[], expandedItems: Map<string, boolean |
|
|||||||
result.push(fileItem);
|
result.push(fileItem);
|
||||||
const expandState = expandedItems.get(fileItem.id);
|
const expandState = expandedItems.get(fileItem.id);
|
||||||
const autoExpandMatches = result.length < 100 && (hasFilter && expandState !== false);
|
const autoExpandMatches = result.length < 100 && (hasFilter && expandState !== false);
|
||||||
if (expandState || autoExpandMatches) {
|
fileItem.expanded = expandState || autoExpandMatches;
|
||||||
fileItem.expanded = true;
|
if (fileItem.expanded) {
|
||||||
for (const testCaseItem of fileItem.children!) {
|
for (const testCaseItem of fileItem.children!) {
|
||||||
result.push(testCaseItem);
|
result.push(testCaseItem);
|
||||||
testCaseItem.expanded = !!expandedItems.get(testCaseItem.id);
|
testCaseItem.expanded = !!expandedItems.get(testCaseItem.id);
|
||||||
@ -403,5 +434,3 @@ function flattenTree(fileItems: FileItem[], expandedItems: Map<string, boolean |
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function noop(_: any) {}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user