diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index 7e4704649e642..ea63b1d412141 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; @@ -591,7 +598,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..a0b139d0bcf9f 100644 --- a/packages/playwright/src/reporters/blob.ts +++ b/packages/playwright/src/reporters/blob.ts @@ -23,21 +23,14 @@ 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 { BlobReporterOptions } from '../../types/test'; 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; -}; - export const currentBlobReportVersion = 2; export type BlobReportMetadata = { @@ -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: BlobReporterOptions & CommonReporterOptions; private readonly _salt: string; private _config!: FullConfig; - constructor(options: BlobReporterOptions) { + 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 fa668ac06efeb..374013d834e3c 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -24,12 +24,12 @@ 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'; import type { ReporterV2 } from './reporterV2'; -import type { Metadata, TestAnnotation } from '../../types/test'; +import type { HtmlReporterOptions as HtmlReporterConfigOptions, Metadata, TestAnnotation } from '../../types/test'; import type * as api from '../../types/testReporter'; import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep } from '@html-reporter/types'; import type { ZipFile } from 'playwright-core/lib/zipBundle'; @@ -40,29 +40,17 @@ type TestEntry = { testCaseSummary: TestCaseSummary }; -const htmlReportOptions = ['always', 'never', 'on-failure']; -type HtmlReportOpenOption = (typeof htmlReportOptions)[number]; +type HtmlReportOpenOption = NonNullable; +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, - title?: 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: HtmlReporterConfigOptions & CommonReporterOptions; private _outputFolder!: string; private _attachmentsBaseURL!: string; private _open: string | undefined; @@ -72,7 +60,7 @@ class HtmlReporter implements ReporterV2 { private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; private _topLevelErrors: api.TestError[] = []; - constructor(options: HtmlReporterOptions) { + constructor(options: HtmlReporterConfigOptions & CommonReporterOptions) { this._options = options; } diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index 6cdd994531983..fb2c0ace3d45a 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -19,24 +19,20 @@ 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'; -type JSONOptions = { - outputFile?: string, - configDir: string, -}; - class JSONReporter implements ReporterV2 { config!: FullConfig; suite!: Suite; private _errors: TestError[] = []; private _resolvedOutputFile: string | undefined; - constructor(options: JSONOptions) { + 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 a89ebd7df7fbf..72d8da7c779f5 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -19,20 +19,13 @@ 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'; -type JUnitOptions = { - outputFile?: string, - stripANSIControlSequences?: boolean, - includeProjectInTestName?: boolean, - - configDir: string, -}; - class JUnitReporter implements ReporterV2 { private config!: FullConfig; private configDir: string; @@ -45,7 +38,7 @@ class JUnitReporter implements ReporterV2 { private stripANSIControlSequences = false; private includeProjectInTestName = false; - constructor(options: JUnitOptions) { + 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 f388f80aef9cf..0f87d650d665f 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -20,7 +20,9 @@ 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 { 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; @@ -37,9 +39,9 @@ class ListReporter extends TerminalReporter { private _needNewLine = false; private _printSteps: boolean; - constructor(options: { printSteps?: boolean } = {}) { + constructor(options?: ListReporterOptions & CommonReporterOptions) { 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/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index 6b00a2599c9f1..c53f992d816f1 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -35,10 +35,9 @@ 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'; - 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, @@ -107,7 +106,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): CommonReporterOptions { return { configDir: config.configDir, _mode: mode, diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index a8a83fc7827cb..f0b72d86406aa 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, title?: 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, title?: string }] | + ['junit'] | ['junit', JUnitReporterOptions] | + ['json'] | ['json', JsonReporterOptions] | + ['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 deadaafac65ce..99225d36bbf6e 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -17,15 +17,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, title?: 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, title?: string }] | + ['junit'] | ['junit', JUnitReporterOptions] | + ['json'] | ['json', JsonReporterOptions] | + ['html'] | ['html', HtmlReporterOptions] | ['null'] | [string] | [string, any] >;