chore: make ReporterV2 a partial interface (#32532)
This makes it easier to write reporters by avoding empty methods.
This commit is contained in:
parent
ec40890fd8
commit
b5d968fa0e
|
|
@ -133,12 +133,12 @@ export class TeleReporterReceiver {
|
|||
public isListing = false;
|
||||
private _rootSuite: TeleSuite;
|
||||
private _options: TeleReporterReceiverOptions;
|
||||
private _reporter: Partial<ReporterV2>;
|
||||
private _reporter: ReporterV2;
|
||||
private _tests = new Map<string, TeleTestCase>();
|
||||
private _rootDir!: string;
|
||||
private _config!: reporterTypes.FullConfig;
|
||||
|
||||
constructor(reporter: Partial<ReporterV2>, options: TeleReporterReceiverOptions = {}) {
|
||||
constructor(reporter: ReporterV2, options: TeleReporterReceiverOptions = {}) {
|
||||
this._rootSuite = new TeleSuite('', 'root');
|
||||
this._options = options;
|
||||
this._reporter = reporter;
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ export class TeleSuiteUpdater {
|
|||
// To work around that, have a dedicated per-run receiver that will only have
|
||||
// suite for a single test run, and hence will have correct total.
|
||||
this._lastRunReceiver = new TeleReporterReceiver({
|
||||
version: () => 'v2',
|
||||
onBegin: (suite: reporterTypes.Suite) => {
|
||||
this._lastRunTestCount = suite.allTests().length;
|
||||
this._lastRunReceiver = undefined;
|
||||
|
|
@ -127,20 +128,13 @@ export class TeleSuiteUpdater {
|
|||
|
||||
onError: (error: reporterTypes.TestError) => this._handleOnError(error),
|
||||
|
||||
printsToStdio: () => {
|
||||
return false;
|
||||
},
|
||||
|
||||
onStdOut: () => { },
|
||||
onStdErr: () => { },
|
||||
onExit: () => { },
|
||||
onStepBegin: () => { },
|
||||
onStepEnd: () => { },
|
||||
printsToStdio: () => false,
|
||||
};
|
||||
}
|
||||
|
||||
processGlobalReport(report: any[]) {
|
||||
const receiver = new TeleReporterReceiver({
|
||||
version: () => 'v2',
|
||||
onConfigure: (c: reporterTypes.FullConfig) => {
|
||||
this.config = c;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -123,9 +123,6 @@ export class BaseReporter implements ReporterV2 {
|
|||
(result as any)[kOutputSymbol].push(output);
|
||||
}
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult): void {
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult) {
|
||||
if (result.status !== 'skipped' && result.status !== test.expectedStatus)
|
||||
++this._failureCount;
|
||||
|
|
@ -146,19 +143,6 @@ export class BaseReporter implements ReporterV2 {
|
|||
this.result = result;
|
||||
}
|
||||
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep): void {
|
||||
}
|
||||
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep): void {
|
||||
}
|
||||
|
||||
async onExit() {
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected fitToScreen(line: string, prefix?: string): string {
|
||||
if (!ttyWidth) {
|
||||
// Guard against the case where we cannot determine available width.
|
||||
|
|
|
|||
|
|
@ -20,10 +20,6 @@ import type { FullResult, TestCase, TestResult, Suite, TestError } from '../../t
|
|||
class DotReporter extends BaseReporter {
|
||||
private _counter = 0;
|
||||
|
||||
override printsToStdio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
super.onBegin(suite);
|
||||
console.log(this.generateStartingMessage());
|
||||
|
|
|
|||
|
|
@ -15,49 +15,15 @@
|
|||
*/
|
||||
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep, Suite } from '../../types/testReporter';
|
||||
|
||||
class EmptyReporter implements ReporterV2 {
|
||||
onConfigure(config: FullConfig) {
|
||||
}
|
||||
|
||||
onBegin(suite: Suite) {
|
||||
}
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult) {
|
||||
}
|
||||
|
||||
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
}
|
||||
|
||||
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult) {
|
||||
}
|
||||
|
||||
async onEnd(result: FullResult) {
|
||||
}
|
||||
|
||||
async onExit() {
|
||||
}
|
||||
|
||||
onError(error: TestError) {
|
||||
}
|
||||
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
}
|
||||
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
}
|
||||
|
||||
export default EmptyReporter;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class GitHubLogger {
|
|||
export class GitHubReporter extends BaseReporter {
|
||||
githubLogger = new GitHubLogger();
|
||||
|
||||
override printsToStdio() {
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import type { ZipFile } from 'playwright-core/lib/zipBundle';
|
|||
import { yazl } from 'playwright-core/lib/zipBundle';
|
||||
import { mime } from 'playwright-core/lib/utilsBundle';
|
||||
import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep } from '@html-reporter/types';
|
||||
import EmptyReporter from './empty';
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
|
||||
type TestEntry = {
|
||||
testCase: TestCase;
|
||||
|
|
@ -55,7 +55,7 @@ type HtmlReporterOptions = {
|
|||
_isTestServer?: boolean;
|
||||
};
|
||||
|
||||
class HtmlReporter extends EmptyReporter {
|
||||
class HtmlReporter implements ReporterV2 {
|
||||
private config!: FullConfig;
|
||||
private suite!: Suite;
|
||||
private _options: HtmlReporterOptions;
|
||||
|
|
@ -68,19 +68,22 @@ class HtmlReporter extends EmptyReporter {
|
|||
private _topLevelErrors: TestError[] = [];
|
||||
|
||||
constructor(options: HtmlReporterOptions) {
|
||||
super();
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
|
||||
override onConfigure(config: FullConfig) {
|
||||
onConfigure(config: FullConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
onBegin(suite: Suite) {
|
||||
const { outputFolder, open, attachmentsBaseURL, host, port } = this._resolveOptions();
|
||||
this._outputFolder = outputFolder;
|
||||
this._open = open;
|
||||
|
|
@ -122,18 +125,18 @@ class HtmlReporter extends EmptyReporter {
|
|||
return !!relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
|
||||
}
|
||||
|
||||
override onError(error: TestError): void {
|
||||
onError(error: TestError): void {
|
||||
this._topLevelErrors.push(error);
|
||||
}
|
||||
|
||||
override async onEnd(result: FullResult) {
|
||||
async onEnd(result: FullResult) {
|
||||
const projectSuites = this.suite.suites;
|
||||
await removeFolders([this._outputFolder]);
|
||||
const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL);
|
||||
this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);
|
||||
}
|
||||
|
||||
override async onExit() {
|
||||
async onExit() {
|
||||
if (process.env.CI || !this._buildResult)
|
||||
return;
|
||||
const { ok, singleTestId } = this._buildResult;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import type { ReporterV2 } from './reporterV2';
|
|||
import { monotonicTime } from 'playwright-core/lib/utils';
|
||||
import { Multiplexer } from './multiplexer';
|
||||
|
||||
export class InternalReporter {
|
||||
export class InternalReporter implements ReporterV2 {
|
||||
private _reporter: ReporterV2;
|
||||
private _didBegin = false;
|
||||
private _config!: FullConfig;
|
||||
|
|
@ -42,29 +42,29 @@ export class InternalReporter {
|
|||
this._config = config;
|
||||
this._startTime = new Date();
|
||||
this._monotonicStartTime = monotonicTime();
|
||||
this._reporter.onConfigure(config);
|
||||
this._reporter.onConfigure?.(config);
|
||||
}
|
||||
|
||||
onBegin(suite: Suite) {
|
||||
this._didBegin = true;
|
||||
this._reporter.onBegin(suite);
|
||||
this._reporter.onBegin?.(suite);
|
||||
}
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult) {
|
||||
this._reporter.onTestBegin(test, result);
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
}
|
||||
|
||||
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
this._reporter.onStdOut(chunk, test, result);
|
||||
this._reporter.onStdOut?.(chunk, test, result);
|
||||
}
|
||||
|
||||
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
this._reporter.onStdErr(chunk, test, result);
|
||||
this._reporter.onStdErr?.(chunk, test, result);
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult) {
|
||||
this._addSnippetToTestErrors(test, result);
|
||||
this._reporter.onTestEnd(test, result);
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
}
|
||||
|
||||
async onEnd(result: { status: FullResult['status'] }) {
|
||||
|
|
@ -72,7 +72,7 @@ export class InternalReporter {
|
|||
// onBegin was not reported, emit it.
|
||||
this.onBegin(new Suite('', 'root'));
|
||||
}
|
||||
return await this._reporter.onEnd({
|
||||
return await this._reporter.onEnd?.({
|
||||
...result,
|
||||
startTime: this._startTime!,
|
||||
duration: monotonicTime() - this._monotonicStartTime!,
|
||||
|
|
@ -80,25 +80,25 @@ export class InternalReporter {
|
|||
}
|
||||
|
||||
async onExit() {
|
||||
await this._reporter.onExit();
|
||||
await this._reporter.onExit?.();
|
||||
}
|
||||
|
||||
onError(error: TestError) {
|
||||
addLocationAndSnippetToError(this._config, error);
|
||||
this._reporter.onError(error);
|
||||
this._reporter.onError?.(error);
|
||||
}
|
||||
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
this._reporter.onStepBegin(test, result, step);
|
||||
this._reporter.onStepBegin?.(test, result, step);
|
||||
}
|
||||
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
this._addSnippetToStepError(test, step);
|
||||
this._reporter.onStepEnd(test, result, step);
|
||||
this._reporter.onStepEnd?.(test, result, step);
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return this._reporter.printsToStdio();
|
||||
return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
|
||||
}
|
||||
|
||||
private _addSnippetToTestErrors(test: TestCase, result: TestResult) {
|
||||
|
|
|
|||
|
|
@ -20,41 +20,44 @@ import type { FullConfig, TestCase, Suite, TestResult, TestError, TestStep, Full
|
|||
import { formatError, prepareErrorStack, resolveOutputFile } from './base';
|
||||
import { MultiMap, toPosixPath } from 'playwright-core/lib/utils';
|
||||
import { getProjectId } from '../common/config';
|
||||
import EmptyReporter from './empty';
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
|
||||
type JSONOptions = {
|
||||
outputFile?: string,
|
||||
configDir: string,
|
||||
};
|
||||
|
||||
class JSONReporter extends EmptyReporter {
|
||||
class JSONReporter implements ReporterV2 {
|
||||
config!: FullConfig;
|
||||
suite!: Suite;
|
||||
private _errors: TestError[] = [];
|
||||
private _resolvedOutputFile: string | undefined;
|
||||
|
||||
constructor(options: JSONOptions) {
|
||||
super();
|
||||
this._resolvedOutputFile = resolveOutputFile('JSON', options)?.outputFile;
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return !this._resolvedOutputFile;
|
||||
}
|
||||
|
||||
override onConfigure(config: FullConfig) {
|
||||
onConfigure(config: FullConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
onBegin(suite: Suite) {
|
||||
this.suite = suite;
|
||||
}
|
||||
|
||||
override onError(error: TestError): void {
|
||||
onError(error: TestError): void {
|
||||
this._errors.push(error);
|
||||
}
|
||||
|
||||
override async onEnd(result: FullResult) {
|
||||
async onEnd(result: FullResult) {
|
||||
await outputReport(this._serializeReport(result), this._resolvedOutputFile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter';
|
||||
import { formatFailure, resolveOutputFile, stripAnsiEscapes } from './base';
|
||||
import EmptyReporter from './empty';
|
||||
import { getAsBooleanFromENV } from 'playwright-core/lib/utils';
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
|
||||
type JUnitOptions = {
|
||||
outputFile?: string,
|
||||
|
|
@ -29,7 +29,7 @@ type JUnitOptions = {
|
|||
configDir: string,
|
||||
};
|
||||
|
||||
class JUnitReporter extends EmptyReporter {
|
||||
class JUnitReporter implements ReporterV2 {
|
||||
private config!: FullConfig;
|
||||
private configDir: string;
|
||||
private suite!: Suite;
|
||||
|
|
@ -42,27 +42,30 @@ class JUnitReporter extends EmptyReporter {
|
|||
private includeProjectInTestName = false;
|
||||
|
||||
constructor(options: JUnitOptions) {
|
||||
super();
|
||||
this.stripANSIControlSequences = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences);
|
||||
this.includeProjectInTestName = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName);
|
||||
this.configDir = options.configDir;
|
||||
this.resolvedOutputFile = resolveOutputFile('JUNIT', options)?.outputFile;
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return !this.resolvedOutputFile;
|
||||
}
|
||||
|
||||
override onConfigure(config: FullConfig) {
|
||||
onConfigure(config: FullConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
onBegin(suite: Suite) {
|
||||
this.suite = suite;
|
||||
this.timestamp = new Date();
|
||||
}
|
||||
|
||||
override async onEnd(result: FullResult) {
|
||||
async onEnd(result: FullResult) {
|
||||
const children: XMLEntry[] = [];
|
||||
for (const projectSuite of this.suite.suites) {
|
||||
for (const fileSuite of projectSuite.suites)
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ class LineReporter extends BaseReporter {
|
|||
private _lastTest: TestCase | undefined;
|
||||
private _didBegin = false;
|
||||
|
||||
override printsToStdio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
super.onBegin(suite);
|
||||
const startingMessage = this.generateStartingMessage();
|
||||
|
|
@ -66,20 +62,17 @@ class LineReporter extends BaseReporter {
|
|||
console.log();
|
||||
}
|
||||
|
||||
override onTestBegin(test: TestCase, result: TestResult) {
|
||||
super.onTestBegin(test, result);
|
||||
onTestBegin(test: TestCase, result: TestResult) {
|
||||
++this._current;
|
||||
this._updateLine(test, result, undefined);
|
||||
}
|
||||
|
||||
override onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
super.onStepBegin(test, result, step);
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
if (step.category === 'test.step')
|
||||
this._updateLine(test, result, step);
|
||||
}
|
||||
|
||||
override onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
super.onStepEnd(test, result, step);
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
if (step.category === 'test.step')
|
||||
this._updateLine(test, result, step.parent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ class ListReporter extends BaseReporter {
|
|||
this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options.printSteps);
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite) {
|
||||
super.onBegin(suite);
|
||||
const startingMessage = this.generateStartingMessage();
|
||||
|
|
@ -52,9 +48,7 @@ class ListReporter extends BaseReporter {
|
|||
}
|
||||
}
|
||||
|
||||
override onTestBegin(test: TestCase, result: TestResult) {
|
||||
super.onTestBegin(test, result);
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult) {
|
||||
const index = String(this._resultIndex.size + 1);
|
||||
this._resultIndex.set(result, index);
|
||||
|
||||
|
|
@ -88,8 +82,7 @@ class ListReporter extends BaseReporter {
|
|||
return stepIndex;
|
||||
}
|
||||
|
||||
override onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
super.onStepBegin(test, result, step);
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
if (step.category !== 'test.step')
|
||||
return;
|
||||
const testIndex = this._resultIndex.get(result) || '';
|
||||
|
|
@ -108,8 +101,7 @@ class ListReporter extends BaseReporter {
|
|||
}
|
||||
}
|
||||
|
||||
override onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
super.onStepEnd(test, result, step);
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
if (step.category !== 'test.step')
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class MarkdownReporter extends BaseReporter {
|
|||
this._options = options;
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,37 +31,37 @@ export class Multiplexer implements ReporterV2 {
|
|||
|
||||
onConfigure(config: FullConfig) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onConfigure(config));
|
||||
wrap(() => reporter.onConfigure?.(config));
|
||||
}
|
||||
|
||||
onBegin(suite: Suite) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onBegin(suite));
|
||||
wrap(() => reporter.onBegin?.(suite));
|
||||
}
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onTestBegin(test, result));
|
||||
wrap(() => reporter.onTestBegin?.(test, result));
|
||||
}
|
||||
|
||||
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStdOut(chunk, test, result));
|
||||
wrap(() => reporter.onStdOut?.(chunk, test, result));
|
||||
}
|
||||
|
||||
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStdErr(chunk, test, result));
|
||||
wrap(() => reporter.onStdErr?.(chunk, test, result));
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onTestEnd(test, result));
|
||||
wrap(() => reporter.onTestEnd?.(test, result));
|
||||
}
|
||||
|
||||
async onEnd(result: FullResult) {
|
||||
for (const reporter of this._reporters) {
|
||||
const outResult = await wrapAsync(() => reporter.onEnd(result));
|
||||
const outResult = await wrapAsync(() => reporter.onEnd?.(result));
|
||||
if (outResult?.status)
|
||||
result.status = outResult.status;
|
||||
}
|
||||
|
|
@ -70,28 +70,28 @@ export class Multiplexer implements ReporterV2 {
|
|||
|
||||
async onExit() {
|
||||
for (const reporter of this._reporters)
|
||||
await wrapAsync(() => reporter.onExit());
|
||||
await wrapAsync(() => reporter.onExit?.());
|
||||
}
|
||||
|
||||
onError(error: TestError) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onError(error));
|
||||
wrap(() => reporter.onError?.(error));
|
||||
}
|
||||
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStepBegin(test, result, step));
|
||||
wrap(() => reporter.onStepBegin?.(test, result, step));
|
||||
}
|
||||
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
||||
for (const reporter of this._reporters)
|
||||
wrap(() => reporter.onStepEnd(test, result, step));
|
||||
wrap(() => reporter.onStepEnd?.(test, result, step));
|
||||
}
|
||||
|
||||
printsToStdio(): boolean {
|
||||
return this._reporters.some(r => {
|
||||
let prints = true;
|
||||
wrap(() => prints = r.printsToStdio());
|
||||
let prints = false;
|
||||
wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true);
|
||||
return prints;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,18 @@
|
|||
import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep, Reporter, Suite } from '../../types/testReporter';
|
||||
|
||||
export interface ReporterV2 {
|
||||
onConfigure(config: FullConfig): void;
|
||||
onBegin(suite: Suite): void;
|
||||
onTestBegin(test: TestCase, result: TestResult): void;
|
||||
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
||||
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
||||
onTestEnd(test: TestCase, result: TestResult): void;
|
||||
onEnd(result: FullResult): Promise<{ status?: FullResult['status'] } | undefined | void> | void;
|
||||
onExit(): void | Promise<void>;
|
||||
onError(error: TestError): void;
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
|
||||
printsToStdio(): boolean;
|
||||
onConfigure?(config: FullConfig): void;
|
||||
onBegin?(suite: Suite): void;
|
||||
onTestBegin?(test: TestCase, result: TestResult): void;
|
||||
onStdOut?(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
||||
onStdErr?(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
||||
onTestEnd?(test: TestCase, result: TestResult): void;
|
||||
onEnd?(result: FullResult): Promise<{ status?: FullResult['status'] } | undefined | void> | void;
|
||||
onExit?(): void | Promise<void>;
|
||||
onError?(error: TestError): void;
|
||||
onStepBegin?(test: TestCase, result: TestResult, step: TestStep): void;
|
||||
onStepEnd?(test: TestCase, result: TestResult, step: TestStep): void;
|
||||
printsToStdio?(): boolean;
|
||||
version(): 'v2';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,9 +145,6 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
async onExit() {
|
||||
}
|
||||
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,17 +198,17 @@ export class Dispatcher {
|
|||
worker.on('stdOut', (params: TestOutputPayload) => {
|
||||
const { chunk, test, result } = handleOutput(params);
|
||||
result?.stdout.push(chunk);
|
||||
this._reporter.onStdOut(chunk, test, result);
|
||||
this._reporter.onStdOut?.(chunk, test, result);
|
||||
});
|
||||
worker.on('stdErr', (params: TestOutputPayload) => {
|
||||
const { chunk, test, result } = handleOutput(params);
|
||||
result?.stderr.push(chunk);
|
||||
this._reporter.onStdErr(chunk, test, result);
|
||||
this._reporter.onStdErr?.(chunk, test, result);
|
||||
});
|
||||
worker.on('teardownErrors', (params: TeardownErrorsPayload) => {
|
||||
this._failureTracker.onWorkerError();
|
||||
for (const error of params.fatalErrors)
|
||||
this._reporter.onError(error);
|
||||
this._reporter.onError?.(error);
|
||||
});
|
||||
worker.on('exit', () => {
|
||||
const producedEnv = this._producedEnvByProjectId.get(testGroup.projectId) || {};
|
||||
|
|
@ -257,7 +257,7 @@ class JobDispatcher {
|
|||
result.parallelIndex = this._parallelIndex;
|
||||
result.workerIndex = this._workerIndex;
|
||||
result.startTime = new Date(params.startWallTime);
|
||||
this._reporter.onTestBegin(test, result);
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
this._currentlyRunning = { test, result };
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ class JobDispatcher {
|
|||
};
|
||||
steps.set(params.stepId, step);
|
||||
(parentStep || result).steps.push(step);
|
||||
this._reporter.onStepBegin(test, result, step);
|
||||
this._reporter.onStepBegin?.(test, result, step);
|
||||
}
|
||||
|
||||
private _onStepEnd(params: StepEndPayload) {
|
||||
|
|
@ -335,14 +335,14 @@ class JobDispatcher {
|
|||
const { result, steps, test } = data;
|
||||
const step = steps.get(params.stepId);
|
||||
if (!step) {
|
||||
this._reporter.onStdErr('Internal error: step end without step begin: ' + params.stepId, test, result);
|
||||
this._reporter.onStdErr?.('Internal error: step end without step begin: ' + params.stepId, test, result);
|
||||
return;
|
||||
}
|
||||
step.duration = params.wallTime - step.startTime.getTime();
|
||||
if (params.error)
|
||||
step.error = params.error;
|
||||
steps.delete(params.stepId);
|
||||
this._reporter.onStepEnd(test, result, step);
|
||||
this._reporter.onStepEnd?.(test, result, step);
|
||||
}
|
||||
|
||||
private _onAttach(params: AttachmentPayload) {
|
||||
|
|
@ -368,7 +368,7 @@ class JobDispatcher {
|
|||
result = runData.result;
|
||||
} else {
|
||||
result = test._appendTestResult();
|
||||
this._reporter.onTestBegin(test, result);
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
}
|
||||
result.errors = [...errors];
|
||||
result.error = result.errors[0];
|
||||
|
|
@ -392,7 +392,7 @@ class JobDispatcher {
|
|||
// Let's just fail the test run.
|
||||
this._failureTracker.onWorkerError();
|
||||
for (const error of errors)
|
||||
this._reporter.onError(error);
|
||||
this._reporter.onError?.(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +526,7 @@ class JobDispatcher {
|
|||
if (allTestsSkipped && !this._failureTracker.hasReachedMaxFailures()) {
|
||||
for (const test of this._job.tests) {
|
||||
const result = test._appendTestResult();
|
||||
this._reporter.onTestBegin(test, result);
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
result.status = 'skipped';
|
||||
this._reportTestEnd(test, result);
|
||||
}
|
||||
|
|
@ -540,13 +540,13 @@ class JobDispatcher {
|
|||
}
|
||||
|
||||
private _reportTestEnd(test: TestCase, result: TestResult) {
|
||||
this._reporter.onTestEnd(test, result);
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
const hadMaxFailures = this._failureTracker.hasReachedMaxFailures();
|
||||
this._failureTracker.onTestEnd(test, result);
|
||||
if (this._failureTracker.hasReachedMaxFailures()) {
|
||||
this._stopCallback();
|
||||
if (!hadMaxFailures)
|
||||
this._reporter.onError({ message: colors.red(`Testing stopped early after ${this._failureTracker.maxFailures()} maximum allowed failures.`) });
|
||||
this._reporter.onError?.({ message: colors.red(`Testing stopped early after ${this._failureTracker.maxFailures()} maximum allowed failures.`) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export async function createReporters(config: FullConfigInternal, mode: 'list' |
|
|||
reporters.push(wrapReporterAsV2(new reporterConstructor(runOptions)));
|
||||
}
|
||||
|
||||
const someReporterPrintsToStdio = reporters.some(r => r.printsToStdio());
|
||||
const someReporterPrintsToStdio = reporters.some(r => r.printsToStdio ? r.printsToStdio() : true);
|
||||
if (reporters.length && !someReporterPrintsToStdio) {
|
||||
// Add a line/dot/list-mode reporter for convenience.
|
||||
// Important to put it first, just in case some other reporter stalls onEnd.
|
||||
|
|
@ -92,16 +92,15 @@ interface ErrorCollectingReporter extends ReporterV2 {
|
|||
|
||||
export function createErrorCollectingReporter(writeToConsole?: boolean): ErrorCollectingReporter {
|
||||
const errors: TestError[] = [];
|
||||
const reporterV2 = wrapReporterAsV2({
|
||||
return {
|
||||
version: () => 'v2',
|
||||
onError(error: TestError) {
|
||||
errors.push(error);
|
||||
if (writeToConsole)
|
||||
process.stdout.write(formatError(error, colors.enabled).message + '\n');
|
||||
}
|
||||
});
|
||||
const reporter = reporterV2 as ErrorCollectingReporter;
|
||||
reporter.errors = () => errors;
|
||||
return reporter;
|
||||
},
|
||||
errors: () => errors,
|
||||
};
|
||||
}
|
||||
|
||||
function reporterOptions(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean) {
|
||||
|
|
@ -132,14 +131,18 @@ function computeCommandHash(config: FullConfigInternal) {
|
|||
return parts.join('-');
|
||||
}
|
||||
|
||||
class ListModeReporter extends EmptyReporter {
|
||||
class ListModeReporter implements ReporterV2 {
|
||||
private config!: FullConfig;
|
||||
|
||||
override onConfigure(config: FullConfig) {
|
||||
version(): 'v2' {
|
||||
return 'v2';
|
||||
}
|
||||
|
||||
onConfigure(config: FullConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
override onBegin(suite: Suite): void {
|
||||
onBegin(suite: Suite): void {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Listing tests:`);
|
||||
const tests = suite.allTests();
|
||||
|
|
@ -157,12 +160,8 @@ class ListModeReporter extends EmptyReporter {
|
|||
console.log(`Total: ${tests.length} ${tests.length === 1 ? 'test' : 'tests'} in ${files.size} ${files.size === 1 ? 'file' : 'files'}`);
|
||||
}
|
||||
|
||||
override onError(error: TestError) {
|
||||
onError(error: TestError) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('\n' + formatError(error, false).message);
|
||||
}
|
||||
|
||||
override printsToStdio(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ export function createTaskRunnerForClearCache(config: FullConfigInternal, report
|
|||
function createReportBeginTask(): Task<TestRun> {
|
||||
return {
|
||||
setup: async (reporter, { rootSuite }) => {
|
||||
reporter.onBegin(rootSuite!);
|
||||
reporter.onBegin?.(rootSuite!);
|
||||
},
|
||||
teardown: async ({}) => {},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export const TraceView: React.FC<{
|
|||
if (pollTimer.current)
|
||||
clearTimeout(pollTimer.current);
|
||||
};
|
||||
}, [outputDir, item, setModel, counter, setCounter]);
|
||||
}, [outputDir, item, setModel, counter, setCounter, pathSeparator]);
|
||||
|
||||
return <Workbench
|
||||
key='workbench'
|
||||
|
|
|
|||
Loading…
Reference in a new issue