chore: ui mode ui improvements (#21325)
This commit is contained in:
parent
2cbde9b8ef
commit
57624bc01b
|
|
@ -85,8 +85,13 @@ class Controller {
|
||||||
this._page.exposeBinding('binding', false, (source, data) => {
|
this._page.exposeBinding('binding', false, (source, data) => {
|
||||||
const { method, params } = data;
|
const { method, params } = data;
|
||||||
if (method === 'run') {
|
if (method === 'run') {
|
||||||
const { location } = params;
|
const { location, testIds } = params;
|
||||||
config._internal.cliArgs = [location];
|
if (location)
|
||||||
|
config._internal.cliArgs = [location];
|
||||||
|
if (testIds) {
|
||||||
|
const testIdSet = testIds ? new Set<string>(testIds) : null;
|
||||||
|
config._internal.testIdMatcher = id => !testIdSet || testIdSet.has(id);
|
||||||
|
}
|
||||||
this._queue = this._queue.then(() => runTests(config, this._runReporter));
|
this._queue = this._queue.then(() => runTests(config, this._runReporter));
|
||||||
return this._queue;
|
return this._queue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,21 @@
|
||||||
.watch-mode-sidebar input {
|
.watch-mode-sidebar input {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.watch-mode-sidebar .toolbar-button:not([disabled]) .codicon-play {
|
||||||
|
color: var(--vscode-testing-runAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
.watch-mode-list-item {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watch-mode-list-item-title {
|
||||||
|
flex: auto;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
.watch-mode-sidebar .toolbar-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import type { FullConfig, Suite, TestCase, TestStep } from '../../../playwright-
|
||||||
import { SplitView } from '@web/components/splitView';
|
import { SplitView } from '@web/components/splitView';
|
||||||
import type { MultiTraceModel } from './modelUtil';
|
import type { MultiTraceModel } from './modelUtil';
|
||||||
import './watchMode.css';
|
import './watchMode.css';
|
||||||
|
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||||
|
|
||||||
let rootSuite: Suite | undefined;
|
let rootSuite: Suite | undefined;
|
||||||
|
|
||||||
|
|
@ -63,10 +64,10 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
const explicitlyOrAutoExpandedFiles = new Set<Suite>();
|
const explicitlyOrAutoExpandedFiles = new Set<Suite>();
|
||||||
const entries = new Map<TestCase | Suite, Entry>();
|
const entries = new Map<TestCase | Suite, Entry>();
|
||||||
const trimmedFilterText = filterText.trim();
|
const trimmedFilterText = filterText.trim();
|
||||||
const filterTokens = trimmedFilterText.split(' ');
|
const filterTokens = trimmedFilterText.toLowerCase().split(' ');
|
||||||
for (const fileSuite of fileSuites) {
|
for (const fileSuite of fileSuites) {
|
||||||
const hasMatch = !trimmedFilterText || fileSuite.allTests().some(test => {
|
const hasMatch = !trimmedFilterText || fileSuite.allTests().some(test => {
|
||||||
const fullTitle = test.titlePath().join(' ');
|
const fullTitle = test.titlePath().join(' ').toLowerCase();
|
||||||
return !filterTokens.some(token => !fullTitle.includes(token));
|
return !filterTokens.some(token => !fullTitle.includes(token));
|
||||||
});
|
});
|
||||||
if (hasMatch)
|
if (hasMatch)
|
||||||
|
|
@ -76,13 +77,28 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
if (expandState === true || autoExpandMatches) {
|
if (expandState === true || autoExpandMatches) {
|
||||||
explicitlyOrAutoExpandedFiles.add(fileSuite);
|
explicitlyOrAutoExpandedFiles.add(fileSuite);
|
||||||
for (const test of fileSuite.allTests()) {
|
for (const test of fileSuite.allTests()) {
|
||||||
const fullTitle = test.titlePath().join(' ');
|
const fullTitle = test.titlePath().join(' ').toLowerCase();
|
||||||
if (!filterTokens.some(token => !fullTitle.includes(token)))
|
if (!filterTokens.some(token => !fullTitle.includes(token)))
|
||||||
entries.set(test, { test, fileSuite });
|
entries.set(test, { test, fileSuite });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visibleTestIds = new Set<string>();
|
||||||
|
for (const { test } of entries.values()) {
|
||||||
|
if (test)
|
||||||
|
visibleTestIds.add(test.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const runEntry = (entry: Entry) => {
|
||||||
|
expandedFiles.set(entry.fileSuite, true);
|
||||||
|
setSelectedTest(entry.test);
|
||||||
|
setIsRunningTest(true);
|
||||||
|
runTests(entry.test ? entry.test.location.file + ':' + entry.test.location.line : entry.fileSuite.title, undefined).then(() => {
|
||||||
|
setIsRunningTest(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const selectedEntry = selectedTest ? entries.get(selectedTest) : selectedOrDefaultFileSuite ? entries.get(selectedOrDefaultFileSuite) : undefined;
|
const selectedEntry = selectedTest ? entries.get(selectedTest) : selectedOrDefaultFileSuite ? entries.get(selectedOrDefaultFileSuite) : undefined;
|
||||||
return <SplitView sidebarSize={300} orientation='horizontal' sidebarIsFirst={true}>
|
return <SplitView sidebarSize={300} orientation='horizontal' sidebarIsFirst={true}>
|
||||||
<TraceView test={selectedTest} isRunningTest={isRunningTest}></TraceView>
|
<TraceView test={selectedTest} isRunningTest={isRunningTest}></TraceView>
|
||||||
|
|
@ -93,12 +109,23 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
setFilterText(e.target.value);
|
setFilterText(e.target.value);
|
||||||
}}
|
}}
|
||||||
onKeyDown={e => {
|
onKeyDown={e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
setIsRunningTest(true);
|
||||||
|
runTests(undefined, [...visibleTestIds]).then(() => {
|
||||||
|
setIsRunningTest(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
}}></input>
|
}}></input>
|
||||||
</div>
|
</div>
|
||||||
<ListView
|
<ListView
|
||||||
items={[...entries.values()]}
|
items={[...entries.values()]}
|
||||||
itemKey={(entry: Entry) => entry.test ? entry.test!.id : entry.fileSuite.title }
|
itemKey={(entry: Entry) => entry.test ? entry.test!.id : entry.fileSuite.title }
|
||||||
itemRender={(entry: Entry) => entry.test ? entry.test!.titlePath().slice(3).join(' › ') : entry.fileSuite.title }
|
itemRender={(entry: Entry) => {
|
||||||
|
return <div className='hbox watch-mode-list-item'>
|
||||||
|
<div className='watch-mode-list-item-title'>{entry.test ? entry.test!.titlePath().slice(3).join(' › ') : entry.fileSuite.title}</div>
|
||||||
|
<ToolbarButton icon='play' title='Run' onClick={() => runEntry(entry)} disabled={isRunningTest}></ToolbarButton>
|
||||||
|
</div>;
|
||||||
|
}}
|
||||||
itemIcon={(entry: Entry) => {
|
itemIcon={(entry: Entry) => {
|
||||||
if (entry.test) {
|
if (entry.test) {
|
||||||
if (entry.test.results.length && entry.test.results[0].duration)
|
if (entry.test.results.length && entry.test.results[0].duration)
|
||||||
|
|
@ -113,15 +140,7 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
}}
|
}}
|
||||||
itemIndent={(entry: Entry) => entry.test ? 1 : 0}
|
itemIndent={(entry: Entry) => entry.test ? 1 : 0}
|
||||||
selectedItem={selectedEntry}
|
selectedItem={selectedEntry}
|
||||||
onAccepted={(entry: Entry) => {
|
onAccepted={runEntry}
|
||||||
if (entry.test) {
|
|
||||||
setSelectedTest(entry.test);
|
|
||||||
setIsRunningTest(true);
|
|
||||||
runTests(entry.test ? entry.test.location.file + ':' + entry.test.location.line : entry.fileSuite.title).then(() => {
|
|
||||||
setIsRunningTest(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onLeftArrow={(entry: Entry) => {
|
onLeftArrow={(entry: Entry) => {
|
||||||
expandedFiles.set(entry.fileSuite, false);
|
expandedFiles.set(entry.fileSuite, false);
|
||||||
setSelectedTest(undefined);
|
setSelectedTest(undefined);
|
||||||
|
|
@ -248,9 +267,9 @@ const receiver = new TeleReporterReceiver({
|
||||||
receiver.dispatch(message);
|
receiver.dispatch(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function runTests(location: string): Promise<void> {
|
async function runTests(location: string | undefined, testIds: string[] | undefined): Promise<void> {
|
||||||
await (window as any).binding({
|
await (window as any).binding({
|
||||||
method: 'run',
|
method: 'run',
|
||||||
params: { location }
|
params: { location, testIds }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue