From 2ce354635f87ae184797fe0954fb34ff66b18209 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 4 Apr 2024 16:26:17 -0700 Subject: [PATCH 1/2] fix --- .../src/test-reporter-api/class-fullconfig.md | 4 +++ .../test-reporter-api/class-fullproject.md | 24 +++++++++++++++++ packages/playwright/types/testReporter.d.ts | 26 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/docs/src/test-reporter-api/class-fullconfig.md b/docs/src/test-reporter-api/class-fullconfig.md index ce4318560f3c6..63eec0cd9a0eb 100644 --- a/docs/src/test-reporter-api/class-fullconfig.md +++ b/docs/src/test-reporter-api/class-fullconfig.md @@ -6,6 +6,7 @@ Resolved configuration passed to [`method: Reporter.onBegin`]. ## property: FullConfig.configFile * since: v1.20 +* deprecated: Use [`property: FullProject.configFile`] instead. - type: ?<[string]> Path to the configuration file (if any) used to run the tests. @@ -36,6 +37,7 @@ See [`property: TestConfig.globalTeardown`]. ## property: FullConfig.globalTimeout * since: v1.10 +* deprecated: Use [`property: FullProject.globalTimeout`] instead. - type: <[int]> See [`property: TestConfig.globalTimeout`]. @@ -54,6 +56,7 @@ See [`property: TestConfig.grepInvert`]. ## property: FullConfig.maxFailures * since: v1.10 +* deprecated: Use [`property: FullProject.maxFailures`] instead. - type: <[int]> See [`property: TestConfig.maxFailures`]. @@ -130,6 +133,7 @@ See [`property: TestConfig.webServer`]. ## property: FullConfig.workers * since: v1.10 +* deprecated: Use [`property: FullProject.workers`] instead. - type: <[int]> See [`property: TestConfig.workers`]. diff --git a/docs/src/test-reporter-api/class-fullproject.md b/docs/src/test-reporter-api/class-fullproject.md index 9a744115df427..21582f6fd3260 100644 --- a/docs/src/test-reporter-api/class-fullproject.md +++ b/docs/src/test-reporter-api/class-fullproject.md @@ -7,12 +7,24 @@ to [Reporter]. It exposes some of the resolved fields declared in [TestProject]. You can get [FullProject] instance from [`property: FullConfig.projects`] or [`method: Suite.project`]. +## property: FullProject.configFile +* since: v1.44 +- type: ?<[string]> + +Path to the configuration file (if any) used to run the tests. + ## property: FullProject.dependencies * since: v1.31 - type: <[Array]<[string]>> See [`property: TestProject.dependencies`]. +## property: FullProject.globalTimeout +* since: v1.44 +- type: <[int]> + +See [`property: TestConfig.globalTimeout`]. + ## property: FullProject.grep * since: v1.10 - type: <[RegExp]|[Array]<[RegExp]>> @@ -43,6 +55,12 @@ See [`property: TestProject.name`]. See [`property: TestProject.snapshotDir`]. +## property: FullProject.maxFailures +* since: v1.44 +- type: <[int]> + +See [`property: TestConfig.maxFailures`]. + ## property: FullProject.outputDir * since: v1.10 - type: <[string]> @@ -96,3 +114,9 @@ See [`property: TestProject.timeout`]. - type: <[Fixtures]> See [`property: TestProject.use`]. + +## property: FullProject.workers +* since: v1.44 +- type: <[int]> + +Number of test workers that ran tests from this project. See [`property: TestConfig.workers`]. diff --git a/packages/playwright/types/testReporter.d.ts b/packages/playwright/types/testReporter.d.ts index 250deef694b15..bdbbb916a2bc8 100644 --- a/packages/playwright/types/testReporter.d.ts +++ b/packages/playwright/types/testReporter.d.ts @@ -39,6 +39,7 @@ export interface FullConfig { webServer: ConfigInWorker['webServer']; /** * Path to the configuration file (if any) used to run the tests. + * @deprecated Use [fullProject.configFile](https://playwright.dev/docs/api/class-fullproject#full-project-config-file) instead. */ configFile?: string; @@ -64,6 +65,8 @@ export interface FullConfig { /** * See [testConfig.globalTimeout](https://playwright.dev/docs/api/class-testconfig#test-config-global-timeout). + * @deprecated Use [fullProject.globalTimeout](https://playwright.dev/docs/api/class-fullproject#full-project-global-timeout) + * instead. */ globalTimeout: number; @@ -79,6 +82,7 @@ export interface FullConfig { /** * See [testConfig.maxFailures](https://playwright.dev/docs/api/class-testconfig#test-config-max-failures). + * @deprecated Use [fullProject.maxFailures](https://playwright.dev/docs/api/class-fullproject#full-project-max-failures) instead. */ maxFailures: number; @@ -141,6 +145,7 @@ export interface FullConfig { /** * See [testConfig.workers](https://playwright.dev/docs/api/class-testconfig#test-config-workers). + * @deprecated Use [fullProject.workers](https://playwright.dev/docs/api/class-fullproject#full-project-workers) instead. */ workers: number; } @@ -156,11 +161,21 @@ export interface FullProject { * See [testProject.use](https://playwright.dev/docs/api/class-testproject#test-project-use). */ use: UseOptions; + /** + * Path to the configuration file (if any) used to run the tests. + */ + configFile?: string; + /** * See [testProject.dependencies](https://playwright.dev/docs/api/class-testproject#test-project-dependencies). */ dependencies: Array; + /** + * See [testConfig.globalTimeout](https://playwright.dev/docs/api/class-testconfig#test-config-global-timeout). + */ + globalTimeout: number; + /** * See [testProject.grep](https://playwright.dev/docs/api/class-testproject#test-project-grep). */ @@ -171,6 +186,11 @@ export interface FullProject { */ grepInvert: null|RegExp|Array; + /** + * See [testConfig.maxFailures](https://playwright.dev/docs/api/class-testconfig#test-config-max-failures). + */ + maxFailures: number; + /** * See [testProject.metadata](https://playwright.dev/docs/api/class-testproject#test-project-metadata). */ @@ -225,6 +245,12 @@ export interface FullProject { * See [testProject.timeout](https://playwright.dev/docs/api/class-testproject#test-project-timeout). */ timeout: number; + + /** + * Number of test workers that ran tests from this project. See + * [testConfig.workers](https://playwright.dev/docs/api/class-testconfig#test-config-workers). + */ + workers: number; } /** From e3c0cfb82772b145ab2063a7be250896a89087fb Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 4 Apr 2024 17:10:27 -0700 Subject: [PATCH 2/2] Start replacement --- packages/playwright/src/common/config.ts | 1 + packages/playwright/src/common/ipc.ts | 2 +- packages/playwright/src/reporters/base.ts | 4 ++-- packages/playwright/src/reporters/json.ts | 4 ++-- packages/playwright/src/reporters/junit.ts | 4 ++-- packages/playwright/src/runner/loadUtils.ts | 2 +- packages/playwright/src/runner/runner.ts | 2 +- packages/playwright/src/runner/tasks.ts | 8 ++++---- packages/trace-viewer/src/ui/uiModeFiltersView.tsx | 2 +- packages/trace-viewer/src/ui/uiModeView.tsx | 2 +- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index 9b8be8e7303a3..550f17d2f50e5 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -175,6 +175,7 @@ export class FullProjectInternal { this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate, defaultSnapshotPathTemplate); this.project = { + globalTimeout: fullConfig.config.globalTimeout, grep: takeFirst(projectConfig.grep, config.grep, defaultGrep), grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null), outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), path.join(throwawayArtifactsPath, 'test-results')), diff --git a/packages/playwright/src/common/ipc.ts b/packages/playwright/src/common/ipc.ts index c1c7b2da25fcf..bddfb6238868a 100644 --- a/packages/playwright/src/common/ipc.ts +++ b/packages/playwright/src/common/ipc.ts @@ -129,7 +129,7 @@ export type EnvProducedPayload = [string, string | null][]; export function serializeConfig(config: FullConfigInternal, passCompilationCache: boolean): SerializedConfig { const result: SerializedConfig = { - location: { configDir: config.configDir, resolvedConfigFile: config.config.configFile }, + location: { configDir: config.configDir, resolvedConfigFile: config.config.projects[0]?.configFile }, configCLIOverrides: config.configCLIOverrides, compilationCache: passCompilationCache ? serializeCompilationCache() : undefined, }; diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index fff2703208151..a66b9ea8fa00f 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -153,7 +153,7 @@ export class BaseReporter implements ReporterV2 { } protected generateStartingMessage() { - const jobs = this.config.metadata.actualWorkers ?? this.config.workers; + const jobs = this.config.metadata.actualWorkers ?? this.config.projects[0].workers; const shardDetails = this.config.shard ? `, shard ${this.config.shard.current} of ${this.config.shard.total}` : ''; if (!this.totalTestCount) return ''; @@ -195,7 +195,7 @@ export class BaseReporter implements ReporterV2 { if (expected) tokens.push(colors.green(` ${expected} passed`) + colors.dim(` (${milliseconds(this.result.duration)})`)); if (this.result.status === 'timedout') - tokens.push(colors.red(` Timed out waiting ${this.config.globalTimeout / 1000}s for the entire test run`)); + tokens.push(colors.red(` Timed out waiting ${this.config.projects[0].globalTimeout / 1000}s for the entire test run`)); if (fatalErrors.length && expected + unexpected.length + interrupted.length + flaky.length > 0) tokens.push(colors.red(` ${fatalErrors.length === 1 ? '1 error was not a part of any test' : fatalErrors.length + ' errors were not a part of any test'}, see above for details`)); diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index 36ba67825813e..5ba8791cb0d5f 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -231,8 +231,8 @@ class JSONReporter extends EmptyReporter { async function outputReport(report: JSONReport, config: FullConfig, outputFile: string | undefined) { const reportString = JSON.stringify(report, undefined, 2); if (outputFile) { - assert(config.configFile || path.isAbsolute(outputFile), 'Expected fully resolved path if not using config file.'); - outputFile = config.configFile ? path.resolve(path.dirname(config.configFile), outputFile) : outputFile; + assert(config.projects[0]?.configFile || path.isAbsolute(outputFile), 'Expected fully resolved path if not using config file.'); + outputFile = config.projects[0]?.configFile ? path.resolve(path.dirname(config.projects[0]?.configFile), outputFile) : outputFile; await fs.promises.mkdir(path.dirname(outputFile), { recursive: true }); await fs.promises.writeFile(outputFile, reportString); } else { diff --git a/packages/playwright/src/reporters/junit.ts b/packages/playwright/src/reporters/junit.ts index cc526abb93fe2..1eaa89003aeb7 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -55,8 +55,8 @@ class JUnitReporter extends EmptyReporter { this.timestamp = new Date(); this.startTime = monotonicTime(); if (this.outputFile) { - assert(this.config.configFile || path.isAbsolute(this.outputFile), 'Expected fully resolved path if not using config file.'); - this.resolvedOutputFile = this.config.configFile ? path.resolve(path.dirname(this.config.configFile), this.outputFile) : this.outputFile; + assert(this.config.projects[0]?.configFile || path.isAbsolute(this.outputFile), 'Expected fully resolved path if not using config file.'); + this.resolvedOutputFile = this.config.projects[0]?.configFile ? path.resolve(path.dirname(this.config.projects[0]?.configFile), this.outputFile) : this.outputFile; } } diff --git a/packages/playwright/src/runner/loadUtils.ts b/packages/playwright/src/runner/loadUtils.ts index b138b6fae4149..d7d8ca76afbfb 100644 --- a/packages/playwright/src/runner/loadUtils.ts +++ b/packages/playwright/src/runner/loadUtils.ts @@ -169,7 +169,7 @@ export async function createRootSuite(testRun: TestRun, errors: TestError[], sho if (config.config.forbidOnly) { const onlyTestsAndSuites = rootSuite._getOnlyItems(); if (onlyTestsAndSuites.length > 0) { - const configFilePath = config.config.configFile ? path.relative(config.config.rootDir, config.config.configFile) : undefined; + const configFilePath = config.config.projects[0]?.configFile ? path.relative(config.config.rootDir, config.config.projects[0]?.configFile) : undefined; errors.push(...createForbidOnlyErrors(onlyTestsAndSuites, config.configCLIOverrides.forbidOnly, configFilePath)); } } diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index 68110bd5ecc8e..5353f313aa170 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -74,7 +74,7 @@ export class Runner { async runAllTests(): Promise { const config = this._config; const listOnly = config.cliListOnly; - const deadline = config.config.globalTimeout ? monotonicTime() + config.config.globalTimeout : 0; + const deadline = config.config.projects[0].globalTimeout ? monotonicTime() + config.config.projects[0].globalTimeout : 0; // Legacy webServer support. webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); diff --git a/packages/playwright/src/runner/tasks.ts b/packages/playwright/src/runner/tasks.ts index 46d0ae4181756..48e8e786e37f8 100644 --- a/packages/playwright/src/runner/tasks.ts +++ b/packages/playwright/src/runner/tasks.ts @@ -63,7 +63,7 @@ export class TestRun { } export function createTaskRunner(config: FullConfigInternal, reporter: ReporterV2): TaskRunner { - const taskRunner = new TaskRunner(reporter, config.config.globalTimeout); + const taskRunner = new TaskRunner(reporter, config.config.projects[0].globalTimeout); addGlobalSetupTasks(taskRunner, config); taskRunner.addTask('load tests', createLoadTask('in-process', { filterOnly: true, failOnLoadErrors: true })); addRunTasks(taskRunner, config); @@ -109,14 +109,14 @@ function addRunTasks(taskRunner: TaskRunner, config: FullConfigInternal } export function createTaskRunnerForList(config: FullConfigInternal, reporter: ReporterV2, mode: 'in-process' | 'out-of-process', options: { failOnLoadErrors: boolean }): TaskRunner { - const taskRunner = new TaskRunner(reporter, config.config.globalTimeout); + const taskRunner = new TaskRunner(reporter, config.config.projects[0].globalTimeout); taskRunner.addTask('load tests', createLoadTask(mode, { ...options, filterOnly: false })); taskRunner.addTask('report begin', createReportBeginTask()); return taskRunner; } export function createTaskRunnerForListFiles(config: FullConfigInternal, reporter: ReporterV2): TaskRunner { - const taskRunner = new TaskRunner(reporter, config.config.globalTimeout); + const taskRunner = new TaskRunner(reporter, config.config.projects[0].globalTimeout); taskRunner.addTask('load tests', createListFilesTask()); taskRunner.addTask('report begin', createReportBeginTask()); return taskRunner; @@ -283,7 +283,7 @@ function createPhasesTask(): Task { testRun.phases.push(phase); for (const project of phaseProjects) { const projectSuite = projectToSuite.get(project)!; - const testGroups = createTestGroups(projectSuite, testRun.config.config.workers); + const testGroups = createTestGroups(projectSuite, project.project.workers); phase.projects.push({ project, projectSuite, testGroups }); testGroupsInPhase += testGroups.length; } diff --git a/packages/trace-viewer/src/ui/uiModeFiltersView.tsx b/packages/trace-viewer/src/ui/uiModeFiltersView.tsx index a6cff6ecf8025..5d0596bd1df32 100644 --- a/packages/trace-viewer/src/ui/uiModeFiltersView.tsx +++ b/packages/trace-viewer/src/ui/uiModeFiltersView.tsx @@ -80,7 +80,7 @@ export const FiltersView: React.FC<{ const copy = new Map(projectFilters); copy.set(projectName, !copy.get(projectName)); setProjectFilters(copy); - const configFile = testModel?.config?.configFile; + const configFile = testModel?.config?.projects[0]?.configFile; if (configFile) settings.setObject(configFile + ':projects', [...copy.entries()].filter(([_, v]) => v).map(([k]) => k)); }}/> diff --git a/packages/trace-viewer/src/ui/uiModeView.tsx b/packages/trace-viewer/src/ui/uiModeView.tsx index 03abb468ab6df..6a269b5371273 100644 --- a/packages/trace-viewer/src/ui/uiModeView.tsx +++ b/packages/trace-viewer/src/ui/uiModeView.tsx @@ -202,7 +202,7 @@ export const UIModeView: React.FC<{}> = ({ return; const { config, rootSuite } = testModel; - const selectedProjects = config.configFile ? settings.getObject(config.configFile + ':projects', undefined) : undefined; + const selectedProjects = config.projects[0]?.configFile ? settings.getObject(config.projects[0]?.configFile + ':projects', undefined) : undefined; const newFilter = new Map(projectFilters); for (const projectName of newFilter.keys()) { if (!rootSuite.suites.find(s => s.title === projectName))