mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: queue run and list commands from ui (#30033)
This commit is contained in:
parent
e0588446c0
commit
a9fc4de37e
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { TestServerInterface, TestServerInterfaceEvents } from '@testIsomorphic/testServerInterface';
|
import type { TestServerInterface, TestServerInterfaceEvents } from '@testIsomorphic/testServerInterface';
|
||||||
import type { Location, TestError } from 'playwright/types/testReporter';
|
import type * as reporterTypes from 'playwright/types/testReporter';
|
||||||
import * as events from './events';
|
import * as events from './events';
|
||||||
|
|
||||||
export class TestServerConnection implements TestServerInterface, TestServerInterfaceEvents {
|
export class TestServerConnection implements TestServerInterface, TestServerInterfaceEvents {
|
||||||
@ -110,7 +110,7 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
async pingNoReply() {
|
async pingNoReply() {
|
||||||
await this._sendMessageNoReply('ping');
|
this._sendMessageNoReply('ping');
|
||||||
}
|
}
|
||||||
|
|
||||||
async watch(params: { fileNames: string[]; }): Promise<void> {
|
async watch(params: { fileNames: string[]; }): Promise<void> {
|
||||||
@ -121,11 +121,11 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
|
|||||||
this._sendMessageNoReply('watch', params);
|
this._sendMessageNoReply('watch', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async open(params: { location: Location; }): Promise<void> {
|
async open(params: { location: reporterTypes.Location; }): Promise<void> {
|
||||||
await this._sendMessage('open', params);
|
await this._sendMessage('open', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
openNoReply(params: { location: Location; }) {
|
openNoReply(params: { location: reporterTypes.Location; }) {
|
||||||
this._sendMessageNoReply('open', params);
|
this._sendMessageNoReply('open', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
|
|||||||
return await this._sendMessage('runGlobalTeardown');
|
return await this._sendMessage('runGlobalTeardown');
|
||||||
}
|
}
|
||||||
|
|
||||||
async listFiles(): Promise<{ projects: { name: string; testDir: string; use: { testIdAttribute?: string | undefined; }; files: string[]; }[]; cliEntryPoint?: string | undefined; error?: TestError | undefined; }> {
|
async listFiles(): Promise<{ projects: { name: string; testDir: string; use: { testIdAttribute?: string | undefined; }; files: string[]; }[]; cliEntryPoint?: string | undefined; error?: reporterTypes.TestError | undefined; }> {
|
||||||
return await this._sendMessage('listFiles');
|
return await this._sendMessage('listFiles');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +161,11 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
|
|||||||
return await this._sendMessage('listTests', params);
|
return await this._sendMessage('listTests', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async runTests(params: { reporter?: string | undefined; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }): Promise<void> {
|
async runTests(params: { reporter?: string | undefined; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }): Promise<{ status: reporterTypes.FullResult['status'] }> {
|
||||||
await this._sendMessage('runTests', params);
|
return await this._sendMessage('runTests', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findRelatedTestFiles(params: { files: string[]; }): Promise<{ testFiles: string[]; errors?: TestError[] | undefined; }> {
|
async findRelatedTestFiles(params: { files: string[]; }): Promise<{ testFiles: string[]; errors?: reporterTypes.TestError[] | undefined; }> {
|
||||||
return await this._sendMessage('findRelatedTestFiles', params);
|
return await this._sendMessage('findRelatedTestFiles', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,6 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
|
|||||||
this._sendMessageNoReply('stopTests');
|
this._sendMessageNoReply('stopTests');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async closeGracefully(): Promise<void> {
|
async closeGracefully(): Promise<void> {
|
||||||
await this._sendMessage('closeGracefully');
|
await this._sendMessage('closeGracefully');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export interface TestServerInterface {
|
|||||||
projects?: string[];
|
projects?: string[];
|
||||||
reuseContext?: boolean;
|
reuseContext?: boolean;
|
||||||
connectWsEndpoint?: string;
|
connectWsEndpoint?: string;
|
||||||
}): Promise<void>;
|
}): Promise<{ status: reporterTypes.FullResult['status'] }>;
|
||||||
|
|
||||||
findRelatedTestFiles(params: {
|
findRelatedTestFiles(params: {
|
||||||
files: string[];
|
files: string[];
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import path from 'path';
|
|||||||
import { registry, startTraceViewerServer } from 'playwright-core/lib/server';
|
import { registry, startTraceViewerServer } from 'playwright-core/lib/server';
|
||||||
import { ManualPromise, gracefullyProcessExitDoNotHang, isUnderTest } from 'playwright-core/lib/utils';
|
import { ManualPromise, gracefullyProcessExitDoNotHang, isUnderTest } from 'playwright-core/lib/utils';
|
||||||
import type { Transport, HttpServer } from 'playwright-core/lib/utils';
|
import type { Transport, HttpServer } from 'playwright-core/lib/utils';
|
||||||
import type { FullResult, Location, TestError } from '../../types/testReporter';
|
import type * as reporterTypes from '../../types/testReporter';
|
||||||
import { collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
|
import { collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
|
||||||
import type { FullConfigInternal } from '../common/config';
|
import type { FullConfigInternal } from '../common/config';
|
||||||
import { InternalReporter } from '../reporters/internalReporter';
|
import { InternalReporter } from '../reporters/internalReporter';
|
||||||
@ -93,10 +93,10 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
private _config: FullConfigInternal;
|
private _config: FullConfigInternal;
|
||||||
private _globalWatcher: Watcher;
|
private _globalWatcher: Watcher;
|
||||||
private _testWatcher: Watcher;
|
private _testWatcher: Watcher;
|
||||||
private _testRun: { run: Promise<FullResult['status']>, stop: ManualPromise<void> } | undefined;
|
private _testRun: { run: Promise<reporterTypes.FullResult['status']>, stop: ManualPromise<void> } | undefined;
|
||||||
readonly transport: Transport;
|
readonly transport: Transport;
|
||||||
private _queue = Promise.resolve();
|
private _queue = Promise.resolve();
|
||||||
private _globalCleanup: (() => Promise<FullResult['status']>) | undefined;
|
private _globalCleanup: (() => Promise<reporterTypes.FullResult['status']>) | undefined;
|
||||||
readonly _dispatchEvent: TestServerInterfaceEventEmitters['dispatchEvent'];
|
readonly _dispatchEvent: TestServerInterfaceEventEmitters['dispatchEvent'];
|
||||||
|
|
||||||
constructor(config: FullConfigInternal) {
|
constructor(config: FullConfigInternal) {
|
||||||
@ -116,7 +116,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
|
|
||||||
async ping() {}
|
async ping() {}
|
||||||
|
|
||||||
async open(params: { location: Location }) {
|
async open(params: { location: reporterTypes.Location }) {
|
||||||
if (isUnderTest())
|
if (isUnderTest())
|
||||||
return;
|
return;
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@ -138,7 +138,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
await installBrowsers();
|
await installBrowsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
async runGlobalSetup(): Promise<FullResult['status']> {
|
async runGlobalSetup(): Promise<reporterTypes.FullResult['status']> {
|
||||||
await this.runGlobalTeardown();
|
await this.runGlobalTeardown();
|
||||||
|
|
||||||
const reporter = new InternalReporter(new ListReporter());
|
const reporter = new InternalReporter(new ListReporter());
|
||||||
@ -167,7 +167,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
const runner = new Runner(this._config);
|
const runner = new Runner(this._config);
|
||||||
return runner.listTestFiles();
|
return runner.listTestFiles();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const error: TestError = serializeError(e);
|
const error: reporterTypes.TestError = serializeError(e);
|
||||||
error.location = prepareErrorStack(e.stack).location;
|
error.location = prepareErrorStack(e.stack).location;
|
||||||
return { projects: [], error };
|
return { projects: [], error };
|
||||||
}
|
}
|
||||||
@ -214,11 +214,15 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async runTests(params: { reporter?: string; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }) {
|
async runTests(params: { reporter?: string; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }) {
|
||||||
this._queue = this._queue.then(() => this._innerRunTests(params)).catch(printInternalError);
|
let status: reporterTypes.FullResult['status'];
|
||||||
|
this._queue = this._queue.then(async () => {
|
||||||
|
status = await this._innerRunTests(params).catch(printInternalError) || 'failed';
|
||||||
|
});
|
||||||
await this._queue;
|
await this._queue;
|
||||||
|
return { status: status! };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _innerRunTests(params: { reporter?: string; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }) {
|
private async _innerRunTests(params: { reporter?: string; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }): Promise<reporterTypes.FullResult['status']> {
|
||||||
await this.stopTests();
|
await this.stopTests();
|
||||||
const { testIds, projects, locations, grep } = params;
|
const { testIds, projects, locations, grep } = params;
|
||||||
|
|
||||||
@ -244,7 +248,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
return status;
|
return status;
|
||||||
});
|
});
|
||||||
this._testRun = { run, stop };
|
this._testRun = { run, stop };
|
||||||
await run;
|
return await run;
|
||||||
}
|
}
|
||||||
|
|
||||||
async watch(params: { fileNames: string[]; }) {
|
async watch(params: { fileNames: string[]; }) {
|
||||||
@ -256,7 +260,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
this._testWatcher.update([...files], [], true);
|
this._testWatcher.update([...files], [], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
findRelatedTestFiles(params: { files: string[]; }): Promise<{ testFiles: string[]; errors?: TestError[] | undefined; }> {
|
findRelatedTestFiles(params: { files: string[]; }): Promise<{ testFiles: string[]; errors?: reporterTypes.TestError[] | undefined; }> {
|
||||||
const runner = new Runner(this._config);
|
const runner = new Runner(this._config);
|
||||||
return runner.findRelatedTestFiles('out-of-process', params.files);
|
return runner.findRelatedTestFiles('out-of-process', params.files);
|
||||||
}
|
}
|
||||||
@ -271,7 +275,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runTestServer(config: FullConfigInternal, options: { host?: string, port?: number }, openUI: (server: HttpServer, cancelPromise: ManualPromise<void>) => Promise<void>): Promise<FullResult['status']> {
|
export async function runTestServer(config: FullConfigInternal, options: { host?: string, port?: number }, openUI: (server: HttpServer, cancelPromise: ManualPromise<void>) => Promise<void>): Promise<reporterTypes.FullResult['status']> {
|
||||||
const testServer = new TestServer(config);
|
const testServer = new TestServer(config);
|
||||||
const cancelPromise = new ManualPromise<void>();
|
const cancelPromise = new ManualPromise<void>();
|
||||||
const sigintWatcher = new SigIntWatcher();
|
const sigintWatcher = new SigIntWatcher();
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export const UIModeView: React.FC<{}> = ({
|
|||||||
const [runningState, setRunningState] = React.useState<{ testIds: Set<string>, itemSelectedByUser?: boolean } | undefined>();
|
const [runningState, setRunningState] = React.useState<{ testIds: Set<string>, itemSelectedByUser?: boolean } | undefined>();
|
||||||
const [watchAll, setWatchAll] = useSetting<boolean>('watch-all', false);
|
const [watchAll, setWatchAll] = useSetting<boolean>('watch-all', false);
|
||||||
const [watchedTreeIds, setWatchedTreeIds] = React.useState<{ value: Set<string> }>({ value: new Set() });
|
const [watchedTreeIds, setWatchedTreeIds] = React.useState<{ value: Set<string> }>({ value: new Set() });
|
||||||
const runTestPromiseChain = React.useRef(Promise.resolve());
|
const commandQueue = React.useRef(Promise.resolve());
|
||||||
const runTestBacklog = React.useRef<Set<string>>(new Set());
|
const runTestBacklog = React.useRef<Set<string>>(new Set());
|
||||||
const [collapseAllCount, setCollapseAllCount] = React.useState(0);
|
const [collapseAllCount, setCollapseAllCount] = React.useState(0);
|
||||||
const [isDisconnected, setIsDisconnected] = React.useState(false);
|
const [isDisconnected, setIsDisconnected] = React.useState(false);
|
||||||
@ -114,7 +114,6 @@ export const UIModeView: React.FC<{}> = ({
|
|||||||
};
|
};
|
||||||
}, [testServerConnection]);
|
}, [testServerConnection]);
|
||||||
|
|
||||||
|
|
||||||
// This is the main routine, every time connection updates it starts the
|
// This is the main routine, every time connection updates it starts the
|
||||||
// whole workflow.
|
// whole workflow.
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -141,10 +140,18 @@ export const UIModeView: React.FC<{}> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const updateList = async () => {
|
const updateList = async () => {
|
||||||
setIsLoading(true);
|
commandQueue.current = commandQueue.current.then(async () => {
|
||||||
const result = await testServerConnection.listTests({});
|
setIsLoading(true);
|
||||||
teleSuiteUpdater.processListReport(result.report);
|
try {
|
||||||
setIsLoading(false);
|
const result = await testServerConnection.listTests({});
|
||||||
|
teleSuiteUpdater.processListReport(result.report);
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(e);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setTestModel(undefined);
|
setTestModel(undefined);
|
||||||
@ -221,7 +228,7 @@ export const UIModeView: React.FC<{}> = ({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
runTestBacklog.current = new Set([...runTestBacklog.current, ...testIds]);
|
runTestBacklog.current = new Set([...runTestBacklog.current, ...testIds]);
|
||||||
runTestPromiseChain.current = runTestPromiseChain.current.then(async () => {
|
commandQueue.current = commandQueue.current.then(async () => {
|
||||||
const testIds = runTestBacklog.current;
|
const testIds = runTestBacklog.current;
|
||||||
runTestBacklog.current = new Set();
|
runTestBacklog.current = new Set();
|
||||||
if (!testIds.size)
|
if (!testIds.size)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user