From 3736a7356d6a5712cc383a256eeb4263d7f5ccb8 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Wed, 16 Apr 2025 12:49:09 -0700 Subject: [PATCH 1/6] chore(reporter): normalize reporter option types --- packages/playwright/src/reporters/base.ts | 2 +- packages/playwright/src/reporters/blob.ts | 13 ++------ packages/playwright/src/reporters/html.ts | 22 ++++--------- packages/playwright/src/reporters/json.ts | 8 ++--- packages/playwright/src/reporters/junit.ts | 11 ++----- packages/playwright/src/reporters/list.ts | 5 +-- packages/playwright/src/reporters/types.ts | 34 +++++++++++++++++++++ packages/playwright/src/runner/reporters.ts | 7 ++--- 8 files changed, 53 insertions(+), 49 deletions(-) create mode 100644 packages/playwright/src/reporters/types.ts diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index ad25258b1b783..dcf02f80a4450 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -597,7 +597,7 @@ export function resolveOutputFile(reporterName: string, options: { fileName: string, outputDir: string, } - }): { outputFile: string, outputDir?: string } |undefined { + }): { outputFile: string, outputDir?: string } | undefined { const name = reporterName.toUpperCase(); let outputFile = resolveFromEnv(`PLAYWRIGHT_${name}_OUTPUT_FILE`); if (!outputFile && options.outputFile) diff --git a/packages/playwright/src/reporters/blob.ts b/packages/playwright/src/reporters/blob.ts index 4168e1cb68ee2..c10340ff18eac 100644 --- a/packages/playwright/src/reporters/blob.ts +++ b/packages/playwright/src/reporters/blob.ts @@ -29,14 +29,7 @@ import { TeleReporterEmitter } from './teleEmitter'; import type { FullConfig, FullResult, TestResult } from '../../types/testReporter'; import type { JsonAttachment, JsonEvent } from '../isomorphic/teleReceiver'; import type { EventEmitter } from 'events'; - -type BlobReporterOptions = { - configDir: string; - outputDir?: string; - fileName?: string; - outputFile?: string; - _commandHash: string; -}; +import type { ExtractReporterOptions } from './types'; export const currentBlobReportVersion = 2; @@ -51,11 +44,11 @@ export type BlobReportMetadata = { export class BlobReporter extends TeleReporterEmitter { private readonly _messages: JsonEvent[] = []; private readonly _attachments: { originalPath: string, zipEntryPath: string }[] = []; - private readonly _options: BlobReporterOptions; + private readonly _options: ExtractReporterOptions<'blob'>; private readonly _salt: string; private _config!: FullConfig; - constructor(options: BlobReporterOptions) { + constructor(options: ExtractReporterOptions<'blob'>) { super(message => this._messages.push(message)); this._options = options; if (this._options.fileName && !this._options.fileName.endsWith('.zip')) diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 916e39e4e67cb..919f79644fcca 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -34,34 +34,24 @@ import type * as api from '../../types/testReporter'; import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep, TestAnnotation } from '@html-reporter/types'; import type { ZipFile } from 'playwright-core/lib/zipBundle'; import type { TransformCallback } from 'stream'; +import type { ExtractReporterOptions } from './types'; type TestEntry = { testCase: TestCase; testCaseSummary: TestCaseSummary }; -const htmlReportOptions = ['always', 'never', 'on-failure']; -type HtmlReportOpenOption = (typeof htmlReportOptions)[number]; +type HtmlReportOpenOption = Exclude['open'], undefined>; +const htmlReportOptions: HtmlReportOpenOption[] = ['always', 'never', 'on-failure']; const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { - return htmlReportOptions.includes(type); -}; - -type HtmlReporterOptions = { - configDir: string, - outputFolder?: string, - open?: HtmlReportOpenOption, - host?: string, - port?: number, - attachmentsBaseURL?: string, - _mode?: 'test' | 'list'; - _isTestServer?: boolean; + return htmlReportOptions.includes(type as HtmlReportOpenOption); }; class HtmlReporter implements ReporterV2 { private config!: api.FullConfig; private suite!: api.Suite; - private _options: HtmlReporterOptions; + private _options: ExtractReporterOptions<'html'>; private _outputFolder!: string; private _attachmentsBaseURL!: string; private _open: string | undefined; @@ -70,7 +60,7 @@ class HtmlReporter implements ReporterV2 { private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; private _topLevelErrors: api.TestError[] = []; - constructor(options: HtmlReporterOptions) { + constructor(options: ExtractReporterOptions<'html'>) { this._options = options; } diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index 6cdd994531983..ca519e126f357 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -24,11 +24,7 @@ import { getProjectId } from '../common/config'; import type { ReporterV2 } from './reporterV2'; import type { FullConfig, FullResult, JSONReport, JSONReportError, JSONReportSpec, JSONReportSuite, JSONReportTest, JSONReportTestResult, JSONReportTestStep, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; - -type JSONOptions = { - outputFile?: string, - configDir: string, -}; +import type { ExtractReporterOptions } from './types'; class JSONReporter implements ReporterV2 { config!: FullConfig; @@ -36,7 +32,7 @@ class JSONReporter implements ReporterV2 { private _errors: TestError[] = []; private _resolvedOutputFile: string | undefined; - constructor(options: JSONOptions) { + constructor(options: ExtractReporterOptions<'json'>) { this._resolvedOutputFile = resolveOutputFile('JSON', options)?.outputFile; } diff --git a/packages/playwright/src/reporters/junit.ts b/packages/playwright/src/reporters/junit.ts index a89ebd7df7fbf..16496e4884b0c 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -24,14 +24,7 @@ import { stripAnsiEscapes } from '../util'; import type { ReporterV2 } from './reporterV2'; import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter'; - -type JUnitOptions = { - outputFile?: string, - stripANSIControlSequences?: boolean, - includeProjectInTestName?: boolean, - - configDir: string, -}; +import type { ExtractReporterOptions } from './types'; class JUnitReporter implements ReporterV2 { private config!: FullConfig; @@ -45,7 +38,7 @@ class JUnitReporter implements ReporterV2 { private stripANSIControlSequences = false; private includeProjectInTestName = false; - constructor(options: JUnitOptions) { + constructor(options: ExtractReporterOptions<'junit'>) { this.stripANSIControlSequences = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences); this.includeProjectInTestName = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName); this.configDir = options.configDir; diff --git a/packages/playwright/src/reporters/list.ts b/packages/playwright/src/reporters/list.ts index f388f80aef9cf..fb088289aa6ec 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -21,6 +21,7 @@ import { TerminalReporter, stepSuffix } from './base'; import { stripAnsiEscapes } from '../util'; import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; +import type { ExtractReporterOptions } from './types'; // Allow it in the Visual Studio Code Terminal and the new Windows Terminal const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION; @@ -37,9 +38,9 @@ class ListReporter extends TerminalReporter { private _needNewLine = false; private _printSteps: boolean; - constructor(options: { printSteps?: boolean } = {}) { + constructor(options?: ExtractReporterOptions<'list'>) { super(); - this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options.printSteps); + this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options?.printSteps); } override onBegin(suite: Suite) { diff --git a/packages/playwright/src/reporters/types.ts b/packages/playwright/src/reporters/types.ts new file mode 100644 index 0000000000000..e7b3a3af877c2 --- /dev/null +++ b/packages/playwright/src/reporters/types.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ReporterDescription } from '../../types/test'; +import type { TestError } from '../../types/testReporter'; +import type { ReporterV2 } from './reporterV2'; + +export type ReporterOptions = { + configDir: string, + _mode: 'list' | 'test' | 'merge', + _isTestServer: boolean, + _commandHash: string, +}; + +export type ExtractReporterSpecificOptions = Extract>[1]; + +export type ExtractReporterOptions = ExtractReporterSpecificOptions & ReporterOptions; + +export interface ErrorCollectingReporter extends ReporterV2 { + errors(): TestError[]; +} diff --git a/packages/playwright/src/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index 6b00a2599c9f1..70dabf5ae5a86 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -37,6 +37,7 @@ import type { BuiltInReporter, FullConfigInternal } from '../common/config'; import type { Suite } from '../common/test'; import type { Screen } from '../reporters/base'; import type { ReporterV2 } from '../reporters/reporterV2'; +import type { ErrorCollectingReporter, ReporterOptions } from '../reporters/types'; export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean, descriptions?: ReporterDescription[]): Promise { @@ -90,10 +91,6 @@ export async function createReporterForTestServer(file: string, messageSink: (me })); } -interface ErrorCollectingReporter extends ReporterV2 { - errors(): TestError[]; -} - export function createErrorCollectingReporter(screen: Screen, writeToConsole?: boolean): ErrorCollectingReporter { const errors: TestError[] = []; return { @@ -107,7 +104,7 @@ export function createErrorCollectingReporter(screen: Screen, writeToConsole?: b }; } -function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean) { +function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean): ReporterOptions { return { configDir: config.configDir, _mode: mode, From 146dc8b6d61d862034ccac04f2eb688b7d9301cc Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Tue, 22 Apr 2025 08:19:27 -0700 Subject: [PATCH 2/6] Share exports instead of ternary --- packages/playwright/src/reporters/blob.ts | 9 ++++++--- packages/playwright/src/reporters/html.ts | 12 +++++++----- packages/playwright/src/reporters/json.ts | 7 +++++-- packages/playwright/src/reporters/junit.ts | 7 +++++-- packages/playwright/src/reporters/list.ts | 7 +++++-- packages/playwright/src/reporters/types.ts | 5 ----- packages/playwright/src/runner/reporters.ts | 1 - packages/playwright/types/test.d.ts | 16 +++++++++++----- utils/generate_types/overrides-test.d.ts | 17 ++++++++++++----- 9 files changed, 51 insertions(+), 30 deletions(-) diff --git a/packages/playwright/src/reporters/blob.ts b/packages/playwright/src/reporters/blob.ts index c10340ff18eac..a6ba61aba8198 100644 --- a/packages/playwright/src/reporters/blob.ts +++ b/packages/playwright/src/reporters/blob.ts @@ -26,10 +26,11 @@ import { yazl } from 'playwright-core/lib/zipBundle'; import { resolveOutputFile } from './base'; import { TeleReporterEmitter } from './teleEmitter'; +import type { ReporterOptions } from './types'; +import type { BlobReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, TestResult } from '../../types/testReporter'; import type { JsonAttachment, JsonEvent } from '../isomorphic/teleReceiver'; import type { EventEmitter } from 'events'; -import type { ExtractReporterOptions } from './types'; export const currentBlobReportVersion = 2; @@ -41,14 +42,16 @@ export type BlobReportMetadata = { pathSeparator?: string; }; +type Options = BlobReporterOptions & ReporterOptions; + export class BlobReporter extends TeleReporterEmitter { private readonly _messages: JsonEvent[] = []; private readonly _attachments: { originalPath: string, zipEntryPath: string }[] = []; - private readonly _options: ExtractReporterOptions<'blob'>; + private readonly _options: Options; private readonly _salt: string; private _config!: FullConfig; - constructor(options: ExtractReporterOptions<'blob'>) { + constructor(options: Options) { super(message => this._messages.push(message)); this._options = options; if (this._options.fileName && !this._options.fileName.endsWith('.zip')) diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 919f79644fcca..bcc633f9613b3 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -29,19 +29,21 @@ import { codeFrameColumns } from '../transform/babelBundle'; import { resolveReporterOutputPath, stripAnsiEscapes } from '../util'; import type { ReporterV2 } from './reporterV2'; -import type { Metadata } from '../../types/test'; +import type { HtmlReporterOptions, Metadata } from '../../types/test'; import type * as api from '../../types/testReporter'; import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep, TestAnnotation } from '@html-reporter/types'; import type { ZipFile } from 'playwright-core/lib/zipBundle'; import type { TransformCallback } from 'stream'; -import type { ExtractReporterOptions } from './types'; +import type { ReporterOptions } from './types'; type TestEntry = { testCase: TestCase; testCaseSummary: TestCaseSummary }; -type HtmlReportOpenOption = Exclude['open'], undefined>; +type Options = HtmlReporterOptions & ReporterOptions; + +type HtmlReportOpenOption = Exclude; const htmlReportOptions: HtmlReportOpenOption[] = ['always', 'never', 'on-failure']; const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { @@ -51,7 +53,7 @@ const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { class HtmlReporter implements ReporterV2 { private config!: api.FullConfig; private suite!: api.Suite; - private _options: ExtractReporterOptions<'html'>; + private _options: Options; private _outputFolder!: string; private _attachmentsBaseURL!: string; private _open: string | undefined; @@ -60,7 +62,7 @@ class HtmlReporter implements ReporterV2 { private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; private _topLevelErrors: api.TestError[] = []; - constructor(options: ExtractReporterOptions<'html'>) { + constructor(options: Options) { this._options = options; } diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index ca519e126f357..1bc137a43f5a7 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -23,8 +23,11 @@ import { formatError, nonTerminalScreen, prepareErrorStack, resolveOutputFile } import { getProjectId } from '../common/config'; import type { ReporterV2 } from './reporterV2'; +import type { JsonReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, JSONReport, JSONReportError, JSONReportSpec, JSONReportSuite, JSONReportTest, JSONReportTestResult, JSONReportTestStep, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; -import type { ExtractReporterOptions } from './types'; +import type { ReporterOptions } from './types'; + +type Options = JsonReporterOptions & ReporterOptions; class JSONReporter implements ReporterV2 { config!: FullConfig; @@ -32,7 +35,7 @@ class JSONReporter implements ReporterV2 { private _errors: TestError[] = []; private _resolvedOutputFile: string | undefined; - constructor(options: ExtractReporterOptions<'json'>) { + constructor(options: Options) { this._resolvedOutputFile = resolveOutputFile('JSON', options)?.outputFile; } diff --git a/packages/playwright/src/reporters/junit.ts b/packages/playwright/src/reporters/junit.ts index 16496e4884b0c..ce3d74cc4aad2 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -23,8 +23,11 @@ import { formatFailure, nonTerminalScreen, resolveOutputFile } from './base'; import { stripAnsiEscapes } from '../util'; import type { ReporterV2 } from './reporterV2'; +import type { JUnitReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter'; -import type { ExtractReporterOptions } from './types'; +import type { ReporterOptions } from './types'; + +type Options = JUnitReporterOptions & ReporterOptions; class JUnitReporter implements ReporterV2 { private config!: FullConfig; @@ -38,7 +41,7 @@ class JUnitReporter implements ReporterV2 { private stripANSIControlSequences = false; private includeProjectInTestName = false; - constructor(options: ExtractReporterOptions<'junit'>) { + constructor(options: Options) { this.stripANSIControlSequences = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences); this.includeProjectInTestName = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName); this.configDir = options.configDir; diff --git a/packages/playwright/src/reporters/list.ts b/packages/playwright/src/reporters/list.ts index fb088289aa6ec..8ca291ccfa27c 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -20,14 +20,17 @@ import { ms as milliseconds } from 'playwright-core/lib/utilsBundle'; import { TerminalReporter, stepSuffix } from './base'; import { stripAnsiEscapes } from '../util'; +import type { ListReporterOptions } from '../../types/test'; import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; -import type { ExtractReporterOptions } from './types'; +import type { ReporterOptions } from './types'; // Allow it in the Visual Studio Code Terminal and the new Windows Terminal const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION; const POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'ok' : '✓'; const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '✘'; +type Options = ListReporterOptions & ReporterOptions; + class ListReporter extends TerminalReporter { private _lastRow = 0; private _lastColumn = 0; @@ -38,7 +41,7 @@ class ListReporter extends TerminalReporter { private _needNewLine = false; private _printSteps: boolean; - constructor(options?: ExtractReporterOptions<'list'>) { + constructor(options?: Options) { super(); this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options?.printSteps); } diff --git a/packages/playwright/src/reporters/types.ts b/packages/playwright/src/reporters/types.ts index e7b3a3af877c2..7cbe8ee447ea4 100644 --- a/packages/playwright/src/reporters/types.ts +++ b/packages/playwright/src/reporters/types.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import type { ReporterDescription } from '../../types/test'; import type { TestError } from '../../types/testReporter'; import type { ReporterV2 } from './reporterV2'; @@ -25,10 +24,6 @@ export type ReporterOptions = { _commandHash: string, }; -export type ExtractReporterSpecificOptions = Extract>[1]; - -export type ExtractReporterOptions = ExtractReporterSpecificOptions & ReporterOptions; - export interface ErrorCollectingReporter extends ReporterV2 { errors(): TestError[]; } diff --git a/packages/playwright/src/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index 70dabf5ae5a86..cce9b26d4d203 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -39,7 +39,6 @@ import type { Screen } from '../reporters/base'; import type { ReporterV2 } from '../reporters/reporterV2'; import type { ErrorCollectingReporter, ReporterOptions } from '../reporters/types'; - export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean, descriptions?: ReporterDescription[]): Promise { const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = { blob: BlobReporter, diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index acb47520820ad..5733234824d6c 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -18,15 +18,21 @@ import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse, PageScreenshotOptions } from 'playwright-core'; export * from 'playwright-core'; +export type BlobReporterOptions = { outputDir?: string, fileName?: string }; +export type ListReporterOptions = { printSteps?: boolean }; +export type JUnitReporterOptions = { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }; +export type JsonReporterOptions = { outputFile?: string }; +export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; + export type ReporterDescription = Readonly< - ['blob'] | ['blob', { outputDir?: string, fileName?: string }] | + ['blob'] | ['blob', BlobReporterOptions] | ['dot'] | ['line'] | - ['list'] | ['list', { printSteps?: boolean }] | + ['list'] | ['list', ListReporterOptions] | ['github'] | - ['junit'] | ['junit', { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }] | - ['json'] | ['json', { outputFile?: string }] | - ['html'] | ['html', { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }] | + ['junit'] | ['junit', JUnitReporterOptions] | + ['json'] | ['json', JsonReporterOptions] | + ['html'] | ['html', HtmlOptions] | ['null'] | [string] | [string, any] >; diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 04121cb281706..eb6008945e4e7 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -17,15 +17,22 @@ import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse, PageScreenshotOptions } from 'playwright-core'; export * from 'playwright-core'; +export type BlobReporterOptions = { outputDir?: string, fileName?: string }; +export type HtmlReporterOptions = { outputDir?: string, fileName?: string }; +export type ListReporterOptions = { printSteps?: boolean }; +export type JUnitReporterOptions = { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }; +export type JsonReporterOptions = { outputFile?: string }; +export type HtmlOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; + export type ReporterDescription = Readonly< - ['blob'] | ['blob', { outputDir?: string, fileName?: string }] | + ['blob'] | ['blob', BlobReporterOptions] | ['dot'] | ['line'] | - ['list'] | ['list', { printSteps?: boolean }] | + ['list'] | ['list', ListReporterOptions] | ['github'] | - ['junit'] | ['junit', { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }] | - ['json'] | ['json', { outputFile?: string }] | - ['html'] | ['html', { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }] | + ['junit'] | ['junit', JUnitReporterOptions] | + ['json'] | ['json', JsonReporterOptions] | + ['html'] | ['html', HtmlOptions] | ['null'] | [string] | [string, any] >; From fb765ca5dfed94c67f022911b9ccc4a427146a70 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Tue, 22 Apr 2025 08:26:35 -0700 Subject: [PATCH 3/6] Fix lint --- packages/playwright/types/test.d.ts | 2 +- utils/generate_types/overrides-test.d.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 5733234824d6c..18752a8b71b8e 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -32,7 +32,7 @@ export type ReporterDescription = Readonly< ['github'] | ['junit'] | ['junit', JUnitReporterOptions] | ['json'] | ['json', JsonReporterOptions] | - ['html'] | ['html', HtmlOptions] | + ['html'] | ['html', HtmlReporterOptions] | ['null'] | [string] | [string, any] >; diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index eb6008945e4e7..d9c85faba0a0b 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -18,11 +18,10 @@ import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, export * from 'playwright-core'; export type BlobReporterOptions = { outputDir?: string, fileName?: string }; -export type HtmlReporterOptions = { outputDir?: string, fileName?: string }; export type ListReporterOptions = { printSteps?: boolean }; export type JUnitReporterOptions = { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }; export type JsonReporterOptions = { outputFile?: string }; -export type HtmlOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; +export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; export type ReporterDescription = Readonly< ['blob'] | ['blob', BlobReporterOptions] | @@ -32,7 +31,7 @@ export type ReporterDescription = Readonly< ['github'] | ['junit'] | ['junit', JUnitReporterOptions] | ['json'] | ['json', JsonReporterOptions] | - ['html'] | ['html', HtmlOptions] | + ['html'] | ['html', HtmlReporterOptions] | ['null'] | [string] | [string, any] >; From 7960fffede1cfa6d4ab289e5135218338b06dbd0 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Wed, 30 Apr 2025 06:25:08 -0700 Subject: [PATCH 4/6] Remove `Option` type everywhere --- packages/playwright/src/reporters/base.ts | 7 +++++ packages/playwright/src/reporters/blob.ts | 9 +++---- packages/playwright/src/reporters/html.ts | 11 +++----- packages/playwright/src/reporters/json.ts | 7 ++--- packages/playwright/src/reporters/junit.ts | 7 ++--- packages/playwright/src/reporters/list.ts | 6 ++--- packages/playwright/src/reporters/types.ts | 29 --------------------- packages/playwright/src/runner/reporters.ts | 9 ++++--- 8 files changed, 26 insertions(+), 59 deletions(-) delete mode 100644 packages/playwright/src/reporters/types.ts diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index dcf02f80a4450..dc43f3bd59c8e 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -46,6 +46,13 @@ type TestSummary = { fatalErrors: TestError[]; }; +export type CommonReporterOptions = { + configDir: string, + _mode: 'list' | 'test' | 'merge', + _isTestServer: boolean, + _commandHash: string, +}; + export type Screen = { resolveFiles: 'cwd' | 'rootDir'; colors: Colors; diff --git a/packages/playwright/src/reporters/blob.ts b/packages/playwright/src/reporters/blob.ts index a6ba61aba8198..a0b139d0bcf9f 100644 --- a/packages/playwright/src/reporters/blob.ts +++ b/packages/playwright/src/reporters/blob.ts @@ -23,10 +23,9 @@ import { ManualPromise, calculateSha1, createGuid, getUserAgent } from 'playwrig import { mime } from 'playwright-core/lib/utilsBundle'; import { yazl } from 'playwright-core/lib/zipBundle'; -import { resolveOutputFile } from './base'; +import { resolveOutputFile, CommonReporterOptions } from './base'; import { TeleReporterEmitter } from './teleEmitter'; -import type { ReporterOptions } from './types'; import type { BlobReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, TestResult } from '../../types/testReporter'; import type { JsonAttachment, JsonEvent } from '../isomorphic/teleReceiver'; @@ -42,16 +41,14 @@ export type BlobReportMetadata = { pathSeparator?: string; }; -type Options = BlobReporterOptions & ReporterOptions; - export class BlobReporter extends TeleReporterEmitter { private readonly _messages: JsonEvent[] = []; private readonly _attachments: { originalPath: string, zipEntryPath: string }[] = []; - private readonly _options: Options; + private readonly _options: BlobReporterOptions & CommonReporterOptions; private readonly _salt: string; private _config!: FullConfig; - constructor(options: Options) { + constructor(options: BlobReporterOptions & CommonReporterOptions) { super(message => this._messages.push(message)); this._options = options; if (this._options.fileName && !this._options.fileName.endsWith('.zip')) diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index bcc633f9613b3..c22f7c4929284 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -24,7 +24,7 @@ import { open } from 'playwright-core/lib/utilsBundle'; import { mime } from 'playwright-core/lib/utilsBundle'; import { yazl } from 'playwright-core/lib/zipBundle'; -import { formatError, formatResultFailure, internalScreen } from './base'; +import { CommonReporterOptions, formatError, formatResultFailure, internalScreen } from './base'; import { codeFrameColumns } from '../transform/babelBundle'; import { resolveReporterOutputPath, stripAnsiEscapes } from '../util'; @@ -34,16 +34,13 @@ import type * as api from '../../types/testReporter'; import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep, TestAnnotation } from '@html-reporter/types'; import type { ZipFile } from 'playwright-core/lib/zipBundle'; import type { TransformCallback } from 'stream'; -import type { ReporterOptions } from './types'; type TestEntry = { testCase: TestCase; testCaseSummary: TestCaseSummary }; -type Options = HtmlReporterOptions & ReporterOptions; - -type HtmlReportOpenOption = Exclude; +type HtmlReportOpenOption = NonNullable; const htmlReportOptions: HtmlReportOpenOption[] = ['always', 'never', 'on-failure']; const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { @@ -53,7 +50,7 @@ const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { class HtmlReporter implements ReporterV2 { private config!: api.FullConfig; private suite!: api.Suite; - private _options: Options; + private _options: HtmlReporterOptions & CommonReporterOptions; private _outputFolder!: string; private _attachmentsBaseURL!: string; private _open: string | undefined; @@ -62,7 +59,7 @@ class HtmlReporter implements ReporterV2 { private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; private _topLevelErrors: api.TestError[] = []; - constructor(options: Options) { + constructor(options: HtmlReporterOptions & CommonReporterOptions) { this._options = options; } diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index 1bc137a43f5a7..fb2c0ace3d45a 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -19,15 +19,12 @@ import path from 'path'; import { toPosixPath, MultiMap } from 'playwright-core/lib/utils'; -import { formatError, nonTerminalScreen, prepareErrorStack, resolveOutputFile } from './base'; +import { formatError, nonTerminalScreen, prepareErrorStack, resolveOutputFile, CommonReporterOptions } from './base'; import { getProjectId } from '../common/config'; import type { ReporterV2 } from './reporterV2'; import type { JsonReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, JSONReport, JSONReportError, JSONReportSpec, JSONReportSuite, JSONReportTest, JSONReportTestResult, JSONReportTestStep, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; -import type { ReporterOptions } from './types'; - -type Options = JsonReporterOptions & ReporterOptions; class JSONReporter implements ReporterV2 { config!: FullConfig; @@ -35,7 +32,7 @@ class JSONReporter implements ReporterV2 { private _errors: TestError[] = []; private _resolvedOutputFile: string | undefined; - constructor(options: Options) { + constructor(options: JsonReporterOptions & CommonReporterOptions) { this._resolvedOutputFile = resolveOutputFile('JSON', options)?.outputFile; } diff --git a/packages/playwright/src/reporters/junit.ts b/packages/playwright/src/reporters/junit.ts index ce3d74cc4aad2..72d8da7c779f5 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -19,15 +19,12 @@ import path from 'path'; import { getAsBooleanFromENV } from 'playwright-core/lib/utils'; -import { formatFailure, nonTerminalScreen, resolveOutputFile } from './base'; +import { CommonReporterOptions, formatFailure, nonTerminalScreen, resolveOutputFile } from './base'; import { stripAnsiEscapes } from '../util'; import type { ReporterV2 } from './reporterV2'; import type { JUnitReporterOptions } from '../../types/test'; import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter'; -import type { ReporterOptions } from './types'; - -type Options = JUnitReporterOptions & ReporterOptions; class JUnitReporter implements ReporterV2 { private config!: FullConfig; @@ -41,7 +38,7 @@ class JUnitReporter implements ReporterV2 { private stripANSIControlSequences = false; private includeProjectInTestName = false; - constructor(options: Options) { + constructor(options: JUnitReporterOptions & CommonReporterOptions) { this.stripANSIControlSequences = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences); this.includeProjectInTestName = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName); this.configDir = options.configDir; diff --git a/packages/playwright/src/reporters/list.ts b/packages/playwright/src/reporters/list.ts index 8ca291ccfa27c..0f87d650d665f 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -22,15 +22,13 @@ import { stripAnsiEscapes } from '../util'; import type { ListReporterOptions } from '../../types/test'; import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; -import type { ReporterOptions } from './types'; +import type { CommonReporterOptions } from './base'; // Allow it in the Visual Studio Code Terminal and the new Windows Terminal const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION; const POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'ok' : '✓'; const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '✘'; -type Options = ListReporterOptions & ReporterOptions; - class ListReporter extends TerminalReporter { private _lastRow = 0; private _lastColumn = 0; @@ -41,7 +39,7 @@ class ListReporter extends TerminalReporter { private _needNewLine = false; private _printSteps: boolean; - constructor(options?: Options) { + constructor(options?: ListReporterOptions & CommonReporterOptions) { super(); this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options?.printSteps); } diff --git a/packages/playwright/src/reporters/types.ts b/packages/playwright/src/reporters/types.ts deleted file mode 100644 index 7cbe8ee447ea4..0000000000000 --- a/packages/playwright/src/reporters/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { TestError } from '../../types/testReporter'; -import type { ReporterV2 } from './reporterV2'; - -export type ReporterOptions = { - configDir: string, - _mode: 'list' | 'test' | 'merge', - _isTestServer: boolean, - _commandHash: string, -}; - -export interface ErrorCollectingReporter extends ReporterV2 { - errors(): TestError[]; -} diff --git a/packages/playwright/src/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index cce9b26d4d203..c53f992d816f1 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -35,9 +35,8 @@ import type { ReporterDescription } from '../../types/test'; import type { FullConfig, TestError } from '../../types/testReporter'; import type { BuiltInReporter, FullConfigInternal } from '../common/config'; import type { Suite } from '../common/test'; -import type { Screen } from '../reporters/base'; +import type { CommonReporterOptions, Screen } from '../reporters/base'; import type { ReporterV2 } from '../reporters/reporterV2'; -import type { ErrorCollectingReporter, ReporterOptions } from '../reporters/types'; export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean, descriptions?: ReporterDescription[]): Promise { const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = { @@ -90,6 +89,10 @@ export async function createReporterForTestServer(file: string, messageSink: (me })); } +interface ErrorCollectingReporter extends ReporterV2 { + errors(): TestError[]; +} + export function createErrorCollectingReporter(screen: Screen, writeToConsole?: boolean): ErrorCollectingReporter { const errors: TestError[] = []; return { @@ -103,7 +106,7 @@ export function createErrorCollectingReporter(screen: Screen, writeToConsole?: b }; } -function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean): ReporterOptions { +function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean): CommonReporterOptions { return { configDir: config.configDir, _mode: mode, From 0c16389e5fa5bf22e2878bec4456c8d4c22ef4d4 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Wed, 30 Apr 2025 06:34:17 -0700 Subject: [PATCH 5/6] Restore HTML title --- packages/playwright/src/reporters/html.ts | 8 +------- packages/playwright/types/test.d.ts | 2 +- utils/generate_types/overrides-test.d.ts | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 608cd07217991..0a0fd0a9ff960 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -47,14 +47,8 @@ const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { return htmlReportOptions.includes(type as HtmlReportOpenOption); }; -type HtmlReporterOptions = { +type HtmlReporterOptions = HtmlReporterConfigOptions & { configDir: string, - outputFolder?: string, - open?: HtmlReportOpenOption, - host?: string, - port?: number, - attachmentsBaseURL?: string, - title?: string, _mode?: 'test' | 'list'; _isTestServer?: boolean; }; diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index dbf5fcc46b6da..f0b72d86406aa 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -22,7 +22,7 @@ export type BlobReporterOptions = { outputDir?: string, fileName?: string }; export type ListReporterOptions = { printSteps?: boolean }; export type JUnitReporterOptions = { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }; export type JsonReporterOptions = { outputFile?: string }; -export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; +export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string, title?: string }; export type ReporterDescription = Readonly< ['blob'] | ['blob', BlobReporterOptions] | diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 4e59cb8930c05..99225d36bbf6e 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -21,7 +21,7 @@ export type BlobReporterOptions = { outputDir?: string, fileName?: string }; export type ListReporterOptions = { printSteps?: boolean }; export type JUnitReporterOptions = { outputFile?: string, stripANSIControlSequences?: boolean, includeProjectInTestName?: boolean }; export type JsonReporterOptions = { outputFile?: string }; -export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }; +export type HtmlReporterOptions = { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string, title?: string }; export type ReporterDescription = Readonly< ['blob'] | ['blob', BlobReporterOptions] | From 584f08d44f0d111c531f33bc67d252cfd7d636f8 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Wed, 30 Apr 2025 08:00:55 -0700 Subject: [PATCH 6/6] Fix bad merge --- packages/playwright/src/reporters/html.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 0a0fd0a9ff960..374013d834e3c 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -47,16 +47,10 @@ const isHtmlReportOption = (type: string): type is HtmlReportOpenOption => { return htmlReportOptions.includes(type as HtmlReportOpenOption); }; -type HtmlReporterOptions = HtmlReporterConfigOptions & { - configDir: string, - _mode?: 'test' | 'list'; - _isTestServer?: boolean; -}; - class HtmlReporter implements ReporterV2 { private config!: api.FullConfig; private suite!: api.Suite; - private _options: HtmlReporterOptions & CommonReporterOptions; + private _options: HtmlReporterConfigOptions & CommonReporterOptions; private _outputFolder!: string; private _attachmentsBaseURL!: string; private _open: string | undefined; @@ -66,7 +60,7 @@ class HtmlReporter implements ReporterV2 { private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; private _topLevelErrors: api.TestError[] = []; - constructor(options: HtmlReporterOptions & CommonReporterOptions) { + constructor(options: HtmlReporterConfigOptions & CommonReporterOptions) { this._options = options; }