From 743a6ffe1d5dc354e7a5a21f947ec34911409499 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 4 Mar 2024 11:08:40 -0800 Subject: [PATCH] chore: iterate towards tele reporter reuse in vscode (#29803) --- .../playwright/src/isomorphic/teleReceiver.ts | 3 +- packages/playwright/src/reporters/html.ts | 2 +- packages/playwright/src/runner/loadUtils.ts | 2 +- packages/playwright/src/runner/reporters.ts | 21 ++++++++++-- packages/playwright/src/runner/runner.ts | 2 +- packages/playwright/src/runner/testServer.ts | 32 +++++++++---------- .../src/runner/testServerInterface.ts | 4 +-- 7 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/playwright/src/isomorphic/teleReceiver.ts b/packages/playwright/src/isomorphic/teleReceiver.ts index 1628351a3e..8b64ce747a 100644 --- a/packages/playwright/src/isomorphic/teleReceiver.ts +++ b/packages/playwright/src/isomorphic/teleReceiver.ts @@ -313,7 +313,6 @@ export class TeleReporterReceiver { } private _onExit(): Promise | void { - // Free up the memory from the string pool. return this._reporter.onExit?.(); } @@ -416,7 +415,7 @@ export class TeleReporterReceiver { } } -export class TeleSuite { +export class TeleSuite implements reporterTypes.Suite { title: string; location?: reporterTypes.Location; parent?: TeleSuite; diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 1b66da35f7..e0262122d1 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -128,7 +128,7 @@ class HtmlReporter extends EmptyReporter { const shouldOpen = this._open === 'always' || (!ok && this._open === 'on-failure'); if (shouldOpen) { 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 relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), this._outputFolder); const hostArg = this._options.host ? ` --host ${this._options.host}` : ''; diff --git a/packages/playwright/src/runner/loadUtils.ts b/packages/playwright/src/runner/loadUtils.ts index f6ecccb3d6..4b881264d2 100644 --- a/packages/playwright/src/runner/loadUtils.ts +++ b/packages/playwright/src/runner/loadUtils.ts @@ -316,7 +316,7 @@ export function loadGlobalHook(config: FullConfigInternal, file: string): Promis return requireOrImportDefaultFunction(path.resolve(config.config.rootDir, file), false); } -export function loadReporter(config: FullConfigInternal | undefined, file: string): Promise Reporter> { +export function loadReporter(config: FullConfigInternal, file: string): Promise Reporter> { return requireOrImportDefaultFunction(config ? path.resolve(config.config.rootDir, file) : file, true); } diff --git a/packages/playwright/src/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index 666eb68e40..3ec842f7e7 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -33,7 +33,7 @@ import { BlobReporter } from '../reporters/blob'; import type { ReporterDescription } from '../../types/test'; import { type ReporterV2, wrapReporterAsV2 } from '../reporters/reporterV2'; -export async function createReporters(config: FullConfigInternal, mode: 'list' | 'run' | 'ui' | 'merge', descriptions?: ReporterDescription[]): Promise { +export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'ui' | 'merge', descriptions?: ReporterDescription[]): Promise { const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = { blob: BlobReporter, dot: mode === 'list' ? ListModeReporter : DotReporter, @@ -50,7 +50,7 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' | descriptions ??= config.config.reporter; if (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) { const [name, arg] = r; const options = { ...runOptions, ...arg }; @@ -63,7 +63,7 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' | } if (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()); @@ -78,6 +78,21 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' | return reporters; } +export async function createReporterForTestServer(config: FullConfigInternal, file: string, mode: 'test' | 'list', messageSink: (message: any) => void): Promise { + 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 { private config!: FullConfig; diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index 142f0958cd..fc6a803c3c 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -83,7 +83,7 @@ export class Runner { // Legacy webServer support. 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 }) : createTaskRunner(config, reporter); diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index c21733b9d5..4df7f7fd49 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -23,7 +23,7 @@ import type { FullResult, TestError } from 'playwright/types/testReporter'; import { loadConfig, restartWithExperimentalTsEsm } from '../common/configLoader'; import { InternalReporter } from '../reporters/internalReporter'; import { Multiplexer } from '../reporters/multiplexer'; -import { createReporters } from './reporters'; +import { createReporterForTestServer, createReporters } from './reporters'; import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer } from './tasks'; import type { ConfigCLIOverrides } from '../common/ipc'; import { Runner } from './runner'; @@ -32,8 +32,6 @@ import type { FullConfigInternal } from '../common/config'; import type { TestServerInterface } from './testServerInterface'; import { serializeError } from '../util'; import { prepareErrorStack } from '../reporters/base'; -import { loadReporter } from './loadUtils'; -import { wrapReporterAsV2 } from '../reporters/reporterV2'; export async function runTestServer() { if (restartWithExperimentalTsEsm(undefined, true)) @@ -116,13 +114,13 @@ class Dispatcher implements TestServerInterface { async listTests(params: { configFile: string; locations: string[]; - reporter: string; + reporters: { file: string, event: string }[]; env: NodeJS.ProcessEnv; }) { const config = await this._loadConfig(params.configFile); config.cliArgs = params.locations || []; - const wireReporter = await this._createReporter(params.reporter); - const reporter = new InternalReporter(new Multiplexer([wireReporter])); + const wireReporters = await this._wireReporters(config, 'list', params.reporters); + const reporter = new InternalReporter(new Multiplexer(wireReporters)); const taskRunner = createTaskRunnerForList(config, reporter, 'out-of-process', { failOnLoadErrors: true }); const testRun = new TestRun(config, reporter); reporter.onConfigure(config.config); @@ -140,7 +138,7 @@ class Dispatcher implements TestServerInterface { async test(params: { configFile: string; locations: string[]; - reporter: string; + reporters: { file: string, event: string }[]; env: NodeJS.ProcessEnv; headed?: boolean; oneWorker?: boolean; @@ -171,9 +169,9 @@ class Dispatcher implements TestServerInterface { config.cliGrep = params.grep; config.cliProjectFilter = params.projects?.length ? params.projects : undefined; - const wireReporter = await this._createReporter(params.reporter); - const configReporters = await createReporters(config, 'run'); - const reporter = new InternalReporter(new Multiplexer([...configReporters, wireReporter])); + const wireReporters = await this._wireReporters(config, 'test', params.reporters); + const configReporters = await createReporters(config, 'test'); + const reporter = new InternalReporter(new Multiplexer([...configReporters, ...wireReporters])); const taskRunner = createTaskRunnerForTestServer(config, reporter); const testRun = new TestRun(config, reporter); reporter.onConfigure(config.config); @@ -188,6 +186,14 @@ class Dispatcher implements TestServerInterface { 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: { configFile: string; files: string[]; @@ -219,12 +225,6 @@ class Dispatcher implements TestServerInterface { private async _loadConfig(configFile: string, overrides?: ConfigCLIOverrides): Promise { 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) { diff --git a/packages/playwright/src/runner/testServerInterface.ts b/packages/playwright/src/runner/testServerInterface.ts index 1e844d8123..23c404da84 100644 --- a/packages/playwright/src/runner/testServerInterface.ts +++ b/packages/playwright/src/runner/testServerInterface.ts @@ -33,13 +33,13 @@ export interface TestServerInterface { listTests(params: { configFile: string; locations: string[]; - reporter: string; + reporters: { file: string, event: string }[]; }): Promise; test(params: { configFile: string; locations: string[]; - reporter: string; + reporters: { file: string, event: string }[]; headed?: boolean; oneWorker?: boolean; trace?: 'on' | 'off';