chore: iterate towards tele reporter reuse in vscode (#29803)

This commit is contained in:
Pavel Feldman 2024-03-04 11:08:40 -08:00 committed by GitHub
parent de73af99fa
commit 743a6ffe1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 40 additions and 26 deletions

View file

@ -313,7 +313,6 @@ export class TeleReporterReceiver {
} }
private _onExit(): Promise<void> | void { private _onExit(): Promise<void> | void {
// Free up the memory from the string pool.
return this._reporter.onExit?.(); return this._reporter.onExit?.();
} }
@ -416,7 +415,7 @@ export class TeleReporterReceiver {
} }
} }
export class TeleSuite { export class TeleSuite implements reporterTypes.Suite {
title: string; title: string;
location?: reporterTypes.Location; location?: reporterTypes.Location;
parent?: TeleSuite; parent?: TeleSuite;

View file

@ -128,7 +128,7 @@ class HtmlReporter extends EmptyReporter {
const shouldOpen = this._open === 'always' || (!ok && this._open === 'on-failure'); const shouldOpen = this._open === 'always' || (!ok && this._open === 'on-failure');
if (shouldOpen) { if (shouldOpen) {
await showHTMLReport(this._outputFolder, this._options.host, this._options.port, singleTestId); await showHTMLReport(this._outputFolder, this._options.host, this._options.port, singleTestId);
} else if (this._options._mode === 'run') { } else if (this._options._mode === 'test') {
const packageManagerCommand = getPackageManagerExecCommand(); const packageManagerCommand = getPackageManagerExecCommand();
const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), this._outputFolder); const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), this._outputFolder);
const hostArg = this._options.host ? ` --host ${this._options.host}` : ''; const hostArg = this._options.host ? ` --host ${this._options.host}` : '';

View file

@ -316,7 +316,7 @@ export function loadGlobalHook(config: FullConfigInternal, file: string): Promis
return requireOrImportDefaultFunction(path.resolve(config.config.rootDir, file), false); return requireOrImportDefaultFunction(path.resolve(config.config.rootDir, file), false);
} }
export function loadReporter(config: FullConfigInternal | undefined, file: string): Promise<new (arg?: any) => Reporter> { export function loadReporter(config: FullConfigInternal, file: string): Promise<new (arg?: any) => Reporter> {
return requireOrImportDefaultFunction(config ? path.resolve(config.config.rootDir, file) : file, true); return requireOrImportDefaultFunction(config ? path.resolve(config.config.rootDir, file) : file, true);
} }

View file

@ -33,7 +33,7 @@ import { BlobReporter } from '../reporters/blob';
import type { ReporterDescription } from '../../types/test'; import type { ReporterDescription } from '../../types/test';
import { type ReporterV2, wrapReporterAsV2 } from '../reporters/reporterV2'; import { type ReporterV2, wrapReporterAsV2 } from '../reporters/reporterV2';
export async function createReporters(config: FullConfigInternal, mode: 'list' | 'run' | 'ui' | 'merge', descriptions?: ReporterDescription[]): Promise<ReporterV2[]> { export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'ui' | 'merge', descriptions?: ReporterDescription[]): Promise<ReporterV2[]> {
const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = { const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = {
blob: BlobReporter, blob: BlobReporter,
dot: mode === 'list' ? ListModeReporter : DotReporter, dot: mode === 'list' ? ListModeReporter : DotReporter,
@ -50,7 +50,7 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' |
descriptions ??= config.config.reporter; descriptions ??= config.config.reporter;
if (config.configCLIOverrides.additionalReporters) if (config.configCLIOverrides.additionalReporters)
descriptions = [...descriptions, ...config.configCLIOverrides.additionalReporters]; descriptions = [...descriptions, ...config.configCLIOverrides.additionalReporters];
const runOptions = { configDir: config.configDir, _mode: mode }; const runOptions = reporterOptions(config, mode);
for (const r of descriptions) { for (const r of descriptions) {
const [name, arg] = r; const [name, arg] = r;
const options = { ...runOptions, ...arg }; const options = { ...runOptions, ...arg };
@ -63,7 +63,7 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' |
} }
if (process.env.PW_TEST_REPORTER) { if (process.env.PW_TEST_REPORTER) {
const reporterConstructor = await loadReporter(config, process.env.PW_TEST_REPORTER); const reporterConstructor = await loadReporter(config, process.env.PW_TEST_REPORTER);
reporters.push(wrapReporterAsV2(new reporterConstructor())); reporters.push(wrapReporterAsV2(new reporterConstructor(runOptions)));
} }
const someReporterPrintsToStdio = reporters.some(r => r.printsToStdio()); const someReporterPrintsToStdio = reporters.some(r => r.printsToStdio());
@ -78,6 +78,21 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' |
return reporters; return reporters;
} }
export async function createReporterForTestServer(config: FullConfigInternal, file: string, mode: 'test' | 'list', messageSink: (message: any) => void): Promise<ReporterV2> {
const reporterConstructor = await loadReporter(config, file);
const runOptions = reporterOptions(config, mode, messageSink);
const instance = new reporterConstructor(runOptions);
return wrapReporterAsV2(instance);
}
function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'ui' | 'merge', send?: (message: any) => void) {
return {
configDir: config.configDir,
send,
_mode: mode,
};
}
class ListModeReporter extends EmptyReporter { class ListModeReporter extends EmptyReporter {
private config!: FullConfig; private config!: FullConfig;

View file

@ -83,7 +83,7 @@ export class Runner {
// Legacy webServer support. // Legacy webServer support.
webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p }));
const reporter = new InternalReporter(new Multiplexer(await createReporters(config, listOnly ? 'list' : 'run'))); const reporter = new InternalReporter(new Multiplexer(await createReporters(config, listOnly ? 'list' : 'test')));
const taskRunner = listOnly ? createTaskRunnerForList(config, reporter, 'in-process', { failOnLoadErrors: true }) const taskRunner = listOnly ? createTaskRunnerForList(config, reporter, 'in-process', { failOnLoadErrors: true })
: createTaskRunner(config, reporter); : createTaskRunner(config, reporter);

View file

@ -23,7 +23,7 @@ import type { FullResult, TestError } from 'playwright/types/testReporter';
import { loadConfig, restartWithExperimentalTsEsm } from '../common/configLoader'; import { loadConfig, restartWithExperimentalTsEsm } from '../common/configLoader';
import { InternalReporter } from '../reporters/internalReporter'; import { InternalReporter } from '../reporters/internalReporter';
import { Multiplexer } from '../reporters/multiplexer'; import { Multiplexer } from '../reporters/multiplexer';
import { createReporters } from './reporters'; import { createReporterForTestServer, createReporters } from './reporters';
import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer } from './tasks'; import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer } from './tasks';
import type { ConfigCLIOverrides } from '../common/ipc'; import type { ConfigCLIOverrides } from '../common/ipc';
import { Runner } from './runner'; import { Runner } from './runner';
@ -32,8 +32,6 @@ import type { FullConfigInternal } from '../common/config';
import type { TestServerInterface } from './testServerInterface'; import type { TestServerInterface } from './testServerInterface';
import { serializeError } from '../util'; import { serializeError } from '../util';
import { prepareErrorStack } from '../reporters/base'; import { prepareErrorStack } from '../reporters/base';
import { loadReporter } from './loadUtils';
import { wrapReporterAsV2 } from '../reporters/reporterV2';
export async function runTestServer() { export async function runTestServer() {
if (restartWithExperimentalTsEsm(undefined, true)) if (restartWithExperimentalTsEsm(undefined, true))
@ -116,13 +114,13 @@ class Dispatcher implements TestServerInterface {
async listTests(params: { async listTests(params: {
configFile: string; configFile: string;
locations: string[]; locations: string[];
reporter: string; reporters: { file: string, event: string }[];
env: NodeJS.ProcessEnv; env: NodeJS.ProcessEnv;
}) { }) {
const config = await this._loadConfig(params.configFile); const config = await this._loadConfig(params.configFile);
config.cliArgs = params.locations || []; config.cliArgs = params.locations || [];
const wireReporter = await this._createReporter(params.reporter); const wireReporters = await this._wireReporters(config, 'list', params.reporters);
const reporter = new InternalReporter(new Multiplexer([wireReporter])); const reporter = new InternalReporter(new Multiplexer(wireReporters));
const taskRunner = createTaskRunnerForList(config, reporter, 'out-of-process', { failOnLoadErrors: true }); const taskRunner = createTaskRunnerForList(config, reporter, 'out-of-process', { failOnLoadErrors: true });
const testRun = new TestRun(config, reporter); const testRun = new TestRun(config, reporter);
reporter.onConfigure(config.config); reporter.onConfigure(config.config);
@ -140,7 +138,7 @@ class Dispatcher implements TestServerInterface {
async test(params: { async test(params: {
configFile: string; configFile: string;
locations: string[]; locations: string[];
reporter: string; reporters: { file: string, event: string }[];
env: NodeJS.ProcessEnv; env: NodeJS.ProcessEnv;
headed?: boolean; headed?: boolean;
oneWorker?: boolean; oneWorker?: boolean;
@ -171,9 +169,9 @@ class Dispatcher implements TestServerInterface {
config.cliGrep = params.grep; config.cliGrep = params.grep;
config.cliProjectFilter = params.projects?.length ? params.projects : undefined; config.cliProjectFilter = params.projects?.length ? params.projects : undefined;
const wireReporter = await this._createReporter(params.reporter); const wireReporters = await this._wireReporters(config, 'test', params.reporters);
const configReporters = await createReporters(config, 'run'); const configReporters = await createReporters(config, 'test');
const reporter = new InternalReporter(new Multiplexer([...configReporters, wireReporter])); const reporter = new InternalReporter(new Multiplexer([...configReporters, ...wireReporters]));
const taskRunner = createTaskRunnerForTestServer(config, reporter); const taskRunner = createTaskRunnerForTestServer(config, reporter);
const testRun = new TestRun(config, reporter); const testRun = new TestRun(config, reporter);
reporter.onConfigure(config.config); reporter.onConfigure(config.config);
@ -188,6 +186,14 @@ class Dispatcher implements TestServerInterface {
await run; await run;
} }
private async _wireReporters(config: FullConfigInternal, mode: 'test' | 'list', reporters: { file: string, event: string }[]) {
return await Promise.all(reporters.map(r => {
return createReporterForTestServer(config, r.file, mode, message => {
this._dispatchEvent(r.event, message);
});
}));
}
async findRelatedTestFiles(params: { async findRelatedTestFiles(params: {
configFile: string; configFile: string;
files: string[]; files: string[];
@ -219,12 +225,6 @@ class Dispatcher implements TestServerInterface {
private async _loadConfig(configFile: string, overrides?: ConfigCLIOverrides): Promise<FullConfigInternal> { private async _loadConfig(configFile: string, overrides?: ConfigCLIOverrides): Promise<FullConfigInternal> {
return loadConfig({ resolvedConfigFile: configFile, configDir: path.dirname(configFile) }, overrides); return loadConfig({ resolvedConfigFile: configFile, configDir: path.dirname(configFile) }, overrides);
} }
private async _createReporter(file: string) {
const reporterConstructor = await loadReporter(undefined, file);
const instance = new reporterConstructor((message: any) => this._dispatchEvent('report', message));
return wrapReporterAsV2(instance);
}
} }
function chunkToPayload(type: 'stdout' | 'stderr', chunk: Buffer | string) { function chunkToPayload(type: 'stdout' | 'stderr', chunk: Buffer | string) {

View file

@ -33,13 +33,13 @@ export interface TestServerInterface {
listTests(params: { listTests(params: {
configFile: string; configFile: string;
locations: string[]; locations: string[];
reporter: string; reporters: { file: string, event: string }[];
}): Promise<void>; }): Promise<void>;
test(params: { test(params: {
configFile: string; configFile: string;
locations: string[]; locations: string[];
reporter: string; reporters: { file: string, event: string }[];
headed?: boolean; headed?: boolean;
oneWorker?: boolean; oneWorker?: boolean;
trace?: 'on' | 'off'; trace?: 'on' | 'off';