2023-01-26 22:20:05 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
|
*
|
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
*
|
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import path from 'path';
|
|
|
|
|
|
import type { Reporter, TestError } from '../../types/testReporter';
|
2023-02-07 18:48:46 +01:00
|
|
|
|
import { separator, formatError } from '../reporters/base';
|
2023-01-26 22:20:05 +01:00
|
|
|
|
import DotReporter from '../reporters/dot';
|
|
|
|
|
|
import EmptyReporter from '../reporters/empty';
|
|
|
|
|
|
import GitHubReporter from '../reporters/github';
|
|
|
|
|
|
import HtmlReporter from '../reporters/html';
|
|
|
|
|
|
import JSONReporter from '../reporters/json';
|
|
|
|
|
|
import JUnitReporter from '../reporters/junit';
|
|
|
|
|
|
import LineReporter from '../reporters/line';
|
|
|
|
|
|
import ListReporter from '../reporters/list';
|
|
|
|
|
|
import { Multiplexer } from '../reporters/multiplexer';
|
2023-01-27 02:26:47 +01:00
|
|
|
|
import type { Suite } from '../common/test';
|
2023-01-27 21:44:15 +01:00
|
|
|
|
import type { FullConfigInternal } from '../common/types';
|
|
|
|
|
|
import { loadReporter } from './loadUtils';
|
|
|
|
|
|
import type { BuiltInReporter } from '../common/configLoader';
|
2023-02-07 18:48:46 +01:00
|
|
|
|
import { colors } from 'playwright-core/lib/utilsBundle';
|
2023-01-26 22:20:05 +01:00
|
|
|
|
|
2023-02-07 00:52:14 +01:00
|
|
|
|
export async function createReporter(config: FullConfigInternal, mode: 'list' | 'watch' | 'run') {
|
2023-01-26 22:20:05 +01:00
|
|
|
|
const defaultReporters: {[key in BuiltInReporter]: new(arg: any) => Reporter} = {
|
2023-02-07 00:52:14 +01:00
|
|
|
|
dot: mode === 'list' ? ListModeReporter : DotReporter,
|
|
|
|
|
|
line: mode === 'list' ? ListModeReporter : LineReporter,
|
|
|
|
|
|
list: mode === 'list' ? ListModeReporter : ListReporter,
|
2023-01-26 22:20:05 +01:00
|
|
|
|
github: GitHubReporter,
|
|
|
|
|
|
json: JSONReporter,
|
|
|
|
|
|
junit: JUnitReporter,
|
|
|
|
|
|
null: EmptyReporter,
|
|
|
|
|
|
html: HtmlReporter,
|
|
|
|
|
|
};
|
|
|
|
|
|
const reporters: Reporter[] = [];
|
2023-02-07 00:52:14 +01:00
|
|
|
|
if (mode === 'watch') {
|
|
|
|
|
|
reporters.push(new WatchModeReporter());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for (const r of config.reporter) {
|
|
|
|
|
|
const [name, arg] = r;
|
|
|
|
|
|
if (name in defaultReporters) {
|
|
|
|
|
|
reporters.push(new defaultReporters[name as keyof typeof defaultReporters](arg));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const reporterConstructor = await loadReporter(config, name);
|
|
|
|
|
|
reporters.push(new reporterConstructor(arg));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (process.env.PW_TEST_REPORTER) {
|
|
|
|
|
|
const reporterConstructor = await loadReporter(config, process.env.PW_TEST_REPORTER);
|
|
|
|
|
|
reporters.push(new reporterConstructor());
|
2023-01-26 22:20:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const someReporterPrintsToStdio = reporters.some(r => {
|
|
|
|
|
|
const prints = r.printsToStdio ? r.printsToStdio() : true;
|
|
|
|
|
|
return prints;
|
|
|
|
|
|
});
|
|
|
|
|
|
if (reporters.length && !someReporterPrintsToStdio) {
|
|
|
|
|
|
// Add a line/dot/list-mode reporter for convenience.
|
|
|
|
|
|
// Important to put it first, jsut in case some other reporter stalls onEnd.
|
2023-02-07 00:52:14 +01:00
|
|
|
|
if (mode === 'list')
|
2023-01-26 22:20:05 +01:00
|
|
|
|
reporters.unshift(new ListModeReporter());
|
|
|
|
|
|
else
|
|
|
|
|
|
reporters.unshift(!process.env.CI ? new LineReporter({ omitFailures: true }) : new DotReporter());
|
|
|
|
|
|
}
|
|
|
|
|
|
return new Multiplexer(reporters);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export class ListModeReporter implements Reporter {
|
|
|
|
|
|
private config!: FullConfigInternal;
|
|
|
|
|
|
|
|
|
|
|
|
onBegin(config: FullConfigInternal, suite: Suite): void {
|
|
|
|
|
|
this.config = config;
|
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
|
console.log(`Listing tests:`);
|
|
|
|
|
|
const tests = suite.allTests();
|
|
|
|
|
|
const files = new Set<string>();
|
|
|
|
|
|
for (const test of tests) {
|
|
|
|
|
|
// root, project, file, ...describes, test
|
|
|
|
|
|
const [, projectName, , ...titles] = test.titlePath();
|
|
|
|
|
|
const location = `${path.relative(config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;
|
|
|
|
|
|
const projectTitle = projectName ? `[${projectName}] › ` : '';
|
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
|
console.log(` ${projectTitle}${location} › ${titles.join(' ')}`);
|
|
|
|
|
|
files.add(test.location.file);
|
|
|
|
|
|
}
|
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
|
console.log(`Total: ${tests.length} ${tests.length === 1 ? 'test' : 'tests'} in ${files.size} ${files.size === 1 ? 'file' : 'files'}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onError(error: TestError) {
|
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
|
console.error('\n' + formatError(this.config, error, false).message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-02-07 00:52:14 +01:00
|
|
|
|
|
2023-02-07 18:48:46 +01:00
|
|
|
|
let seq = 0;
|
|
|
|
|
|
|
|
|
|
|
|
export class WatchModeReporter extends ListReporter {
|
2023-02-08 17:36:02 +01:00
|
|
|
|
private _options: { isShowBrowser?: () => boolean; } | undefined;
|
|
|
|
|
|
constructor(options?: {
|
|
|
|
|
|
isShowBrowser?: () => boolean,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
super();
|
|
|
|
|
|
this._options = options;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-02-07 18:48:46 +01:00
|
|
|
|
override generateStartingMessage(): string {
|
|
|
|
|
|
const tokens: string[] = [];
|
|
|
|
|
|
tokens.push('npx playwright test');
|
|
|
|
|
|
tokens.push(...(this.config._internal.cliProjectFilter || [])?.map(p => colors.blue(`--project ${p}`)));
|
|
|
|
|
|
if (this.config._internal.cliGrep)
|
|
|
|
|
|
tokens.push(colors.red(`--grep ${this.config._internal.cliGrep}`));
|
|
|
|
|
|
if (this.config._internal.cliArgs)
|
|
|
|
|
|
tokens.push(...this.config._internal.cliArgs.map(a => colors.bold(a)));
|
|
|
|
|
|
tokens.push(colors.dim(`#${++seq}`));
|
|
|
|
|
|
const lines: string[] = [];
|
|
|
|
|
|
const sep = separator();
|
|
|
|
|
|
lines.push('\x1Bc' + sep);
|
2023-02-08 00:56:39 +01:00
|
|
|
|
lines.push(`${tokens.join(' ')}` + super.generateStartingMessage());
|
2023-02-08 17:36:02 +01:00
|
|
|
|
lines.push(`${colors.dim('Show & reuse browser:')} ${colors.bold(this._options?.isShowBrowser?.() ? 'on' : 'off')}${colors.dim(', press')} ${colors.bold('s')} ${colors.dim('to toggle.')}`);
|
2023-02-07 18:48:46 +01:00
|
|
|
|
return lines.join('\n');
|
|
|
|
|
|
}
|
2023-02-07 00:52:14 +01:00
|
|
|
|
}
|