chore: add explicit command for gui runner (#21509)

This commit is contained in:
Pavel Feldman 2023-03-09 08:04:02 -08:00 committed by GitHub
parent 9191c72a3f
commit 47a71731f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 34 deletions

View File

@ -30,6 +30,7 @@ import type { FullResult } from '../reporter';
export function addTestCommands(program: Command) {
addTestCommand(program);
addOpenCommand(program);
addShowReportCommand(program);
addListFilesCommand(program);
}
@ -37,32 +38,8 @@ export function addTestCommands(program: Command) {
function addTestCommand(program: Command) {
const command = program.command('test [test-filter...]');
command.description('run tests with Playwright Test');
command.option('--browser <browser>', `Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium")`);
command.option('--headed', `Run tests in headed browsers (default: headless)`);
command.option('--debug', `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --max-failures=1 --headed --workers=1" options`);
command.option('-c, --config <file>', `Configuration file, or a test directory with optional ${kDefaultConfigFiles.map(file => `"${file}"`).join('/')}`);
command.option('--forbid-only', `Fail if test.only is called (default: false)`);
command.option('--fully-parallel', `Run all tests in parallel (default: false)`);
command.option('-g, --grep <grep>', `Only run tests matching this regular expression (default: ".*")`);
command.option('-gv, --grep-invert <grep>', `Only run tests that do not match this regular expression`);
command.option('--global-timeout <timeout>', `Maximum time this test suite can run in milliseconds (default: unlimited)`);
command.option('--ignore-snapshots', `Ignore screenshot and snapshot expectations`);
command.option('-j, --workers <workers>', `Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%)`);
command.option('--list', `Collect all the tests and report them, but do not run`);
command.option('--max-failures <N>', `Stop after the first N failures`);
command.option('--no-deps', 'Do not run project dependencies');
command.option('--output <dir>', `Folder for output artifacts (default: "test-results")`);
command.option('--pass-with-no-tests', `Makes test run succeed even if no tests were found`);
command.option('--quiet', `Suppress stdio`);
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: "${baseFullConfig.reporter[0]}")`);
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('--project <project-name...>', `Only run tests from the specified list of projects (default: run all projects)`);
command.option('--timeout <timeout>', `Specify test timeout threshold in milliseconds, zero for unlimited (default: ${defaultTimeout})`);
command.option('--trace <mode>', `Force tracing mode, can be ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`);
command.option('-u, --update-snapshots', `Update snapshots with actual results (default: only create missing snapshots)`);
command.option('-x', `Stop after the first failure`);
const options = [...sharedOptions, ...testOnlyOptions].sort((a, b) => a[0].replace(/-/g, '').localeCompare(b[0].replace(/-/g, '')));
options.forEach(([name, description]) => command.option(name, description));
command.action(async (args, opts) => {
try {
await runTests(args, opts);
@ -79,7 +56,31 @@ Examples:
$ npx playwright test my.spec.ts
$ npx playwright test some.spec.ts:42
$ npx playwright test --headed
$ npx playwright test --browser=webkit`);
$ npx playwright test --project=webkit`);
}
function addOpenCommand(program: Command) {
const command = program.command('gui [test-filter...]');
command.description('open Playwright Test UI');
sharedOptions.forEach(([name, description]) => command.option(name, description));
command.action(async (args, opts) => {
try {
opts.ui = true;
await runTests(args, opts);
} catch (e) {
console.error(e);
process.exit(1);
}
});
command.addHelpText('afterAll', `
Arguments [test-filter...]:
Pass arguments to filter test files. Each argument is treated as a regular expression. Matching is performed against the absolute file paths.
Examples:
$ npx playwright gui my.spec.ts
$ npx playwright gui some.spec.ts:42
$ npx playwright gui --headed
$ npx playwright gui --project=webkit`);
}
function addListFilesCommand(program: Command) {
@ -168,7 +169,7 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
const runner = new Runner(config);
let status: FullResult['status'];
if (process.env.PWTEST_UI)
if (opts.ui)
status = await runner.uiAllTests();
else if (process.env.PWTEST_WATCH)
status = await runner.watchAllTests();
@ -257,3 +258,35 @@ function restartWithExperimentalTsEsm(configFile: string | null): boolean {
}
const kTraceModes: TraceMode[] = ['on', 'off', 'on-first-retry', 'retain-on-failure'];
const sharedOptions: [string, string][] = [
['--headed', `Run tests in headed browsers (default: headless)`],
['-c, --config <file>', `Configuration file, or a test directory with optional ${kDefaultConfigFiles.map(file => `"${file}"`).join('/')}`],
['--fully-parallel', `Run all tests in parallel (default: false)`],
['--ignore-snapshots', `Ignore screenshot and snapshot expectations`],
['-j, --workers <workers>', `Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%)`],
['--max-failures <N>', `Stop after the first N failures`],
['--no-deps', 'Do not run project dependencies'],
['--output <dir>', `Folder for output artifacts (default: "test-results")`],
['--quiet', `Suppress stdio`],
['--reporter <reporter>', `Reporter to use, comma-separated, can be ${builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${baseFullConfig.reporter[0]}")`],
['--project <project-name...>', `Only run tests from the specified list of projects (default: run all projects)`],
['--timeout <timeout>', `Specify test timeout threshold in milliseconds, zero for unlimited (default: ${defaultTimeout})`],
['-x', `Stop after the first failure`],
];
const testOnlyOptions: [string, string][] = [
['--browser <browser>', `Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium")`],
['--debug', `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --max-failures=1 --headed --workers=1" options`],
['--forbid-only', `Fail if test.only is called (default: false)`],
['--global-timeout <timeout>', `Maximum time this test suite can run in milliseconds (default: unlimited)`],
['-g, --grep <grep>', `Only run tests matching this regular expression (default: ".*")`],
['-gv, --grep-invert <grep>', `Only run tests that do not match this regular expression`],
['--list', `Collect all the tests and report them, but do not run`],
['--pass-with-no-tests', `Makes test run succeed even if no tests were found`],
['--repeat-each <N>', `Run each test N times (default: 1)`],
['--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`],
['--shard <shard>', `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"`],
['--trace <mode>', `Force tracing mode, can be ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`],
['-u, --update-snapshots', `Update snapshots with actual results (default: only create missing snapshots)`],
];

View File

@ -31,7 +31,7 @@ import type { FullConfigInternal } from '../common/types';
import { loadReporter } from './loadUtils';
import type { BuiltInReporter } from '../common/configLoader';
export async function createReporter(config: FullConfigInternal, mode: 'list' | 'watch' | 'run') {
export async function createReporter(config: FullConfigInternal, mode: 'list' | 'watch' | 'run' | 'ui', additionalReporters: Reporter[] = []): Promise<Multiplexer> {
const defaultReporters: {[key in BuiltInReporter]: new(arg: any) => Reporter} = {
dot: mode === 'list' ? ListModeReporter : DotReporter,
line: mode === 'list' ? ListModeReporter : LineReporter,
@ -40,7 +40,7 @@ export async function createReporter(config: FullConfigInternal, mode: 'list' |
json: JSONReporter,
junit: JUnitReporter,
null: EmptyReporter,
html: HtmlReporter,
html: mode === 'ui' ? LineReporter : HtmlReporter,
};
const reporters: Reporter[] = [];
if (mode === 'watch') {
@ -55,6 +55,7 @@ export async function createReporter(config: FullConfigInternal, mode: 'list' |
reporters.push(new reporterConstructor(arg));
}
}
reporters.push(...additionalReporters);
if (process.env.PW_TEST_REPORTER) {
const reporterConstructor = await loadReporter(config, process.env.PW_TEST_REPORTER);
reporters.push(new reporterConstructor());

View File

@ -20,7 +20,6 @@ import { ManualPromise } from 'playwright-core/lib/utils';
import type { FullResult } from '../../reporter';
import { clearCompilationCache, dependenciesForTestFile } from '../common/compilationCache';
import type { FullConfigInternal } from '../common/types';
import ListReporter from '../reporters/list';
import { Multiplexer } from '../reporters/multiplexer';
import { TeleReporterEmitter } from '../reporters/teleEmitter';
import { createReporter } from './reporters';
@ -111,7 +110,7 @@ class UIMode {
return;
}
if (method === 'open' && params.location) {
open.openApp('code', { arguments: ['--goto', params.location] }).catch(() => {});
open('vscode://file/' + params.location).catch(e => this._originalStderr(String(e)));
return;
}
if (method === 'resizeTerminal') {
@ -163,7 +162,7 @@ class UIMode {
this._config._internal.testIdMatcher = id => !testIdSet || testIdSet.has(id);
const runReporter = new TeleReporterEmitter(e => this._dispatchEvent(e));
const reporter = new Multiplexer([new ListReporter(), runReporter]);
const reporter = await createReporter(this._config, 'ui', [runReporter]);
const taskRunner = createTaskRunnerForWatch(this._config, reporter);
const context: TaskRunnerState = { config: this._config, reporter, phases: [] };
clearCompilationCache();

View File

@ -232,7 +232,7 @@ export const SettingsView: React.FC<{
<ToolbarButton icon='close' title='Close settings' toggled={false} onClick={onClose}></ToolbarButton>
</div>
{[...projects.entries()].map(([projectName, value]) => {
return <div style={{ display: 'flex', alignItems: 'center', lineHeight: '24px' }}>
return <div style={{ display: 'flex', alignItems: 'center', lineHeight: '24px', marginLeft: 5 }}>
<input id={`project-${projectName}`} type='checkbox' checked={value} style={{ cursor: 'pointer' }} onClick={() => {
const copy = new Map(projects);
copy.set(projectName, !copy.get(projectName));