chore: remove default config from cli (#13832)
This commit is contained in:
parent
4984878411
commit
18bff137ce
|
|
@ -17,6 +17,7 @@
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import type stream from 'stream';
|
import type stream from 'stream';
|
||||||
import * as URL from 'url';
|
import * as URL from 'url';
|
||||||
|
import v8 from 'v8';
|
||||||
|
|
||||||
type NameValue = {
|
type NameValue = {
|
||||||
name: string,
|
name: string,
|
||||||
|
|
@ -214,3 +215,7 @@ export function streamToString(stream: stream.Readable): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isLikelyNpxGlobal = () => process.argv.length >= 2 && process.argv[1].includes('_npx');
|
export const isLikelyNpxGlobal = () => process.argv.length >= 2 && process.argv[1].includes('_npx');
|
||||||
|
|
||||||
|
export function deepCopy<T>(obj: T): T {
|
||||||
|
return v8.deserialize(v8.serialize(obj));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,12 @@ import type { Command } from 'playwright-core/lib/utilsBundle';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import os from 'os';
|
|
||||||
import type { Config } from './types';
|
import type { Config } from './types';
|
||||||
import type { BuiltInReporter } from './runner';
|
|
||||||
import { Runner, builtInReporters, kDefaultConfigFiles } from './runner';
|
import { Runner, builtInReporters, kDefaultConfigFiles } from './runner';
|
||||||
import { stopProfiling, startProfiling } from './profiler';
|
import { stopProfiling, startProfiling } from './profiler';
|
||||||
import type { FilePatternFilter } from './util';
|
import type { FilePatternFilter } from './util';
|
||||||
import { showHTMLReport } from './reporters/html';
|
import { showHTMLReport } from './reporters/html';
|
||||||
import { hostPlatform } from 'playwright-core/lib/utils/hostPlatform';
|
import { baseFullConfig, defaultTimeout, fileIsModule } from './loader';
|
||||||
import { fileIsModule } from './loader';
|
|
||||||
|
|
||||||
const defaultTimeout = 30000;
|
|
||||||
const defaultReporter: BuiltInReporter = process.env.CI ? 'dot' : 'list';
|
|
||||||
|
|
||||||
export function addTestCommand(program: Command) {
|
export function addTestCommand(program: Command) {
|
||||||
const command = program.command('test [test-filter...]');
|
const command = program.command('test [test-filter...]');
|
||||||
|
|
@ -51,7 +45,7 @@ export function addTestCommand(program: Command) {
|
||||||
command.option('--output <dir>', `Folder for output artifacts (default: "test-results")`);
|
command.option('--output <dir>', `Folder for output artifacts (default: "test-results")`);
|
||||||
command.option('--quiet', `Suppress stdio`);
|
command.option('--quiet', `Suppress stdio`);
|
||||||
command.option('--repeat-each <N>', `Run each test N times (default: 1)`);
|
command.option('--repeat-each <N>', `Run each test N times (default: 1)`);
|
||||||
command.option('--reporter <reporter>', `Reporter to use, comma-separated, can be ${builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${defaultReporter}")`);
|
command.option('--reporter <reporter>', `Reporter to use, comma-separated, can be ${builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${baseFullConfig.reporter[0]}")`);
|
||||||
command.option('--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`);
|
command.option('--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`);
|
||||||
command.option('--shard <shard>', `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"`);
|
command.option('--shard <shard>', `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"`);
|
||||||
command.option('--project <project-name...>', `Only run tests from the specified list of projects (default: run all projects)`);
|
command.option('--project <project-name...>', `Only run tests from the specified list of projects (default: run all projects)`);
|
||||||
|
|
@ -108,24 +102,13 @@ Examples:
|
||||||
async function runTests(args: string[], opts: { [key: string]: any }) {
|
async function runTests(args: string[], opts: { [key: string]: any }) {
|
||||||
await startProfiling();
|
await startProfiling();
|
||||||
|
|
||||||
const cpus = os.cpus().length;
|
const overrides = overridesFromOptions(opts);
|
||||||
const workers = hostPlatform.startsWith('mac') && hostPlatform.endsWith('arm64') ? cpus : Math.ceil(cpus / 2);
|
|
||||||
|
|
||||||
const defaultConfig: Config = {
|
|
||||||
preserveOutput: 'always',
|
|
||||||
reporter: [ [defaultReporter] ],
|
|
||||||
reportSlowTests: { max: 5, threshold: 15000 },
|
|
||||||
timeout: defaultTimeout,
|
|
||||||
updateSnapshots: 'missing',
|
|
||||||
workers,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (opts.browser) {
|
if (opts.browser) {
|
||||||
const browserOpt = opts.browser.toLowerCase();
|
const browserOpt = opts.browser.toLowerCase();
|
||||||
if (!['all', 'chromium', 'firefox', 'webkit'].includes(browserOpt))
|
if (!['all', 'chromium', 'firefox', 'webkit'].includes(browserOpt))
|
||||||
throw new Error(`Unsupported browser "${opts.browser}", must be one of "all", "chromium", "firefox" or "webkit"`);
|
throw new Error(`Unsupported browser "${opts.browser}", must be one of "all", "chromium", "firefox" or "webkit"`);
|
||||||
const browserNames = browserOpt === 'all' ? ['chromium', 'firefox', 'webkit'] : [browserOpt];
|
const browserNames = browserOpt === 'all' ? ['chromium', 'firefox', 'webkit'] : [browserOpt];
|
||||||
defaultConfig.projects = browserNames.map(browserName => {
|
overrides.projects = browserNames.map(browserName => {
|
||||||
return {
|
return {
|
||||||
name: browserName,
|
name: browserName,
|
||||||
use: { browserName },
|
use: { browserName },
|
||||||
|
|
@ -133,7 +116,6 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const overrides = overridesFromOptions(opts);
|
|
||||||
if (opts.headed || opts.debug)
|
if (opts.headed || opts.debug)
|
||||||
overrides.use = { headless: false };
|
overrides.use = { headless: false };
|
||||||
if (opts.debug) {
|
if (opts.debug) {
|
||||||
|
|
@ -149,7 +131,7 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
|
||||||
if (restartWithExperimentalTsEsm(resolvedConfigFile))
|
if (restartWithExperimentalTsEsm(resolvedConfigFile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const runner = new Runner(overrides, { defaultConfig });
|
const runner = new Runner(overrides);
|
||||||
const config = resolvedConfigFile ? await runner.loadConfigFromResolvedFile(resolvedConfigFile) : await runner.loadEmptyConfig(configFileOrDirectory);
|
const config = resolvedConfigFile ? await runner.loadConfigFromResolvedFile(resolvedConfigFile) : await runner.loadEmptyConfig(configFileOrDirectory);
|
||||||
if (('projects' in config) && opts.browser)
|
if (('projects' in config) && opts.browser)
|
||||||
throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);
|
throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);
|
||||||
|
|
@ -185,7 +167,7 @@ async function listTestFiles(opts: { [key: string]: any }) {
|
||||||
if (restartWithExperimentalTsEsm(resolvedConfigFile))
|
if (restartWithExperimentalTsEsm(resolvedConfigFile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const runner = new Runner({}, { defaultConfig: {} });
|
const runner = new Runner();
|
||||||
await runner.loadConfigFromResolvedFile(resolvedConfigFile);
|
await runner.loadConfigFromResolvedFile(resolvedConfigFile);
|
||||||
const report = await runner.listTestFiles(resolvedConfigFile, opts.project);
|
const report = await runner.listTestFiles(resolvedConfigFile, opts.project);
|
||||||
write(JSON.stringify(report), () => {
|
write(JSON.stringify(report), () => {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import type { TestError } from '../types/testReporter';
|
||||||
import type { Config, TestStatus } from './types';
|
import type { Config, TestStatus } from './types';
|
||||||
|
|
||||||
export type SerializedLoaderData = {
|
export type SerializedLoaderData = {
|
||||||
defaultConfig: Config;
|
|
||||||
overrides: Config;
|
overrides: Config;
|
||||||
configFile: { file: string } | { configDir: string };
|
configFile: { file: string } | { configDir: string };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,34 +24,36 @@ import type { SerializedLoaderData } from './ipc';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
import { ProjectImpl } from './project';
|
import { ProjectImpl } from './project';
|
||||||
import type { BuiltInReporter } from './runner';
|
import type { BuiltInReporter } from './runner';
|
||||||
import type { Reporter } from '../types/testReporter';
|
import type { Reporter } from '../types/testReporter';
|
||||||
import { builtInReporters } from './runner';
|
import { builtInReporters } from './runner';
|
||||||
import { isRegExp } from 'playwright-core/lib/utils';
|
import { deepCopy, isRegExp } from 'playwright-core/lib/utils';
|
||||||
import { serializeError } from './util';
|
import { serializeError } from './util';
|
||||||
import { _legacyWebServer } from './plugins/webServerPlugin';
|
import { _legacyWebServer } from './plugins/webServerPlugin';
|
||||||
|
import { hostPlatform } from 'playwright-core/lib/utils/hostPlatform';
|
||||||
|
|
||||||
|
export const defaultTimeout = 30000;
|
||||||
|
|
||||||
// To allow multiple loaders in the same process without clearing require cache,
|
// To allow multiple loaders in the same process without clearing require cache,
|
||||||
// we make these maps global.
|
// we make these maps global.
|
||||||
const cachedFileSuites = new Map<string, Suite>();
|
const cachedFileSuites = new Map<string, Suite>();
|
||||||
|
|
||||||
export class Loader {
|
export class Loader {
|
||||||
private _defaultConfig: Config;
|
|
||||||
private _configOverrides: Config;
|
private _configOverrides: Config;
|
||||||
private _fullConfig: FullConfigInternal;
|
private _fullConfig: FullConfigInternal;
|
||||||
private _configDir: string = '';
|
private _configDir: string = '';
|
||||||
private _configFile: string | undefined;
|
private _configFile: string | undefined;
|
||||||
private _projects: ProjectImpl[] = [];
|
private _projects: ProjectImpl[] = [];
|
||||||
|
|
||||||
constructor(defaultConfig: Config, configOverrides: Config) {
|
constructor(configOverrides?: Config) {
|
||||||
this._defaultConfig = defaultConfig;
|
this._configOverrides = configOverrides || {};
|
||||||
this._configOverrides = configOverrides;
|
|
||||||
this._fullConfig = { ...baseFullConfig };
|
this._fullConfig = { ...baseFullConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deserialize(data: SerializedLoaderData): Promise<Loader> {
|
static async deserialize(data: SerializedLoaderData): Promise<Loader> {
|
||||||
const loader = new Loader(data.defaultConfig, data.overrides);
|
const loader = new Loader(data.overrides);
|
||||||
if ('file' in data.configFile)
|
if ('file' in data.configFile)
|
||||||
await loader.loadConfigFile(data.configFile.file);
|
await loader.loadConfigFile(data.configFile.file);
|
||||||
else
|
else
|
||||||
|
|
@ -62,11 +64,12 @@ export class Loader {
|
||||||
async loadConfigFile(file: string): Promise<Config> {
|
async loadConfigFile(file: string): Promise<Config> {
|
||||||
if (this._configFile)
|
if (this._configFile)
|
||||||
throw new Error('Cannot load two config files');
|
throw new Error('Cannot load two config files');
|
||||||
let config = await this._requireOrImport(file);
|
let config = await this._requireOrImport(file) as Config;
|
||||||
if (config && typeof config === 'object' && ('default' in config))
|
if (config && typeof config === 'object' && ('default' in config))
|
||||||
config = config['default'];
|
config = (config as any)['default'];
|
||||||
this._configFile = file;
|
this._configFile = file;
|
||||||
const rawConfig = { ...config };
|
const rawConfig = deepCopy({ ...config, plugins: [] });
|
||||||
|
rawConfig.plugins = config.plugins?.slice() || [] as any;
|
||||||
await this._processConfigObject(config, path.dirname(file));
|
await this._processConfigObject(config, path.dirname(file));
|
||||||
return rawConfig;
|
return rawConfig;
|
||||||
}
|
}
|
||||||
|
|
@ -108,9 +111,6 @@ export class Loader {
|
||||||
if (config.webServer)
|
if (config.webServer)
|
||||||
config.webServer.cwd = config.webServer.cwd ? path.resolve(configDir, config.webServer.cwd) : configDir;
|
config.webServer.cwd = config.webServer.cwd ? path.resolve(configDir, config.webServer.cwd) : configDir;
|
||||||
|
|
||||||
const configUse = mergeObjects(this._defaultConfig.use, config.use);
|
|
||||||
config = mergeObjects(mergeObjects(this._defaultConfig, config), { use: configUse });
|
|
||||||
|
|
||||||
this._fullConfig._configDir = configDir;
|
this._fullConfig._configDir = configDir;
|
||||||
this._fullConfig.rootDir = config.testDir || this._configDir;
|
this._fullConfig.rootDir = config.testDir || this._configDir;
|
||||||
this._fullConfig._globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._globalOutputDir);
|
this._fullConfig._globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._globalOutputDir);
|
||||||
|
|
@ -132,7 +132,7 @@ export class Loader {
|
||||||
this._fullConfig.webServer = takeFirst(this._configOverrides.webServer, config.webServer, baseFullConfig.webServer);
|
this._fullConfig.webServer = takeFirst(this._configOverrides.webServer, config.webServer, baseFullConfig.webServer);
|
||||||
this._fullConfig._plugins = takeFirst(this._configOverrides.plugins, config.plugins, baseFullConfig._plugins);
|
this._fullConfig._plugins = takeFirst(this._configOverrides.plugins, config.plugins, baseFullConfig._plugins);
|
||||||
|
|
||||||
const projects: Project[] = ('projects' in config) && config.projects !== undefined ? config.projects : [config];
|
const projects: Project[] = this._configOverrides.projects || config.projects || [config];
|
||||||
for (const project of projects)
|
for (const project of projects)
|
||||||
this._addProject(config, project, throwawayArtifactsPath);
|
this._addProject(config, project, throwawayArtifactsPath);
|
||||||
this._fullConfig.projects = this._projects.map(p => p.config);
|
this._fullConfig.projects = this._projects.map(p => p.config);
|
||||||
|
|
@ -210,7 +210,6 @@ export class Loader {
|
||||||
|
|
||||||
serialize(): SerializedLoaderData {
|
serialize(): SerializedLoaderData {
|
||||||
return {
|
return {
|
||||||
defaultConfig: this._defaultConfig,
|
|
||||||
configFile: this._configFile ? { file: this._configFile } : { configDir: this._configDir },
|
configFile: this._configFile ? { file: this._configFile } : { configDir: this._configDir },
|
||||||
overrides: this._configOverrides,
|
overrides: this._configOverrides,
|
||||||
};
|
};
|
||||||
|
|
@ -248,7 +247,7 @@ export class Loader {
|
||||||
_screenshotsDir: screenshotsDir,
|
_screenshotsDir: screenshotsDir,
|
||||||
testIgnore: takeFirst(this._configOverrides.testIgnore, projectConfig.testIgnore, config.testIgnore, []),
|
testIgnore: takeFirst(this._configOverrides.testIgnore, projectConfig.testIgnore, config.testIgnore, []),
|
||||||
testMatch: takeFirst(this._configOverrides.testMatch, projectConfig.testMatch, config.testMatch, '**/?(*.)@(spec|test).*'),
|
testMatch: takeFirst(this._configOverrides.testMatch, projectConfig.testMatch, config.testMatch, '**/?(*.)@(spec|test).*'),
|
||||||
timeout: takeFirst(this._configOverrides.timeout, projectConfig.timeout, config.timeout, 10000),
|
timeout: takeFirst(this._configOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout),
|
||||||
use: mergeObjects(mergeObjects(config.use, projectConfig.use), this._configOverrides.use),
|
use: mergeObjects(mergeObjects(config.use, projectConfig.use), this._configOverrides.use),
|
||||||
};
|
};
|
||||||
this._projects.push(new ProjectImpl(fullProject, this._projects.length));
|
this._projects.push(new ProjectImpl(fullProject, this._projects.length));
|
||||||
|
|
@ -467,7 +466,10 @@ function validateProject(file: string, project: Project, title: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseFullConfig: FullConfigInternal = {
|
const cpus = os.cpus().length;
|
||||||
|
const workers = hostPlatform.startsWith('mac') && hostPlatform.endsWith('arm64') ? cpus : Math.ceil(cpus / 2);
|
||||||
|
|
||||||
|
export const baseFullConfig: FullConfigInternal = {
|
||||||
forbidOnly: false,
|
forbidOnly: false,
|
||||||
fullyParallel: false,
|
fullyParallel: false,
|
||||||
globalSetup: null,
|
globalSetup: null,
|
||||||
|
|
@ -478,14 +480,14 @@ const baseFullConfig: FullConfigInternal = {
|
||||||
maxFailures: 0,
|
maxFailures: 0,
|
||||||
preserveOutput: 'always',
|
preserveOutput: 'always',
|
||||||
projects: [],
|
projects: [],
|
||||||
reporter: [ ['list'] ],
|
reporter: [ [process.env.CI ? 'dot' : 'list'] ],
|
||||||
reportSlowTests: null,
|
reportSlowTests: { max: 5, threshold: 15000 },
|
||||||
rootDir: path.resolve(process.cwd()),
|
rootDir: path.resolve(process.cwd()),
|
||||||
quiet: false,
|
quiet: false,
|
||||||
shard: null,
|
shard: null,
|
||||||
updateSnapshots: 'missing',
|
updateSnapshots: 'missing',
|
||||||
version: require('../package.json').version,
|
version: require('../package.json').version,
|
||||||
workers: 1,
|
workers,
|
||||||
webServer: null,
|
webServer: null,
|
||||||
_globalOutputDir: path.resolve(process.cwd()),
|
_globalOutputDir: path.resolve(process.cwd()),
|
||||||
_configDir: '',
|
_configDir: '',
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ export class Runner {
|
||||||
private _reporter!: Reporter;
|
private _reporter!: Reporter;
|
||||||
private _globalInfo: GlobalInfoImpl;
|
private _globalInfo: GlobalInfoImpl;
|
||||||
|
|
||||||
constructor(configOverrides: Config, options: { defaultConfig?: Config } = {}) {
|
constructor(configOverrides?: Config) {
|
||||||
this._loader = new Loader(options.defaultConfig || {}, configOverrides);
|
this._loader = new Loader(configOverrides);
|
||||||
this._globalInfo = new GlobalInfoImpl(this._loader.fullConfig());
|
this._globalInfo = new GlobalInfoImpl(this._loader.fullConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue