feat(test-runner): rename Test to TestCase (#7725)
This commit is contained in:
parent
56ada374df
commit
2ac0c59156
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
import { Reporter, Test } from '@playwright/test/reporter';
|
import { Reporter, TestCase } from '@playwright/test/reporter';
|
||||||
|
|
||||||
test.use({ locale: 'en-US' });
|
test.use({ locale: 'en-US' });
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ test2('should work 2', async ({ foo, bar }) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export class MyReporter implements Reporter {
|
export class MyReporter implements Reporter {
|
||||||
onTestBegin(test: Test) {
|
onTestBegin(test: TestCase) {
|
||||||
test.titlePath().slice();
|
test.titlePath().slice();
|
||||||
if (test.results[0].status === test.expectedStatus)
|
if (test.results[0].status === test.expectedStatus)
|
||||||
console.log(`Nice test ${test.title} at ${test.location.file}`);
|
console.log(`Nice test ${test.title} at ${test.location.file}`);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import path from 'path';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { RunPayload, TestBeginPayload, TestEndPayload, DonePayload, TestOutputPayload, WorkerInitParams } from './ipc';
|
import { RunPayload, TestBeginPayload, TestEndPayload, DonePayload, TestOutputPayload, WorkerInitParams } from './ipc';
|
||||||
import type { TestResult, Reporter, TestStatus } from '../../types/testReporter';
|
import type { TestResult, Reporter, TestStatus } from '../../types/testReporter';
|
||||||
import { Suite, Test } from './test';
|
import { Suite, TestCase } from './test';
|
||||||
import { Loader } from './loader';
|
import { Loader } from './loader';
|
||||||
|
|
||||||
type DispatcherEntry = {
|
type DispatcherEntry = {
|
||||||
|
|
@ -34,7 +34,7 @@ export class Dispatcher {
|
||||||
private _freeWorkers: Worker[] = [];
|
private _freeWorkers: Worker[] = [];
|
||||||
private _workerClaimers: (() => void)[] = [];
|
private _workerClaimers: (() => void)[] = [];
|
||||||
|
|
||||||
private _testById = new Map<string, { test: Test, result: TestResult }>();
|
private _testById = new Map<string, { test: TestCase, result: TestResult }>();
|
||||||
private _queue: DispatcherEntry[] = [];
|
private _queue: DispatcherEntry[] = [];
|
||||||
private _stopCallback = () => {};
|
private _stopCallback = () => {};
|
||||||
readonly _loader: Loader;
|
readonly _loader: Loader;
|
||||||
|
|
@ -321,7 +321,7 @@ export class Dispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _reportTestBegin(test: Test) {
|
private _reportTestBegin(test: TestCase) {
|
||||||
if (this._isStopped)
|
if (this._isStopped)
|
||||||
return;
|
return;
|
||||||
const maxFailures = this._loader.fullConfig().maxFailures;
|
const maxFailures = this._loader.fullConfig().maxFailures;
|
||||||
|
|
@ -329,7 +329,7 @@ export class Dispatcher {
|
||||||
this._reporter.onTestBegin?.(test);
|
this._reporter.onTestBegin?.(test);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _reportTestEnd(test: Test, result: TestResult, status: TestStatus) {
|
private _reportTestEnd(test: TestCase, result: TestResult, status: TestStatus) {
|
||||||
if (this._isStopped)
|
if (this._isStopped)
|
||||||
return;
|
return;
|
||||||
result.status = status;
|
result.status = status;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { TestType, FullProject, Fixtures, FixturesWithLocation } from './types';
|
import type { TestType, FullProject, Fixtures, FixturesWithLocation } from './types';
|
||||||
import { Suite, Test } from './test';
|
import { Suite, TestCase } from './test';
|
||||||
import { FixturePool } from './fixtures';
|
import { FixturePool } from './fixtures';
|
||||||
import { DeclaredFixtures, TestTypeImpl } from './testType';
|
import { DeclaredFixtures, TestTypeImpl } from './testType';
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ export class ProjectImpl {
|
||||||
private index: number;
|
private index: number;
|
||||||
private defines = new Map<TestType<any, any>, Fixtures>();
|
private defines = new Map<TestType<any, any>, Fixtures>();
|
||||||
private testTypePools = new Map<TestTypeImpl, FixturePool>();
|
private testTypePools = new Map<TestTypeImpl, FixturePool>();
|
||||||
private testPools = new Map<Test, FixturePool>();
|
private testPools = new Map<TestCase, FixturePool>();
|
||||||
|
|
||||||
constructor(project: FullProject, index: number) {
|
constructor(project: FullProject, index: number) {
|
||||||
this.config = project;
|
this.config = project;
|
||||||
|
|
@ -53,7 +53,7 @@ export class ProjectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we can optimize this function by building the pool inline in cloneSuite
|
// TODO: we can optimize this function by building the pool inline in cloneSuite
|
||||||
private buildPool(test: Test): FixturePool {
|
private buildPool(test: TestCase): FixturePool {
|
||||||
if (!this.testPools.has(test)) {
|
if (!this.testPools.has(test)) {
|
||||||
let pool = this.buildTestTypePool(test._testType);
|
let pool = this.buildTestTypePool(test._testType);
|
||||||
const overrides: Fixtures = test.parent!._buildFixtureOverrides();
|
const overrides: Fixtures = test.parent!._buildFixtureOverrides();
|
||||||
|
|
@ -78,7 +78,7 @@ export class ProjectImpl {
|
||||||
return this.testPools.get(test)!;
|
return this.testPools.get(test)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _cloneEntries(from: Suite, to: Suite, repeatEachIndex: number, filter: (test: Test) => boolean): boolean {
|
private _cloneEntries(from: Suite, to: Suite, repeatEachIndex: number, filter: (test: TestCase) => boolean): boolean {
|
||||||
for (const entry of from._entries) {
|
for (const entry of from._entries) {
|
||||||
if (entry instanceof Suite) {
|
if (entry instanceof Suite) {
|
||||||
const suite = entry._clone();
|
const suite = entry._clone();
|
||||||
|
|
@ -107,7 +107,7 @@ export class ProjectImpl {
|
||||||
return to._entries.length > 0;
|
return to._entries.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cloneFileSuite(suite: Suite, repeatEachIndex: number, filter: (test: Test) => boolean): Suite | undefined {
|
cloneFileSuite(suite: Suite, repeatEachIndex: number, filter: (test: TestCase) => boolean): Suite | undefined {
|
||||||
const result = suite._clone();
|
const result = suite._clone();
|
||||||
return this._cloneEntries(suite, result, repeatEachIndex, filter) ? result : undefined;
|
return this._cloneEntries(suite, result, repeatEachIndex, filter) ? result : undefined;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import fs from 'fs';
|
||||||
import milliseconds from 'ms';
|
import milliseconds from 'ms';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import StackUtils from 'stack-utils';
|
import StackUtils from 'stack-utils';
|
||||||
import { FullConfig, TestStatus, Test, Suite, TestResult, TestError, Reporter, FullResult } from '../../../types/testReporter';
|
import { FullConfig, TestStatus, TestCase, Suite, TestResult, TestError, Reporter, FullResult } from '../../../types/testReporter';
|
||||||
|
|
||||||
const stackUtils = new StackUtils();
|
const stackUtils = new StackUtils();
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ export class BaseReporter implements Reporter {
|
||||||
process.stderr.write(chunk);
|
process.stderr.write(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestEnd(test: Test, result: TestResult) {
|
onTestEnd(test: TestCase, result: TestResult) {
|
||||||
const projectName = test.titlePath()[1];
|
const projectName = test.titlePath()[1];
|
||||||
const relativePath = relativeTestPath(this.config, test);
|
const relativePath = relativeTestPath(this.config, test);
|
||||||
const fileAndProject = (projectName ? `[${projectName}] › ` : '') + relativePath;
|
const fileAndProject = (projectName ? `[${projectName}] › ` : '') + relativePath;
|
||||||
|
|
@ -83,8 +83,8 @@ export class BaseReporter implements Reporter {
|
||||||
epilogue(full: boolean) {
|
epilogue(full: boolean) {
|
||||||
let skipped = 0;
|
let skipped = 0;
|
||||||
let expected = 0;
|
let expected = 0;
|
||||||
const unexpected: Test[] = [];
|
const unexpected: TestCase[] = [];
|
||||||
const flaky: Test[] = [];
|
const flaky: TestCase[] = [];
|
||||||
|
|
||||||
this.suite.allTests().forEach(test => {
|
this.suite.allTests().forEach(test => {
|
||||||
switch (test.outcome()) {
|
switch (test.outcome()) {
|
||||||
|
|
@ -119,28 +119,28 @@ export class BaseReporter implements Reporter {
|
||||||
console.log(colors.red(` Timed out waiting ${this.config.globalTimeout / 1000}s for the entire test run`));
|
console.log(colors.red(` Timed out waiting ${this.config.globalTimeout / 1000}s for the entire test run`));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _printTestHeaders(tests: Test[]) {
|
private _printTestHeaders(tests: TestCase[]) {
|
||||||
tests.forEach(test => {
|
tests.forEach(test => {
|
||||||
console.log(formatTestHeader(this.config, test, ' '));
|
console.log(formatTestHeader(this.config, test, ' '));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _printFailures(failures: Test[]) {
|
private _printFailures(failures: TestCase[]) {
|
||||||
failures.forEach((test, index) => {
|
failures.forEach((test, index) => {
|
||||||
console.log(formatFailure(this.config, test, index + 1));
|
console.log(formatFailure(this.config, test, index + 1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hasResultWithStatus(test: Test, status: TestStatus): boolean {
|
hasResultWithStatus(test: TestCase, status: TestStatus): boolean {
|
||||||
return !!test.results.find(r => r.status === status);
|
return !!test.results.find(r => r.status === status);
|
||||||
}
|
}
|
||||||
|
|
||||||
willRetry(test: Test, result: TestResult): boolean {
|
willRetry(test: TestCase, result: TestResult): boolean {
|
||||||
return result.status !== 'passed' && result.status !== test.expectedStatus && test.results.length <= test.retries;
|
return result.status !== 'passed' && result.status !== test.expectedStatus && test.results.length <= test.retries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatFailure(config: FullConfig, test: Test, index?: number): string {
|
export function formatFailure(config: FullConfig, test: TestCase, index?: number): string {
|
||||||
const tokens: string[] = [];
|
const tokens: string[] = [];
|
||||||
tokens.push(formatTestHeader(config, test, ' ', index));
|
tokens.push(formatTestHeader(config, test, ' ', index));
|
||||||
for (const result of test.results) {
|
for (const result of test.results) {
|
||||||
|
|
@ -152,11 +152,11 @@ export function formatFailure(config: FullConfig, test: Test, index?: number): s
|
||||||
return tokens.join('\n');
|
return tokens.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function relativeTestPath(config: FullConfig, test: Test): string {
|
function relativeTestPath(config: FullConfig, test: TestCase): string {
|
||||||
return path.relative(config.rootDir, test.location.file) || path.basename(test.location.file);
|
return path.relative(config.rootDir, test.location.file) || path.basename(test.location.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatTestTitle(config: FullConfig, test: Test): string {
|
export function formatTestTitle(config: FullConfig, test: TestCase): string {
|
||||||
// root, project, file, ...describes, test
|
// root, project, file, ...describes, test
|
||||||
const [, projectName, , ...titles] = test.titlePath();
|
const [, projectName, , ...titles] = test.titlePath();
|
||||||
const location = `${relativeTestPath(config, test)}:${test.location.line}:${test.location.column}`;
|
const location = `${relativeTestPath(config, test)}:${test.location.line}:${test.location.column}`;
|
||||||
|
|
@ -164,14 +164,14 @@ export function formatTestTitle(config: FullConfig, test: Test): string {
|
||||||
return `${projectTitle}${location} › ${titles.join(' ')}`;
|
return `${projectTitle}${location} › ${titles.join(' ')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTestHeader(config: FullConfig, test: Test, indent: string, index?: number): string {
|
function formatTestHeader(config: FullConfig, test: TestCase, indent: string, index?: number): string {
|
||||||
const title = formatTestTitle(config, test);
|
const title = formatTestTitle(config, test);
|
||||||
const passedUnexpectedlySuffix = test.results[0].status === 'passed' ? ' -- passed unexpectedly' : '';
|
const passedUnexpectedlySuffix = test.results[0].status === 'passed' ? ' -- passed unexpectedly' : '';
|
||||||
const header = `${indent}${index ? index + ') ' : ''}${title}${passedUnexpectedlySuffix}`;
|
const header = `${indent}${index ? index + ') ' : ''}${title}${passedUnexpectedlySuffix}`;
|
||||||
return colors.red(pad(header, '='));
|
return colors.red(pad(header, '='));
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFailedResult(test: Test, result: TestResult): string {
|
function formatFailedResult(test: TestCase, result: TestResult): string {
|
||||||
const tokens: string[] = [];
|
const tokens: string[] = [];
|
||||||
if (result.retry)
|
if (result.retry)
|
||||||
tokens.push(colors.gray(pad(`\n Retry #${result.retry}`, '-')));
|
tokens.push(colors.gray(pad(`\n Retry #${result.retry}`, '-')));
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@
|
||||||
|
|
||||||
import colors from 'colors/safe';
|
import colors from 'colors/safe';
|
||||||
import { BaseReporter } from './base';
|
import { BaseReporter } from './base';
|
||||||
import { FullResult, Test, TestResult } from '../../../types/testReporter';
|
import { FullResult, TestCase, TestResult } from '../../../types/testReporter';
|
||||||
|
|
||||||
class DotReporter extends BaseReporter {
|
class DotReporter extends BaseReporter {
|
||||||
private _counter = 0;
|
private _counter = 0;
|
||||||
|
|
||||||
onTestEnd(test: Test, result: TestResult) {
|
onTestEnd(test: TestCase, result: TestResult) {
|
||||||
super.onTestEnd(test, result);
|
super.onTestEnd(test, result);
|
||||||
if (++this._counter === 81) {
|
if (++this._counter === 81) {
|
||||||
process.stdout.write('\n');
|
process.stdout.write('\n');
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { FullConfig, Test, Suite, TestResult, TestError, FullResult, TestStatus, Location, Reporter } from '../../../types/testReporter';
|
import { FullConfig, TestCase, Suite, TestResult, TestError, FullResult, TestStatus, Location, Reporter } from '../../../types/testReporter';
|
||||||
|
|
||||||
export interface JSONReport {
|
export interface JSONReport {
|
||||||
config: Omit<FullConfig, 'projects'> & {
|
config: Omit<FullConfig, 'projects'> & {
|
||||||
|
|
@ -192,7 +192,7 @@ class JSONReporter implements Reporter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeTestSpec(test: Test): JSONReportSpec {
|
private _serializeTestSpec(test: TestCase): JSONReportSpec {
|
||||||
return {
|
return {
|
||||||
title: test.title,
|
title: test.title,
|
||||||
ok: test.ok(),
|
ok: test.ok(),
|
||||||
|
|
@ -201,7 +201,7 @@ class JSONReporter implements Reporter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeTest(test: Test): JSONReportTest {
|
private _serializeTest(test: TestCase): JSONReportTest {
|
||||||
return {
|
return {
|
||||||
timeout: test.timeout,
|
timeout: test.timeout,
|
||||||
annotations: test.annotations,
|
annotations: test.annotations,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { FullConfig, FullResult, Reporter, Suite, Test } from '../../../types/testReporter';
|
import { FullConfig, FullResult, Reporter, Suite, TestCase } from '../../../types/testReporter';
|
||||||
import { monotonicTime } from '../util';
|
import { monotonicTime } from '../util';
|
||||||
import { formatFailure, formatTestTitle, stripAscii } from './base';
|
import { formatFailure, formatTestTitle, stripAscii } from './base';
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ class JUnitReporter implements Reporter {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addTestCase(test: Test, entries: XMLEntry[]) {
|
private _addTestCase(test: TestCase, entries: XMLEntry[]) {
|
||||||
const entry = {
|
const entry = {
|
||||||
name: 'testcase',
|
name: 'testcase',
|
||||||
attributes: {
|
attributes: {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
import colors from 'colors/safe';
|
import colors from 'colors/safe';
|
||||||
import { BaseReporter, formatFailure, formatTestTitle } from './base';
|
import { BaseReporter, formatFailure, formatTestTitle } from './base';
|
||||||
import { FullConfig, Test, Suite, TestResult, FullResult } from '../../../types/testReporter';
|
import { FullConfig, TestCase, Suite, TestResult, FullResult } from '../../../types/testReporter';
|
||||||
|
|
||||||
class LineReporter extends BaseReporter {
|
class LineReporter extends BaseReporter {
|
||||||
private _total = 0;
|
private _total = 0;
|
||||||
private _current = 0;
|
private _current = 0;
|
||||||
private _failures = 0;
|
private _failures = 0;
|
||||||
private _lastTest: Test | undefined;
|
private _lastTest: TestCase | undefined;
|
||||||
|
|
||||||
onBegin(config: FullConfig, suite: Suite) {
|
onBegin(config: FullConfig, suite: Suite) {
|
||||||
super.onBegin(config, suite);
|
super.onBegin(config, suite);
|
||||||
|
|
@ -30,15 +30,15 @@ class LineReporter extends BaseReporter {
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdOut(chunk: string | Buffer, test?: Test) {
|
onStdOut(chunk: string | Buffer, test?: TestCase) {
|
||||||
this._dumpToStdio(test, chunk, process.stdout);
|
this._dumpToStdio(test, chunk, process.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdErr(chunk: string | Buffer, test?: Test) {
|
onStdErr(chunk: string | Buffer, test?: TestCase) {
|
||||||
this._dumpToStdio(test, chunk, process.stderr);
|
this._dumpToStdio(test, chunk, process.stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dumpToStdio(test: Test | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream) {
|
private _dumpToStdio(test: TestCase | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream) {
|
||||||
if (this.config.quiet)
|
if (this.config.quiet)
|
||||||
return;
|
return;
|
||||||
stream.write(`\u001B[1A\u001B[2K`);
|
stream.write(`\u001B[1A\u001B[2K`);
|
||||||
|
|
@ -52,7 +52,7 @@ class LineReporter extends BaseReporter {
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestEnd(test: Test, result: TestResult) {
|
onTestEnd(test: TestCase, result: TestResult) {
|
||||||
super.onTestEnd(test, result);
|
super.onTestEnd(test, result);
|
||||||
const width = process.stdout.columns! - 1;
|
const width = process.stdout.columns! - 1;
|
||||||
const title = `[${++this._current}/${this._total}] ${formatTestTitle(this.config, test)}`.substring(0, width);
|
const title = `[${++this._current}/${this._total}] ${formatTestTitle(this.config, test)}`.substring(0, width);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import colors from 'colors/safe';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import milliseconds from 'ms';
|
import milliseconds from 'ms';
|
||||||
import { BaseReporter, formatTestTitle } from './base';
|
import { BaseReporter, formatTestTitle } from './base';
|
||||||
import { FullConfig, FullResult, Suite, Test, TestResult } from '../../../types/testReporter';
|
import { FullConfig, FullResult, Suite, TestCase, TestResult } from '../../../types/testReporter';
|
||||||
|
|
||||||
// Allow it in the Visual Studio Code Terminal and the new Windows Terminal
|
// Allow it in the Visual Studio Code Terminal and the new Windows Terminal
|
||||||
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;
|
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;
|
||||||
|
|
@ -29,7 +29,7 @@ const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '✘';
|
||||||
class ListReporter extends BaseReporter {
|
class ListReporter extends BaseReporter {
|
||||||
private _failure = 0;
|
private _failure = 0;
|
||||||
private _lastRow = 0;
|
private _lastRow = 0;
|
||||||
private _testRows = new Map<Test, number>();
|
private _testRows = new Map<TestCase, number>();
|
||||||
private _needNewLine = false;
|
private _needNewLine = false;
|
||||||
|
|
||||||
onBegin(config: FullConfig, suite: Suite) {
|
onBegin(config: FullConfig, suite: Suite) {
|
||||||
|
|
@ -37,7 +37,7 @@ class ListReporter extends BaseReporter {
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestBegin(test: Test) {
|
onTestBegin(test: TestCase) {
|
||||||
if (process.stdout.isTTY) {
|
if (process.stdout.isTTY) {
|
||||||
if (this._needNewLine) {
|
if (this._needNewLine) {
|
||||||
this._needNewLine = false;
|
this._needNewLine = false;
|
||||||
|
|
@ -49,15 +49,15 @@ class ListReporter extends BaseReporter {
|
||||||
this._testRows.set(test, this._lastRow++);
|
this._testRows.set(test, this._lastRow++);
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdOut(chunk: string | Buffer, test?: Test) {
|
onStdOut(chunk: string | Buffer, test?: TestCase) {
|
||||||
this._dumpToStdio(test, chunk, process.stdout);
|
this._dumpToStdio(test, chunk, process.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdErr(chunk: string | Buffer, test?: Test) {
|
onStdErr(chunk: string | Buffer, test?: TestCase) {
|
||||||
this._dumpToStdio(test, chunk, process.stdout);
|
this._dumpToStdio(test, chunk, process.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dumpToStdio(test: Test | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream) {
|
private _dumpToStdio(test: TestCase | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream) {
|
||||||
if (this.config.quiet)
|
if (this.config.quiet)
|
||||||
return;
|
return;
|
||||||
const text = chunk.toString('utf-8');
|
const text = chunk.toString('utf-8');
|
||||||
|
|
@ -69,7 +69,7 @@ class ListReporter extends BaseReporter {
|
||||||
stream.write(chunk);
|
stream.write(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestEnd(test: Test, result: TestResult) {
|
onTestEnd(test: TestCase, result: TestResult) {
|
||||||
super.onTestEnd(test, result);
|
super.onTestEnd(test, result);
|
||||||
|
|
||||||
const duration = colors.dim(` (${milliseconds(result.duration)})`);
|
const duration = colors.dim(` (${milliseconds(result.duration)})`);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FullConfig, Suite, Test, TestError, TestResult, Reporter, FullResult } from '../../../types/testReporter';
|
import { FullConfig, Suite, TestCase, TestError, TestResult, Reporter, FullResult } from '../../../types/testReporter';
|
||||||
|
|
||||||
export class Multiplexer implements Reporter {
|
export class Multiplexer implements Reporter {
|
||||||
private _reporters: Reporter[];
|
private _reporters: Reporter[];
|
||||||
|
|
@ -28,22 +28,22 @@ export class Multiplexer implements Reporter {
|
||||||
reporter.onBegin?.(config, suite);
|
reporter.onBegin?.(config, suite);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestBegin(test: Test) {
|
onTestBegin(test: TestCase) {
|
||||||
for (const reporter of this._reporters)
|
for (const reporter of this._reporters)
|
||||||
reporter.onTestBegin?.(test);
|
reporter.onTestBegin?.(test);
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdOut(chunk: string | Buffer, test?: Test) {
|
onStdOut(chunk: string | Buffer, test?: TestCase) {
|
||||||
for (const reporter of this._reporters)
|
for (const reporter of this._reporters)
|
||||||
reporter.onStdOut?.(chunk, test);
|
reporter.onStdOut?.(chunk, test);
|
||||||
}
|
}
|
||||||
|
|
||||||
onStdErr(chunk: string | Buffer, test?: Test) {
|
onStdErr(chunk: string | Buffer, test?: TestCase) {
|
||||||
for (const reporter of this._reporters)
|
for (const reporter of this._reporters)
|
||||||
reporter.onStdErr?.(chunk, test);
|
reporter.onStdErr?.(chunk, test);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTestEnd(test: Test, result: TestResult) {
|
onTestEnd(test: TestCase, result: TestResult) {
|
||||||
for (const reporter of this._reporters)
|
for (const reporter of this._reporters)
|
||||||
reporter.onTestEnd?.(test, result);
|
reporter.onTestEnd?.(test, result);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import * as path from 'path';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { Dispatcher } from './dispatcher';
|
import { Dispatcher } from './dispatcher';
|
||||||
import { createMatcher, FilePatternFilter, monotonicTime, raceAgainstDeadline } from './util';
|
import { createMatcher, FilePatternFilter, monotonicTime, raceAgainstDeadline } from './util';
|
||||||
import { Test, Suite } from './test';
|
import { TestCase, Suite } from './test';
|
||||||
import { Loader } from './loader';
|
import { Loader } from './loader';
|
||||||
import { Reporter } from '../../types/testReporter';
|
import { Reporter } from '../../types/testReporter';
|
||||||
import { Multiplexer } from './reporters/multiplexer';
|
import { Multiplexer } from './reporters/multiplexer';
|
||||||
|
|
@ -50,7 +50,7 @@ type RunResult = {
|
||||||
locations: string[]
|
locations: string[]
|
||||||
} | {
|
} | {
|
||||||
status: 'clashing-test-titles',
|
status: 'clashing-test-titles',
|
||||||
clashingTests: Map<string, Test[]>
|
clashingTests: Map<string, TestCase[]>
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Runner {
|
export class Runner {
|
||||||
|
|
@ -286,7 +286,7 @@ export class Runner {
|
||||||
|
|
||||||
function filterOnly(suite: Suite) {
|
function filterOnly(suite: Suite) {
|
||||||
const suiteFilter = (suite: Suite) => suite._only;
|
const suiteFilter = (suite: Suite) => suite._only;
|
||||||
const testFilter = (test: Test) => test._only;
|
const testFilter = (test: TestCase) => test._only;
|
||||||
return filterSuite(suite, suiteFilter, testFilter);
|
return filterSuite(suite, suiteFilter, testFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,11 +296,11 @@ function filterByFocusedLine(suite: Suite, focusedTestFileLines: FilePatternFilt
|
||||||
return re.test(testFileName) && (line === testLine || line === null);
|
return re.test(testFileName) && (line === testLine || line === null);
|
||||||
});
|
});
|
||||||
const suiteFilter = (suite: Suite) => !!suite.location && testFileLineMatches(suite.location.file, suite.location.line);
|
const suiteFilter = (suite: Suite) => !!suite.location && testFileLineMatches(suite.location.file, suite.location.line);
|
||||||
const testFilter = (test: Test) => testFileLineMatches(test.location.file, test.location.line);
|
const testFilter = (test: TestCase) => testFileLineMatches(test.location.file, test.location.line);
|
||||||
return filterSuite(suite, suiteFilter, testFilter);
|
return filterSuite(suite, suiteFilter, testFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSuite(suite: Suite, suiteFilter: (suites: Suite) => boolean, testFilter: (test: Test) => boolean) {
|
function filterSuite(suite: Suite, suiteFilter: (suites: Suite) => boolean, testFilter: (test: TestCase) => boolean) {
|
||||||
const onlySuites = suite.suites.filter(child => filterSuite(child, suiteFilter, testFilter) || suiteFilter(child));
|
const onlySuites = suite.suites.filter(child => filterSuite(child, suiteFilter, testFilter) || suiteFilter(child));
|
||||||
const onlyTests = suite.tests.filter(testFilter);
|
const onlyTests = suite.tests.filter(testFilter);
|
||||||
const onlyEntries = new Set([...onlySuites, ...onlyTests]);
|
const onlyEntries = new Set([...onlySuites, ...onlyTests]);
|
||||||
|
|
@ -382,8 +382,8 @@ async function collectFiles(testDir: string): Promise<string[]> {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClashingTestsPerSuite(rootSuite: Suite): Map<string, Test[]> {
|
function getClashingTestsPerSuite(rootSuite: Suite): Map<string, TestCase[]> {
|
||||||
function visit(suite: Suite, clashingTests: Map<string, Test[]>) {
|
function visit(suite: Suite, clashingTests: Map<string, TestCase[]>) {
|
||||||
for (const childSuite of suite.suites)
|
for (const childSuite of suite.suites)
|
||||||
visit(childSuite, clashingTests);
|
visit(childSuite, clashingTests);
|
||||||
for (const test of suite.tests) {
|
for (const test of suite.tests) {
|
||||||
|
|
@ -393,9 +393,9 @@ function getClashingTestsPerSuite(rootSuite: Suite): Map<string, Test[]> {
|
||||||
clashingTests.set(fullTitle, clashingTests.get(fullTitle)!.concat(test));
|
clashingTests.set(fullTitle, clashingTests.get(fullTitle)!.concat(test));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const out = new Map<string, Test[]>();
|
const out = new Map<string, TestCase[]>();
|
||||||
for (const fileSuite of rootSuite.suites) {
|
for (const fileSuite of rootSuite.suites) {
|
||||||
const clashingTests = new Map<string, Test[]>();
|
const clashingTests = new Map<string, TestCase[]>();
|
||||||
visit(fileSuite, clashingTests);
|
visit(fileSuite, clashingTests);
|
||||||
for (const [title, tests] of clashingTests.entries()) {
|
for (const [title, tests] of clashingTests.entries()) {
|
||||||
if (tests.length > 1)
|
if (tests.length > 1)
|
||||||
|
|
@ -405,7 +405,7 @@ function getClashingTestsPerSuite(rootSuite: Suite): Map<string, Test[]> {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildItemLocation(rootDir: string, testOrSuite: Suite | Test) {
|
function buildItemLocation(rootDir: string, testOrSuite: Suite | TestCase) {
|
||||||
if (!testOrSuite.location)
|
if (!testOrSuite.location)
|
||||||
return '';
|
return '';
|
||||||
return `${path.relative(rootDir, testOrSuite.location.file)}:${testOrSuite.location.line}`;
|
return `${path.relative(rootDir, testOrSuite.location.file)}:${testOrSuite.location.line}`;
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ export type Modifier = {
|
||||||
|
|
||||||
export class Suite extends Base implements reporterTypes.Suite {
|
export class Suite extends Base implements reporterTypes.Suite {
|
||||||
suites: Suite[] = [];
|
suites: Suite[] = [];
|
||||||
tests: Test[] = [];
|
tests: TestCase[] = [];
|
||||||
location?: Location;
|
location?: Location;
|
||||||
_fixtureOverrides: any = {};
|
_fixtureOverrides: any = {};
|
||||||
_entries: (Suite | Test)[] = [];
|
_entries: (Suite | TestCase)[] = [];
|
||||||
_hooks: {
|
_hooks: {
|
||||||
type: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll',
|
type: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll',
|
||||||
fn: Function,
|
fn: Function,
|
||||||
|
|
@ -59,7 +59,7 @@ export class Suite extends Base implements reporterTypes.Suite {
|
||||||
_annotations: Annotations = [];
|
_annotations: Annotations = [];
|
||||||
_modifiers: Modifier[] = [];
|
_modifiers: Modifier[] = [];
|
||||||
|
|
||||||
_addTest(test: Test) {
|
_addTest(test: TestCase) {
|
||||||
test.parent = this;
|
test.parent = this;
|
||||||
this.tests.push(test);
|
this.tests.push(test);
|
||||||
this._entries.push(test);
|
this._entries.push(test);
|
||||||
|
|
@ -71,8 +71,8 @@ export class Suite extends Base implements reporterTypes.Suite {
|
||||||
this._entries.push(suite);
|
this._entries.push(suite);
|
||||||
}
|
}
|
||||||
|
|
||||||
allTests(): Test[] {
|
allTests(): TestCase[] {
|
||||||
const result: Test[] = [];
|
const result: TestCase[] = [];
|
||||||
const visit = (suite: Suite) => {
|
const visit = (suite: Suite) => {
|
||||||
for (const entry of suite._entries) {
|
for (const entry of suite._entries) {
|
||||||
if (entry instanceof Suite)
|
if (entry instanceof Suite)
|
||||||
|
|
@ -85,8 +85,8 @@ export class Suite extends Base implements reporterTypes.Suite {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getOnlyItems(): (Test | Suite)[] {
|
_getOnlyItems(): (TestCase | Suite)[] {
|
||||||
const items: (Test | Suite)[] = [];
|
const items: (TestCase | Suite)[] = [];
|
||||||
if (this._only)
|
if (this._only)
|
||||||
items.push(this);
|
items.push(this);
|
||||||
for (const suite of this.suites)
|
for (const suite of this.suites)
|
||||||
|
|
@ -113,7 +113,7 @@ export class Suite extends Base implements reporterTypes.Suite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Test extends Base implements reporterTypes.Test {
|
export class TestCase extends Base implements reporterTypes.TestCase {
|
||||||
fn: Function;
|
fn: Function;
|
||||||
results: reporterTypes.TestResult[] = [];
|
results: reporterTypes.TestResult[] = [];
|
||||||
location: Location;
|
location: Location;
|
||||||
|
|
@ -164,8 +164,8 @@ export class Test extends Base implements reporterTypes.Test {
|
||||||
return status === 'expected' || status === 'flaky' || status === 'skipped';
|
return status === 'expected' || status === 'flaky' || status === 'skipped';
|
||||||
}
|
}
|
||||||
|
|
||||||
_clone(): Test {
|
_clone(): TestCase {
|
||||||
const test = new Test(this.title, this.fn, this._ordinalInFile, this._testType, this.location);
|
const test = new TestCase(this.title, this.fn, this._ordinalInFile, this._testType, this.location);
|
||||||
test._only = this._only;
|
test._only = this._only;
|
||||||
test._requireFile = this._requireFile;
|
test._requireFile = this._requireFile;
|
||||||
return test;
|
return test;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { expect } from './expect';
|
import { expect } from './expect';
|
||||||
import { currentlyLoadingFileSuite, currentTestInfo, setCurrentlyLoadingFileSuite } from './globals';
|
import { currentlyLoadingFileSuite, currentTestInfo, setCurrentlyLoadingFileSuite } from './globals';
|
||||||
import { Test, Suite } from './test';
|
import { TestCase, Suite } from './test';
|
||||||
import { wrapFunctionWithLocation } from './transform';
|
import { wrapFunctionWithLocation } from './transform';
|
||||||
import { Fixtures, FixturesWithLocation, Location, TestType } from './types';
|
import { Fixtures, FixturesWithLocation, Location, TestType } from './types';
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ export class TestTypeImpl {
|
||||||
const ordinalInFile = countByFile.get(suite._requireFile) || 0;
|
const ordinalInFile = countByFile.get(suite._requireFile) || 0;
|
||||||
countByFile.set(suite._requireFile, ordinalInFile + 1);
|
countByFile.set(suite._requireFile, ordinalInFile + 1);
|
||||||
|
|
||||||
const test = new Test(title, fn, ordinalInFile, this, location);
|
const test = new TestCase(title, fn, ordinalInFile, this, location);
|
||||||
test._requireFile = suite._requireFile;
|
test._requireFile = suite._requireFile;
|
||||||
suite._addTest(test);
|
suite._addTest(test);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { monotonicTime, DeadlineRunner, raceAgainstDeadline, serializeError } fr
|
||||||
import { TestBeginPayload, TestEndPayload, RunPayload, TestEntry, DonePayload, WorkerInitParams } from './ipc';
|
import { TestBeginPayload, TestEndPayload, RunPayload, TestEntry, DonePayload, WorkerInitParams } from './ipc';
|
||||||
import { setCurrentTestInfo } from './globals';
|
import { setCurrentTestInfo } from './globals';
|
||||||
import { Loader } from './loader';
|
import { Loader } from './loader';
|
||||||
import { Modifier, Suite, Test } from './test';
|
import { Modifier, Suite, TestCase } from './test';
|
||||||
import { Annotations, TestError, TestInfo, WorkerInfo } from './types';
|
import { Annotations, TestError, TestInfo, WorkerInfo } from './types';
|
||||||
import { ProjectImpl } from './project';
|
import { ProjectImpl } from './project';
|
||||||
import { FixturePool, FixtureRunner } from './fixtures';
|
import { FixturePool, FixtureRunner } from './fixtures';
|
||||||
|
|
@ -191,7 +191,7 @@ export class WorkerRunner extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _runTest(test: Test, annotations: Annotations) {
|
private async _runTest(test: TestCase, annotations: Annotations) {
|
||||||
if (this._isStopped)
|
if (this._isStopped)
|
||||||
return;
|
return;
|
||||||
const entry = this._entries.get(test._id);
|
const entry = this._entries.get(test._id);
|
||||||
|
|
@ -351,7 +351,7 @@ export class WorkerRunner extends EventEmitter {
|
||||||
setCurrentTestInfo(currentTest ? currentTest.testInfo : null);
|
setCurrentTestInfo(currentTest ? currentTest.testInfo : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _runTestWithBeforeHooks(test: Test, testInfo: TestInfo) {
|
private async _runTestWithBeforeHooks(test: TestCase, testInfo: TestInfo) {
|
||||||
try {
|
try {
|
||||||
const beforeEachModifiers: Modifier[] = [];
|
const beforeEachModifiers: Modifier[] = [];
|
||||||
for (let s = test.parent; s; s = s.parent) {
|
for (let s = test.parent; s; s = s.parent) {
|
||||||
|
|
@ -399,7 +399,7 @@ export class WorkerRunner extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _runAfterHooks(test: Test, testInfo: TestInfo) {
|
private async _runAfterHooks(test: TestCase, testInfo: TestInfo) {
|
||||||
try {
|
try {
|
||||||
await this._runHooks(test.parent!, 'afterEach', testInfo);
|
await this._runHooks(test.parent!, 'afterEach', testInfo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
36
types/testReporter.d.ts
vendored
36
types/testReporter.d.ts
vendored
|
|
@ -18,7 +18,7 @@ import type { FullConfig, TestStatus, TestError } from './test';
|
||||||
export type { FullConfig, TestStatus, TestError } from './test';
|
export type { FullConfig, TestStatus, TestError } from './test';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test or Suite location where it was defined.
|
* Location where TestCase or Suite was defined.
|
||||||
*/
|
*/
|
||||||
export interface Location {
|
export interface Location {
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,9 +43,9 @@ export interface Location {
|
||||||
* - Project suite #1 (for each project)
|
* - Project suite #1 (for each project)
|
||||||
* - File suite #1 (for each file in the project)
|
* - File suite #1 (for each file in the project)
|
||||||
* - Suites for any describe() calls
|
* - Suites for any describe() calls
|
||||||
* - Test #1 defined in the file or describe() group
|
* - TestCase #1 defined in the file or describe() group
|
||||||
* - Test #2
|
* - TestCase #2
|
||||||
* ... < more tests >
|
* ... < more test cases >
|
||||||
* - File suite #2
|
* - File suite #2
|
||||||
* ... < more file suites >
|
* ... < more file suites >
|
||||||
* - Second project suite
|
* - Second project suite
|
||||||
|
|
@ -57,7 +57,7 @@ export interface Suite {
|
||||||
* - Empty for root suite.
|
* - Empty for root suite.
|
||||||
* - Project name for project suite.
|
* - Project name for project suite.
|
||||||
* - File path for file suite.
|
* - File path for file suite.
|
||||||
* - Title passed to describe() for describe suites
|
* - Title passed to describe() for describe suites.
|
||||||
*/
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
|
@ -72,11 +72,11 @@ export interface Suite {
|
||||||
suites: Suite[];
|
suites: Suite[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests in the suite. Note that only tests defined directly in this suite
|
* Test cases in the suite. Note that only test cases defined directly in this suite
|
||||||
* are in the list. Any tests defined in nested describe() groups are listed
|
* are in the list. Any test cases defined in nested describe() groups are listed
|
||||||
* in the child `suites`.
|
* in the child `suites`.
|
||||||
*/
|
*/
|
||||||
tests: Test[];
|
tests: TestCase[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of titles from the root down to this suite.
|
* A list of titles from the root down to this suite.
|
||||||
|
|
@ -84,17 +84,17 @@ export interface Suite {
|
||||||
titlePath(): string[];
|
titlePath(): string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of all tests in this suite and its descendants.
|
* Returns the list of all test cases in this suite and its descendants.
|
||||||
*/
|
*/
|
||||||
allTests(): Test[];
|
allTests(): TestCase[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test, corresponds to test() call in a test file. When a single test() is
|
* `TestCase` corresponds to a test() call in a test file. When a single test() is
|
||||||
* running in multiple projects (or repeated multiple times), it will have multiple
|
* running in multiple projects or repeated multiple times, it will have multiple
|
||||||
* `Test` objects in corresponding projects' suites.
|
* `TestCase` objects in corresponding projects' suites.
|
||||||
*/
|
*/
|
||||||
export interface Test {
|
export interface TestCase {
|
||||||
/**
|
/**
|
||||||
* Test title as passed to the test() call.
|
* Test title as passed to the test() call.
|
||||||
*/
|
*/
|
||||||
|
|
@ -232,24 +232,24 @@ export interface Reporter {
|
||||||
/**
|
/**
|
||||||
* Called after a test has been started in the worker process.
|
* Called after a test has been started in the worker process.
|
||||||
*/
|
*/
|
||||||
onTestBegin?(test: Test): void;
|
onTestBegin?(test: TestCase): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when something has been written to the standard output in the worker process.
|
* Called when something has been written to the standard output in the worker process.
|
||||||
* When `test` is given, output happened while the test was running.
|
* When `test` is given, output happened while the test was running.
|
||||||
*/
|
*/
|
||||||
onStdOut?(chunk: string | Buffer, test?: Test): void;
|
onStdOut?(chunk: string | Buffer, test?: TestCase): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when something has been written to the standard error in the worker process.
|
* Called when something has been written to the standard error in the worker process.
|
||||||
* When `test` is given, output happened while the test was running.
|
* When `test` is given, output happened while the test was running.
|
||||||
*/
|
*/
|
||||||
onStdErr?(chunk: string | Buffer, test?: Test): void;
|
onStdErr?(chunk: string | Buffer, test?: TestCase): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a test has been finished in the worker process.
|
* Called after a test has been finished in the worker process.
|
||||||
*/
|
*/
|
||||||
onTestEnd?(test: Test, result: TestResult): void;
|
onTestEnd?(test: TestCase, result: TestResult): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on some global error, for example unhandled expection in the worker process.
|
* Called on some global error, for example unhandled expection in the worker process.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue