From 4e0727048e89f471ec42a8f66995bfc1e55ee5af Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 6 Mar 2024 10:38:00 -0800 Subject: [PATCH] chore(test runner): move all cli options into ConfigCLIOverrides --- packages/playwright/src/common/config.ts | 17 +++++------ .../playwright/src/common/configLoader.ts | 12 ++------ packages/playwright/src/common/ipc.ts | 7 +++++ packages/playwright/src/program.ts | 18 ++++++------ packages/playwright/src/runner/loadUtils.ts | 10 +++---- packages/playwright/src/runner/runner.ts | 2 +- packages/playwright/src/runner/tasks.ts | 6 ++-- packages/playwright/src/runner/testServer.ts | 10 +++---- packages/playwright/src/runner/uiMode.ts | 10 +++---- packages/playwright/src/runner/watchMode.ts | 28 +++++++++---------- 10 files changed, 59 insertions(+), 61 deletions(-) diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index cfe294a75c..3ff252a698 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -41,20 +41,12 @@ export const defaultTimeout = 30000; export class FullConfigInternal { readonly config: FullConfig; - readonly globalOutputDir: string; readonly configDir: string; readonly configCLIOverrides: ConfigCLIOverrides; readonly ignoreSnapshots: boolean; - readonly preserveOutputDir: boolean; readonly webServers: Exclude[]; readonly plugins: TestRunnerPluginRegistration[]; readonly projects: FullProjectInternal[] = []; - cliArgs: string[] = []; - cliGrep: string | undefined; - cliGrepInvert: string | undefined; - cliProjectFilter?: string[]; - cliListOnly = false; - cliPassWithNoTests?: boolean; testIdMatcher?: Matcher; defineConfigWasUsed = false; @@ -69,8 +61,6 @@ export class FullConfigInternal { this.configDir = configDir; this.configCLIOverrides = configCLIOverrides; - this.globalOutputDir = takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, userConfig.outputDir), throwawayArtifactsPath, path.resolve(process.cwd())); - this.preserveOutputDir = configCLIOverrides.preserveOutputDir || false; this.ignoreSnapshots = takeFirst(configCLIOverrides.ignoreSnapshots, userConfig.ignoreSnapshots, false); const privateConfiguration = (userConfig as any)['@playwright/test']; this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); @@ -138,6 +128,13 @@ export class FullConfigInternal { external: userConfig.build?.external || [], }); this.config.projects = this.projects.map(p => p.project); + + if (configCLIOverrides.ignoreProjectDependencies) { + for (const project of this.projects) { + project.deps = []; + project.teardown = undefined; + } + } } private _assignUniqueProjectIds(projects: FullProjectInternal[]) { diff --git a/packages/playwright/src/common/configLoader.ts b/packages/playwright/src/common/configLoader.ts index 59ba309b2e..a1b3c5b10b 100644 --- a/packages/playwright/src/common/configLoader.ts +++ b/packages/playwright/src/common/configLoader.ts @@ -100,17 +100,11 @@ async function loadUserConfig(location: ConfigLocation): Promise { return object as Config; } -export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides, ignoreProjectDependencies = false): Promise { +export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides): Promise { const userConfig = await loadUserConfig(location); validateConfig(location.resolvedConfigFile || '', userConfig); const fullConfig = new FullConfigInternal(location, userConfig, overrides || {}); fullConfig.defineConfigWasUsed = !!(userConfig as any)[kDefineConfigWasUsed]; - if (ignoreProjectDependencies) { - for (const project of fullConfig.projects) { - project.deps = []; - project.teardown = undefined; - } - } return fullConfig; } @@ -316,7 +310,7 @@ export function resolveConfigFile(configFileOrDirectory: string): string | undef } } -export async function loadConfigFromFileRestartIfNeeded(configFile: string | undefined, overrides?: ConfigCLIOverrides, ignoreDeps?: boolean): Promise { +export async function loadConfigFromFileRestartIfNeeded(configFile: string | undefined, overrides?: ConfigCLIOverrides): Promise { const configFileOrDirectory = configFile ? path.resolve(process.cwd(), configFile) : process.cwd(); const resolvedConfigFile = resolveConfigFile(configFileOrDirectory); if (restartWithExperimentalTsEsm(resolvedConfigFile)) @@ -325,7 +319,7 @@ export async function loadConfigFromFileRestartIfNeeded(configFile: string | und configDir: resolvedConfigFile ? path.dirname(resolvedConfigFile) : configFileOrDirectory, resolvedConfigFile, }; - return await loadConfig(location, overrides, ignoreDeps); + return await loadConfig(location, overrides); } export async function loadEmptyConfigForMergeReports() { diff --git a/packages/playwright/src/common/ipc.ts b/packages/playwright/src/common/ipc.ts index bb35f6c06d..745a50327c 100644 --- a/packages/playwright/src/common/ipc.ts +++ b/packages/playwright/src/common/ipc.ts @@ -20,6 +20,13 @@ import type { ConfigLocation, FullConfigInternal } from './config'; import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test'; export type ConfigCLIOverrides = { + cliArgs?: string[]; + grep?: string; + grepInvert?: string; + projectFilter?: string[]; + listOnly?: boolean; + passWithNoTests?: boolean; + ignoreProjectDependencies?: boolean; forbidOnly?: boolean; fullyParallel?: boolean; globalTimeout?: number; diff --git a/packages/playwright/src/program.ts b/packages/playwright/src/program.ts index fc67d5353e..f0934d7872 100644 --- a/packages/playwright/src/program.ts +++ b/packages/playwright/src/program.ts @@ -152,17 +152,10 @@ Examples: async function runTests(args: string[], opts: { [key: string]: any }) { await startProfiling(); - const config = await loadConfigFromFileRestartIfNeeded(opts.config, overridesFromOptions(opts), opts.deps === false); + const config = await loadConfigFromFileRestartIfNeeded(opts.config, overridesFromOptions(opts, args)); if (!config) return; - config.cliArgs = args; - config.cliGrep = opts.grep as string | undefined; - config.cliGrepInvert = opts.grepInvert as string | undefined; - config.cliListOnly = !!opts.list; - config.cliProjectFilter = opts.project || undefined; - config.cliPassWithNoTests = !!opts.passWithNoTests; - const runner = new Runner(config); let status: FullResult['status']; if (opts.ui || opts.uiHost || opts.uiPort) @@ -226,9 +219,16 @@ async function mergeReports(reportDir: string | undefined, opts: { [key: string] gracefullyProcessExitDoNotHang(0); } -function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrides { +function overridesFromOptions(options: { [key: string]: any }, args: string[]): ConfigCLIOverrides { const shardPair = options.shard ? options.shard.split('/').map((t: string) => parseInt(t, 10)) : undefined; const overrides: ConfigCLIOverrides = { + cliArgs: args, + grep: options.grep as string | undefined, + grepInvert: options.grepInvert as string | undefined, + projectFilter: options.project || undefined, + listOnly: !!options.list, + passWithNoTests: !!options.passWithNoTests, + ignoreProjectDependencies: options.deps === false, forbidOnly: options.forbidOnly ? true : undefined, fullyParallel: options.fullyParallel ? true : undefined, globalTimeout: options.globalTimeout ? parseInt(options.globalTimeout, 10) : undefined, diff --git a/packages/playwright/src/runner/loadUtils.ts b/packages/playwright/src/runner/loadUtils.ts index 4b881264d2..f07b0c5678 100644 --- a/packages/playwright/src/runner/loadUtils.ts +++ b/packages/playwright/src/runner/loadUtils.ts @@ -36,11 +36,11 @@ export async function collectProjectsAndTestFiles(testRun: TestRun, doNotRunTest const config = testRun.config; const fsCache = new Map(); const sourceMapCache = new Map(); - const cliFileMatcher = config.cliArgs.length ? createFileMatcherFromArguments(config.cliArgs) : null; + const cliFileMatcher = config.configCLIOverrides.cliArgs?.length ? createFileMatcherFromArguments(config.configCLIOverrides.cliArgs) : null; // First collect all files for the projects in the command line, don't apply any file filters. const allFilesForProject = new Map(); - const filteredProjects = filterProjects(config.projects, config.cliProjectFilter); + const filteredProjects = filterProjects(config.projects, config.configCLIOverrides.projectFilter); for (const project of filteredProjects) { const files = await collectFilesForProject(project, fsCache); allFilesForProject.set(project, files); @@ -131,9 +131,9 @@ export async function createRootSuite(testRun: TestRun, errors: TestError[], sho // Filter all the projects using grep, testId, file names. { // Interpret cli parameters. - const cliFileFilters = createFileFiltersFromArguments(config.cliArgs); - const grepMatcher = config.cliGrep ? createTitleMatcher(forceRegExp(config.cliGrep)) : () => true; - const grepInvertMatcher = config.cliGrepInvert ? createTitleMatcher(forceRegExp(config.cliGrepInvert)) : () => false; + const cliFileFilters = createFileFiltersFromArguments(config.configCLIOverrides.cliArgs || []); + const grepMatcher = config.configCLIOverrides.grep ? createTitleMatcher(forceRegExp(config.configCLIOverrides.grep)) : () => true; + const grepInvertMatcher = config.configCLIOverrides.grepInvert ? createTitleMatcher(forceRegExp(config.configCLIOverrides.grepInvert)) : () => false; const cliTitleMatcher = (title: string) => !grepInvertMatcher(title) && grepMatcher(title); // Filter file suites for all projects. diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index fc6a803c3c..17b51c2acf 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -77,7 +77,7 @@ export class Runner { async runAllTests(): Promise { const config = this._config; - const listOnly = config.cliListOnly; + const listOnly = config.configCLIOverrides.listOnly; const deadline = config.config.globalTimeout ? monotonicTime() + config.config.globalTimeout : 0; // Legacy webServer support. diff --git a/packages/playwright/src/runner/tasks.ts b/packages/playwright/src/runner/tasks.ts index 1cd57034e4..deeadc01c6 100644 --- a/packages/playwright/src/runner/tasks.ts +++ b/packages/playwright/src/runner/tasks.ts @@ -175,7 +175,7 @@ function createRemoveOutputDirsTask(): Task { return { setup: async ({ config }) => { const outputDirs = new Set(); - const projects = filterProjects(config.projects, config.cliProjectFilter); + const projects = filterProjects(config.projects, config.configCLIOverrides.projectFilter); projects.forEach(p => outputDirs.add(p.project.outputDir)); await Promise.all(Array.from(outputDirs).map(outputDir => removeFolders([outputDir]).then(async ([error]) => { @@ -203,8 +203,8 @@ function createLoadTask(mode: 'out-of-process' | 'in-process', options: { filter testRun.rootSuite = await createRootSuite(testRun, options.failOnLoadErrors ? errors : softErrors, !!options.filterOnly); testRun.failureTracker.onRootSuite(testRun.rootSuite); // Fail when no tests. - if (options.failOnLoadErrors && !testRun.rootSuite.allTests().length && !testRun.config.cliPassWithNoTests && !testRun.config.config.shard) { - if (testRun.config.cliArgs.length) { + if (options.failOnLoadErrors && !testRun.rootSuite.allTests().length && !testRun.config.configCLIOverrides.passWithNoTests && !testRun.config.config.shard) { + if (testRun.config.configCLIOverrides.cliArgs?.length) { throw new Error([ `No tests found.`, `Make sure that arguments are regular expressions matching test files.`, diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index 38c950d164..bc8248f544 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -118,7 +118,7 @@ class Dispatcher implements TestServerInterface { env: NodeJS.ProcessEnv; }) { const config = await this._loadConfig(params.configFile); - config.cliArgs = params.locations || []; + config.configCLIOverrides.cliArgs = params.locations || []; const wireReporter = await createReporterForTestServer(config, params.reporter, 'list', message => this._dispatchEvent('report', message)); const reporter = new InternalReporter(new Multiplexer([wireReporter])); const taskRunner = createTaskRunnerForList(config, reporter, 'out-of-process', { failOnLoadErrors: true }); @@ -164,10 +164,10 @@ class Dispatcher implements TestServerInterface { }; const config = await this._loadConfig(params.configFile, overrides); - config.cliListOnly = false; - config.cliArgs = params.locations || []; - config.cliGrep = params.grep; - config.cliProjectFilter = params.projects?.length ? params.projects : undefined; + config.configCLIOverrides.listOnly = false; + config.configCLIOverrides.cliArgs = params.locations || []; + config.configCLIOverrides.grep = params.grep; + config.configCLIOverrides.projectFilter = params.projects?.length ? params.projects : undefined; const wireReporter = await createReporterForTestServer(config, params.reporter, 'test', message => this._dispatchEvent('report', message)); const configReporters = await createReporters(config, 'test'); diff --git a/packages/playwright/src/runner/uiMode.ts b/packages/playwright/src/runner/uiMode.ts index ac6c6bf11b..0931ab6ee0 100644 --- a/packages/playwright/src/runner/uiMode.ts +++ b/packages/playwright/src/runner/uiMode.ts @@ -43,8 +43,8 @@ class UIMode { constructor(config: FullConfigInternal) { this._config = config; process.env.PW_LIVE_TRACE_STACKS = '1'; - config.cliListOnly = false; - config.cliPassWithNoTests = true; + config.configCLIOverrides.listOnly = false; + config.configCLIOverrides.passWithNoTests = true; config.config.preserveOutput = 'always'; for (const p of config.projects) { @@ -168,7 +168,7 @@ class UIMode { private async _listTests() { const reporter = new InternalReporter(new TeleReporterEmitter(e => this._dispatchEvent('listReport', e), { omitBuffers: true })); - this._config.cliListOnly = true; + this._config.configCLIOverrides.listOnly = true; this._config.testIdMatcher = undefined; const taskRunner = createTaskRunnerForList(this._config, reporter, 'out-of-process', { failOnLoadErrors: false }); const testRun = new TestRun(this._config, reporter); @@ -190,8 +190,8 @@ class UIMode { await this._stopTests(); const testIdSet = testIds ? new Set(testIds) : null; - this._config.cliListOnly = false; - this._config.cliProjectFilter = projects.length ? projects : undefined; + this._config.configCLIOverrides.listOnly = false; + this._config.configCLIOverrides.projectFilter = projects.length ? projects : undefined; this._config.testIdMatcher = id => !testIdSet || testIdSet.has(id); const reporters = await createReporters(this._config, 'ui'); diff --git a/packages/playwright/src/runner/watchMode.ts b/packages/playwright/src/runner/watchMode.ts index 5758bf673e..90564685b7 100644 --- a/packages/playwright/src/runner/watchMode.ts +++ b/packages/playwright/src/runner/watchMode.ts @@ -39,8 +39,8 @@ class FSWatcher { private _timer: NodeJS.Timeout | undefined; async update(config: FullConfigInternal) { - const commandLineFileMatcher = config.cliArgs.length ? createFileMatcherFromArguments(config.cliArgs) : () => true; - const projects = filterProjects(config.projects, config.cliProjectFilter); + const commandLineFileMatcher = config.configCLIOverrides.cliArgs?.length ? createFileMatcherFromArguments(config.configCLIOverrides.cliArgs) : () => true; + const projects = filterProjects(config.projects, config.configCLIOverrides.projectFilter); const projectClosure = buildProjectsClosure(projects); const projectFilters = new Map(); for (const [project, type] of projectClosure) { @@ -107,7 +107,7 @@ class FSWatcher { export async function runWatchModeLoop(config: FullConfigInternal): Promise { // Reset the settings that don't apply to watch. - config.cliPassWithNoTests = true; + config.configCLIOverrides.passWithNoTests = true; for (const p of config.projects) p.project.retries = 0; @@ -172,7 +172,7 @@ export async function runWatchModeLoop(config: FullConfigInternal): Promise ({ projectNames: null })); if (!projectNames) continue; - config.cliProjectFilter = projectNames.length ? projectNames : undefined; + config.configCLIOverrides.projectFilter = projectNames.length ? projectNames : undefined; await fsWatcher.update(config); await runTests(config, failedTestIdCollector); lastRun = { type: 'regular' }; @@ -188,9 +188,9 @@ export async function runWatchModeLoop(config: FullConfigInternal): Promise projectClosure.get(p) === 'dependency'); @@ -386,11 +386,11 @@ function printConfiguration(config: FullConfigInternal, title?: string) { const packageManagerCommand = getPackageManagerExecCommand(); const tokens: string[] = []; tokens.push(`${packageManagerCommand} playwright test`); - tokens.push(...(config.cliProjectFilter || [])?.map(p => colors.blue(`--project ${p}`))); - if (config.cliGrep) - tokens.push(colors.red(`--grep ${config.cliGrep}`)); - if (config.cliArgs) - tokens.push(...config.cliArgs.map(a => colors.bold(a))); + tokens.push(...(config.configCLIOverrides.projectFilter || [])?.map(p => colors.blue(`--project ${p}`))); + if (config.configCLIOverrides.grep) + tokens.push(colors.red(`--grep ${config.configCLIOverrides.grep}`)); + if (config.configCLIOverrides.cliArgs) + tokens.push(...config.configCLIOverrides.cliArgs.map(a => colors.bold(a))); if (title) tokens.push(colors.dim(`(${title})`)); if (seq)