chore(test runner): move all cli options into ConfigCLIOverrides
This commit is contained in:
parent
d125ff4d39
commit
4e0727048e
|
|
@ -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<FullConfig['webServer'], null>[];
|
||||
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[]) {
|
||||
|
|
|
|||
|
|
@ -100,17 +100,11 @@ async function loadUserConfig(location: ConfigLocation): Promise<Config> {
|
|||
return object as Config;
|
||||
}
|
||||
|
||||
export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides, ignoreProjectDependencies = false): Promise<FullConfigInternal> {
|
||||
export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides): Promise<FullConfigInternal> {
|
||||
const userConfig = await loadUserConfig(location);
|
||||
validateConfig(location.resolvedConfigFile || '<default config>', 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<FullConfigInternal | null> {
|
||||
export async function loadConfigFromFileRestartIfNeeded(configFile: string | undefined, overrides?: ConfigCLIOverrides): Promise<FullConfigInternal | null> {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<FullProjectInternal, string[]>();
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export class Runner {
|
|||
|
||||
async runAllTests(): Promise<FullResult['status']> {
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ function createRemoveOutputDirsTask(): Task<TestRun> {
|
|||
return {
|
||||
setup: async ({ config }) => {
|
||||
const outputDirs = new Set<string>();
|
||||
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.`,
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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<string>(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');
|
||||
|
|
|
|||
|
|
@ -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<FullProjectInternal, Matcher>();
|
||||
for (const [project, type] of projectClosure) {
|
||||
|
|
@ -107,7 +107,7 @@ class FSWatcher {
|
|||
|
||||
export async function runWatchModeLoop(config: FullConfigInternal): Promise<FullResult['status']> {
|
||||
// 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<Full
|
|||
}).catch(() => ({ 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<Full
|
|||
if (filePattern === null)
|
||||
continue;
|
||||
if (filePattern.trim())
|
||||
config.cliArgs = filePattern.split(' ');
|
||||
config.configCLIOverrides.cliArgs = filePattern.split(' ');
|
||||
else
|
||||
config.cliArgs = [];
|
||||
config.configCLIOverrides.cliArgs = [];
|
||||
await fsWatcher.update(config);
|
||||
await runTests(config, failedTestIdCollector);
|
||||
lastRun = { type: 'regular' };
|
||||
|
|
@ -206,9 +206,9 @@ export async function runWatchModeLoop(config: FullConfigInternal): Promise<Full
|
|||
if (testPattern === null)
|
||||
continue;
|
||||
if (testPattern.trim())
|
||||
config.cliGrep = testPattern;
|
||||
config.configCLIOverrides.grep = testPattern;
|
||||
else
|
||||
config.cliGrep = undefined;
|
||||
config.configCLIOverrides.grep = undefined;
|
||||
await fsWatcher.update(config);
|
||||
await runTests(config, failedTestIdCollector);
|
||||
lastRun = { type: 'regular' };
|
||||
|
|
@ -263,7 +263,7 @@ async function runChangedTests(config: FullConfigInternal, failedTestIdCollector
|
|||
|
||||
// Collect all the affected projects, follow project dependencies.
|
||||
// Prepare to exclude all the projects that do not depend on this file, as if they did not exist.
|
||||
const projects = filterProjects(config.projects, config.cliProjectFilter);
|
||||
const projects = filterProjects(config.projects, config.configCLIOverrides.projectFilter);
|
||||
const projectClosure = buildProjectsClosure(projects);
|
||||
const affectedProjects = affectedProjectsClosure([...projectClosure.keys()], [...filesByProject.keys()]);
|
||||
const affectsAnyDependency = [...affectedProjects].some(p => 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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue