mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: support suites in the tree (#21508)
This commit is contained in:
parent
72c41db668
commit
5ef2edb9f7
@ -38,7 +38,6 @@ class UIMode {
|
||||
private _testWatcher: FSWatcher | undefined;
|
||||
private _watchTestFile: string | undefined;
|
||||
private _originalStderr: (buffer: string | Uint8Array) => void;
|
||||
private _globalWatcher: FSWatcher;
|
||||
|
||||
constructor(config: FullConfigInternal) {
|
||||
this._config = config;
|
||||
@ -58,7 +57,7 @@ class UIMode {
|
||||
return true;
|
||||
};
|
||||
|
||||
this._globalWatcher = this._installGlobalWatcher();
|
||||
this._installGlobalWatcher();
|
||||
}
|
||||
|
||||
private _installGlobalWatcher(): FSWatcher {
|
||||
|
||||
@ -324,6 +324,8 @@ const refreshRootSuite = (eraseResults: boolean) => {
|
||||
else
|
||||
++progress.passed;
|
||||
updateRootSuite(rootSuite, progress);
|
||||
// This will update selected trace viewer.
|
||||
updateStepsProgress();
|
||||
},
|
||||
|
||||
onStepBegin: () => {
|
||||
@ -373,22 +375,13 @@ const sendMessageNoReply = (method: string, params?: any) => {
|
||||
};
|
||||
|
||||
const fileName = (treeItem?: TreeItem): string | undefined => {
|
||||
if (!treeItem)
|
||||
return;
|
||||
if (treeItem.kind === 'file')
|
||||
return treeItem.file;
|
||||
return fileName(treeItem.parent || undefined);
|
||||
return treeItem?.location.file;
|
||||
};
|
||||
|
||||
const locationToOpen = (treeItem?: TreeItem) => {
|
||||
if (!treeItem)
|
||||
return;
|
||||
if (treeItem.kind === 'test')
|
||||
return treeItem.test.location.file + ':' + treeItem.test.location.line;
|
||||
if (treeItem.kind === 'case')
|
||||
return treeItem.location.file + ':' + treeItem.location.line;
|
||||
if (treeItem.kind === 'file')
|
||||
return treeItem.file;
|
||||
return treeItem.location.file + ':' + treeItem.location.line;
|
||||
};
|
||||
|
||||
const collectTestIds = (treeItem?: TreeItem): string[] => {
|
||||
@ -414,29 +407,22 @@ type Progress = {
|
||||
};
|
||||
|
||||
type TreeItemBase = {
|
||||
kind: 'root' | 'file' | 'case' | 'test',
|
||||
kind: 'root' | 'group' | 'case' | 'test',
|
||||
id: string;
|
||||
title: string;
|
||||
parent: TreeItem | null;
|
||||
location: Location,
|
||||
children: TreeItem[];
|
||||
status: 'none' | 'running' | 'passed' | 'failed';
|
||||
};
|
||||
|
||||
type RootItem = TreeItemBase & {
|
||||
kind: 'root',
|
||||
children: FileItem[];
|
||||
};
|
||||
|
||||
type FileItem = TreeItemBase & {
|
||||
kind: 'file',
|
||||
file: string;
|
||||
children: TestCaseItem[];
|
||||
type GroupItem = TreeItemBase & {
|
||||
kind: 'group',
|
||||
children: (TestCaseItem | GroupItem)[];
|
||||
};
|
||||
|
||||
type TestCaseItem = TreeItemBase & {
|
||||
kind: 'case',
|
||||
tests: TestCase[];
|
||||
location: Location,
|
||||
};
|
||||
|
||||
type TestItem = TreeItemBase & {
|
||||
@ -444,77 +430,77 @@ type TestItem = TreeItemBase & {
|
||||
test: TestCase;
|
||||
};
|
||||
|
||||
type TreeItem = RootItem | FileItem | TestCaseItem | TestItem;
|
||||
type TreeItem = GroupItem | TestCaseItem | TestItem;
|
||||
|
||||
function createTree(rootSuite: Suite | undefined, projects: Map<string, boolean>): RootItem {
|
||||
const rootItem: RootItem = {
|
||||
kind: 'root',
|
||||
function createTree(rootSuite: Suite | undefined, projects: Map<string, boolean>): GroupItem {
|
||||
const rootItem: GroupItem = {
|
||||
kind: 'group',
|
||||
id: 'root',
|
||||
title: '',
|
||||
parent: null,
|
||||
location: { file: '', line: 0, column: 0 },
|
||||
children: [],
|
||||
status: 'none',
|
||||
};
|
||||
const fileItems = new Map<string, FileItem>();
|
||||
for (const projectSuite of rootSuite?.suites || []) {
|
||||
if (!projects.get(projectSuite.title))
|
||||
continue;
|
||||
for (const fileSuite of projectSuite.suites) {
|
||||
const file = fileSuite.location!.file;
|
||||
|
||||
let fileItem = fileItems.get(file);
|
||||
if (!fileItem) {
|
||||
fileItem = {
|
||||
kind: 'file',
|
||||
id: fileSuite.title,
|
||||
title: fileSuite.title,
|
||||
file,
|
||||
parent: null,
|
||||
const visitSuite = (projectName: string, parentSuite: Suite, parentGroup: GroupItem) => {
|
||||
for (const suite of parentSuite.suites) {
|
||||
const title = suite.title;
|
||||
let group = parentGroup.children.find(item => item.title === title) as GroupItem | undefined;
|
||||
if (!group) {
|
||||
group = {
|
||||
kind: 'group',
|
||||
id: parentGroup.id + '\x1e' + title,
|
||||
title,
|
||||
location: suite.location!,
|
||||
children: [],
|
||||
status: 'none',
|
||||
};
|
||||
fileItems.set(fileSuite.location!.file, fileItem);
|
||||
rootItem.children.push(fileItem);
|
||||
parentGroup.children.push(group);
|
||||
}
|
||||
|
||||
for (const test of fileSuite.allTests()) {
|
||||
const title = test.titlePath().slice(3).join(' › ');
|
||||
let testCaseItem = fileItem.children.find(t => t.title === title) as TestCaseItem;
|
||||
if (!testCaseItem) {
|
||||
testCaseItem = {
|
||||
kind: 'case',
|
||||
id: fileItem.id + ' / ' + title,
|
||||
title,
|
||||
parent: fileItem,
|
||||
children: [],
|
||||
tests: [],
|
||||
location: test.location,
|
||||
status: 'none',
|
||||
};
|
||||
fileItem.children.push(testCaseItem);
|
||||
}
|
||||
|
||||
let status: 'none' | 'running' | 'passed' | 'failed' = 'none';
|
||||
if (test.results.some(r => r.duration === -1))
|
||||
status = 'running';
|
||||
else if (test.results.length && test.outcome() !== 'expected')
|
||||
status = 'failed';
|
||||
else if (test.outcome() === 'expected')
|
||||
status = 'passed';
|
||||
|
||||
testCaseItem.tests.push(test);
|
||||
testCaseItem.children.push({
|
||||
kind: 'test',
|
||||
id: test.id,
|
||||
title: projectSuite.title,
|
||||
parent: testCaseItem,
|
||||
test,
|
||||
children: [],
|
||||
status,
|
||||
});
|
||||
}
|
||||
(fileItem.children as TestCaseItem[]).sort((a, b) => a.location.line - b.location.line);
|
||||
visitSuite(projectName, suite, group);
|
||||
}
|
||||
|
||||
for (const test of parentSuite.tests) {
|
||||
const title = test.title;
|
||||
let testCaseItem = parentGroup.children.find(t => t.title === title) as TestCaseItem;
|
||||
if (!testCaseItem) {
|
||||
testCaseItem = {
|
||||
kind: 'case',
|
||||
id: parentGroup.id + '\x1e' + title,
|
||||
title,
|
||||
children: [],
|
||||
tests: [],
|
||||
location: test.location,
|
||||
status: 'none',
|
||||
};
|
||||
parentGroup.children.push(testCaseItem);
|
||||
}
|
||||
|
||||
let status: 'none' | 'running' | 'passed' | 'failed' = 'none';
|
||||
if (test.results.some(r => r.duration === -1))
|
||||
status = 'running';
|
||||
else if (test.results.length && test.outcome() !== 'expected')
|
||||
status = 'failed';
|
||||
else if (test.outcome() === 'expected')
|
||||
status = 'passed';
|
||||
|
||||
testCaseItem.tests.push(test);
|
||||
testCaseItem.children.push({
|
||||
kind: 'test',
|
||||
id: test.id,
|
||||
title: projectName,
|
||||
location: test.location!,
|
||||
test,
|
||||
children: [],
|
||||
status,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for (const projectSuite of rootSuite?.suites || []) {
|
||||
if (!projects.get(projectSuite.title))
|
||||
continue;
|
||||
visitSuite(projectSuite.title, projectSuite, rootItem);
|
||||
}
|
||||
|
||||
const propagateStatus = (treeItem: TreeItem) => {
|
||||
@ -542,27 +528,29 @@ function createTree(rootSuite: Suite | undefined, projects: Map<string, boolean>
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
function filterTree(rootItem: RootItem, filterText: string) {
|
||||
function filterTree(rootItem: GroupItem, filterText: string) {
|
||||
const trimmedFilterText = filterText.trim();
|
||||
const filterTokens = trimmedFilterText.toLowerCase().split(' ');
|
||||
const result: FileItem[] = [];
|
||||
for (const fileItem of rootItem.children) {
|
||||
if (trimmedFilterText) {
|
||||
const filteredCases: TestCaseItem[] = [];
|
||||
for (const testCaseItem of fileItem.children) {
|
||||
const fullTitle = (fileItem.title + ' ' + testCaseItem.title).toLowerCase();
|
||||
if (filterTokens.every(token => fullTitle.includes(token)))
|
||||
filteredCases.push(testCaseItem);
|
||||
|
||||
const visit = (treeItem: GroupItem) => {
|
||||
const newChildren: (GroupItem | TestCaseItem)[] = [];
|
||||
for (const child of treeItem.children) {
|
||||
if (child.kind === 'case') {
|
||||
const title = child.tests[0].titlePath().join(' ').toLowerCase();
|
||||
if (filterTokens.every(token => title.includes(token)))
|
||||
newChildren.push(child);
|
||||
} else {
|
||||
visit(child);
|
||||
if (child.children.length)
|
||||
newChildren.push(child);
|
||||
}
|
||||
fileItem.children = filteredCases;
|
||||
}
|
||||
if (fileItem.children.length)
|
||||
result.push(fileItem);
|
||||
}
|
||||
rootItem.children = result;
|
||||
treeItem.children = newChildren;
|
||||
};
|
||||
visit(rootItem);
|
||||
}
|
||||
|
||||
function hideOnlyTests(rootItem: RootItem) {
|
||||
function hideOnlyTests(rootItem: GroupItem) {
|
||||
const visit = (treeItem: TreeItem) => {
|
||||
if (treeItem.kind === 'case' && treeItem.children.length === 1)
|
||||
treeItem.children = [];
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
import * as React from 'react';
|
||||
import './xtermWrapper.css';
|
||||
import type { Terminal } from 'xterm';
|
||||
import type { ITheme, Terminal } from 'xterm';
|
||||
import type { XtermModule } from './xtermModule';
|
||||
import { isDarkTheme } from '@web/theme';
|
||||
|
||||
@ -77,7 +77,7 @@ export const XtermWrapper: React.FC<{ source: XtermDataSource }> = ({
|
||||
</div>;
|
||||
};
|
||||
|
||||
const lightTheme = {
|
||||
const lightTheme: ITheme = {
|
||||
foreground: '#383a42',
|
||||
background: '#fafafa',
|
||||
cursor: '#383a42',
|
||||
@ -96,10 +96,12 @@ const lightTheme = {
|
||||
brightBlue: '#4078f2',
|
||||
brightMagenta: '#a626a4',
|
||||
brightCyan: '#0184bc',
|
||||
brightWhite: '#383a42'
|
||||
brightWhite: '#383a42',
|
||||
selectionBackground: '#d7d7d7',
|
||||
selectionForeground: '#383a42',
|
||||
};
|
||||
|
||||
const darkTheme = {
|
||||
const darkTheme: ITheme = {
|
||||
foreground: '#f8f8f2',
|
||||
background: '#1e1e1e',
|
||||
cursor: '#f8f8f0',
|
||||
@ -119,4 +121,6 @@ const darkTheme = {
|
||||
brightMagenta: '#ff92df',
|
||||
brightCyan: '#a4ffff',
|
||||
brightWhite: '#e6e6e6',
|
||||
selectionBackground: '#44475a',
|
||||
selectionForeground: '#f8f8f2',
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user