chore: allow matchers decorate step title (#13199)
This commit is contained in:
parent
ecc804d808
commit
923f74c5a6
|
|
@ -262,6 +262,8 @@ export class Dispatcher {
|
||||||
this._reporter.onStdErr?.('Internal error: step end without step begin: ' + params.stepId, data.test, result);
|
this._reporter.onStdErr?.('Internal error: step end without step begin: ' + params.stepId, data.test, result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (params.refinedTitle)
|
||||||
|
step.title = params.refinedTitle;
|
||||||
step.duration = params.wallTime - step.startTime.getTime();
|
step.duration = params.wallTime - step.startTime.getTime();
|
||||||
if (params.error)
|
if (params.error)
|
||||||
step.error = params.error;
|
step.error = params.error;
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,19 @@ import {
|
||||||
toHaveURL,
|
toHaveURL,
|
||||||
toHaveValue
|
toHaveValue
|
||||||
} from './matchers/matchers';
|
} from './matchers/matchers';
|
||||||
import { toMatchSnapshot, toHaveScreenshot, getSnapshotName } from './matchers/toMatchSnapshot';
|
import { toMatchSnapshot, toHaveScreenshot } from './matchers/toMatchSnapshot';
|
||||||
import type { Expect, TestError } from './types';
|
import type { Expect, TestError } from './types';
|
||||||
import matchers from 'expect/build/matchers';
|
import matchers from 'expect/build/matchers';
|
||||||
import { currentTestInfo } from './globals';
|
import { currentTestInfo } from './globals';
|
||||||
import { serializeError, captureStackTrace, currentExpectTimeout } from './util';
|
import { serializeError, captureStackTrace, currentExpectTimeout } from './util';
|
||||||
import { monotonicTime } from 'playwright-core/lib/utils/utils';
|
import { monotonicTime } from 'playwright-core/lib/utils/utils';
|
||||||
|
|
||||||
|
// from expect/build/types
|
||||||
|
export type SyncExpectationResult = {
|
||||||
|
pass: boolean;
|
||||||
|
message: () => string;
|
||||||
|
};
|
||||||
|
|
||||||
// #region
|
// #region
|
||||||
// Mirrored from https://github.com/facebook/jest/blob/f13abff8df9a0e1148baf3584bcde6d1b479edc7/packages/expect/src/print.ts
|
// Mirrored from https://github.com/facebook/jest/blob/f13abff8df9a0e1148baf3584bcde6d1b479edc7/packages/expect/src/print.ts
|
||||||
/**
|
/**
|
||||||
|
|
@ -230,11 +236,6 @@ function wrap(matcherName: string, matcher: any) {
|
||||||
if (!testInfo)
|
if (!testInfo)
|
||||||
return matcher.call(this, ...args);
|
return matcher.call(this, ...args);
|
||||||
|
|
||||||
let titleSuffix = '';
|
|
||||||
if (matcherName === 'toHaveScreenshot' || matcherName === 'toMatchSnapshot') {
|
|
||||||
const [received, nameOrOptions, optOptions] = args;
|
|
||||||
titleSuffix = `(${getSnapshotName(testInfo, received, nameOrOptions, optOptions)})`;
|
|
||||||
}
|
|
||||||
const stackTrace = captureStackTrace();
|
const stackTrace = captureStackTrace();
|
||||||
const stackLines = stackTrace.frameTexts;
|
const stackLines = stackTrace.frameTexts;
|
||||||
const frame = stackTrace.frames[0];
|
const frame = stackTrace.frames[0];
|
||||||
|
|
@ -242,15 +243,16 @@ function wrap(matcherName: string, matcher: any) {
|
||||||
const isSoft = expectCallMetaInfo?.isSoft ?? false;
|
const isSoft = expectCallMetaInfo?.isSoft ?? false;
|
||||||
const isPoll = expectCallMetaInfo?.isPoll ?? false;
|
const isPoll = expectCallMetaInfo?.isPoll ?? false;
|
||||||
const pollTimeout = expectCallMetaInfo?.pollTimeout;
|
const pollTimeout = expectCallMetaInfo?.pollTimeout;
|
||||||
|
const defaultTitle = `expect${isPoll ? '.poll' : ''}${isSoft ? '.soft' : ''}${this.isNot ? '.not' : ''}.${matcherName}`;
|
||||||
const step = testInfo._addStep({
|
const step = testInfo._addStep({
|
||||||
location: frame && frame.file ? { file: path.resolve(process.cwd(), frame.file), line: frame.line || 0, column: frame.column || 0 } : undefined,
|
location: frame && frame.file ? { file: path.resolve(process.cwd(), frame.file), line: frame.line || 0, column: frame.column || 0 } : undefined,
|
||||||
category: 'expect',
|
category: 'expect',
|
||||||
title: customMessage || `expect${isPoll ? '.poll' : ''}${isSoft ? '.soft' : ''}${this.isNot ? '.not' : ''}.${matcherName}${titleSuffix}`,
|
title: customMessage || defaultTitle,
|
||||||
canHaveChildren: true,
|
canHaveChildren: true,
|
||||||
forceNoParent: false
|
forceNoParent: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const reportStepEnd = (result: any) => {
|
const reportStepEnd = (result: any, options: { refinedTitle?: string }) => {
|
||||||
const success = result.pass !== this.isNot;
|
const success = result.pass !== this.isNot;
|
||||||
let error: TestError | undefined;
|
let error: TestError | undefined;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
@ -276,15 +278,19 @@ function wrap(matcherName: string, matcher: any) {
|
||||||
result.message = () => newMessage;
|
result.message = () => newMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
step.complete(error);
|
step.complete({ ...options, error });
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const reportStepError = (error: Error) => {
|
const reportStepError = (error: Error) => {
|
||||||
step.complete(serializeError(error));
|
step.complete({ error: serializeError(error) });
|
||||||
throw error;
|
throw error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const refineTitle = (result: SyncExpectationResult & { titleSuffix?: string }): string | undefined => {
|
||||||
|
return !customMessage && result.titleSuffix ? defaultTitle + result.titleSuffix : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result;
|
let result;
|
||||||
const [receivedOrGenerator, ...otherArgs] = args;
|
const [receivedOrGenerator, ...otherArgs] = args;
|
||||||
|
|
@ -300,8 +306,8 @@ function wrap(matcherName: string, matcher: any) {
|
||||||
result = matcher.call(this, ...args);
|
result = matcher.call(this, ...args);
|
||||||
}
|
}
|
||||||
if (result instanceof Promise)
|
if (result instanceof Promise)
|
||||||
return result.then(reportStepEnd).catch(reportStepError);
|
return result.then(result => reportStepEnd(result, { refinedTitle: refineTitle(result) })).catch(reportStepError);
|
||||||
return reportStepEnd(result);
|
return reportStepEnd(result, { refinedTitle: refineTitle(result) });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reportStepError(e);
|
reportStepError(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
},
|
},
|
||||||
onApiCallEnd: (userData: any, error?: Error) => {
|
onApiCallEnd: (userData: any, error?: Error) => {
|
||||||
const step = userData.userObject;
|
const step = userData.userObject;
|
||||||
step?.complete(error);
|
step?.complete({ error });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ export type StepBeginPayload = {
|
||||||
export type StepEndPayload = {
|
export type StepEndPayload = {
|
||||||
testId: string;
|
testId: string;
|
||||||
stepId: string;
|
stepId: string;
|
||||||
|
refinedTitle?: string;
|
||||||
wallTime: number; // milliseconds since unix epoch
|
wallTime: number; // milliseconds since unix epoch
|
||||||
error?: TestError;
|
error?: TestError;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -31,38 +31,11 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as mime from 'mime';
|
import * as mime from 'mime';
|
||||||
import { TestInfoImpl } from '../testInfo';
|
import { TestInfoImpl } from '../testInfo';
|
||||||
|
import { SyncExpectationResult } from '../expect';
|
||||||
// from expect/build/types
|
|
||||||
type SyncExpectationResult = {
|
|
||||||
pass: boolean;
|
|
||||||
message: () => string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type NameOrSegments = string | string[];
|
type NameOrSegments = string | string[];
|
||||||
const SNAPSHOT_COUNTER = Symbol('noname-snapshot-counter');
|
const SNAPSHOT_COUNTER = Symbol('noname-snapshot-counter');
|
||||||
|
|
||||||
export function getSnapshotName(
|
|
||||||
testInfo: TestInfoImpl,
|
|
||||||
received: any,
|
|
||||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } = {},
|
|
||||||
optOptions: any = {}
|
|
||||||
) {
|
|
||||||
const [
|
|
||||||
anonymousSnapshotExtension,
|
|
||||||
snapshotPathResolver,
|
|
||||||
] = typeof received === 'string' || Buffer.isBuffer(received) ? [
|
|
||||||
determineFileExtension(received),
|
|
||||||
testInfo.snapshotPath.bind(testInfo),
|
|
||||||
] : [
|
|
||||||
'png',
|
|
||||||
testInfo._screenshotPath.bind(testInfo),
|
|
||||||
];
|
|
||||||
const helper = new SnapshotHelper(
|
|
||||||
testInfo, snapshotPathResolver, anonymousSnapshotExtension, {},
|
|
||||||
nameOrOptions, optOptions, true /* dryRun */);
|
|
||||||
return path.basename(helper.snapshotPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SnapshotHelper<T extends ImageComparatorOptions> {
|
class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
readonly testInfo: TestInfoImpl;
|
readonly testInfo: TestInfoImpl;
|
||||||
readonly expectedPath: string;
|
readonly expectedPath: string;
|
||||||
|
|
@ -84,7 +57,6 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
configOptions: ImageComparatorOptions,
|
configOptions: ImageComparatorOptions,
|
||||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & T,
|
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & T,
|
||||||
optOptions: T,
|
optOptions: T,
|
||||||
dryRun: boolean = false,
|
|
||||||
) {
|
) {
|
||||||
let options: T;
|
let options: T;
|
||||||
let name: NameOrSegments | undefined;
|
let name: NameOrSegments | undefined;
|
||||||
|
|
@ -102,8 +74,7 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
...testInfo.titlePath.slice(1),
|
...testInfo.titlePath.slice(1),
|
||||||
(testInfo as any)[SNAPSHOT_COUNTER] + 1,
|
(testInfo as any)[SNAPSHOT_COUNTER] + 1,
|
||||||
].join(' ');
|
].join(' ');
|
||||||
if (!dryRun)
|
++(testInfo as any)[SNAPSHOT_COUNTER];
|
||||||
++(testInfo as any)[SNAPSHOT_COUNTER];
|
|
||||||
name = sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension;
|
name = sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,19 +114,23 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
this.kind = this.mimeType.startsWith('image/') ? 'Screenshot' : 'Snapshot';
|
this.kind = this.mimeType.startsWith('image/') ? 'Screenshot' : 'Snapshot';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decorateTitle(result: SyncExpectationResult): SyncExpectationResult & { titleSuffix: string } {
|
||||||
|
return { ...result, titleSuffix: `(${path.basename(this.snapshotPath)})` };
|
||||||
|
}
|
||||||
|
|
||||||
handleMissingNegated() {
|
handleMissingNegated() {
|
||||||
const isWriteMissingMode = this.updateSnapshots === 'all' || this.updateSnapshots === 'missing';
|
const isWriteMissingMode = this.updateSnapshots === 'all' || this.updateSnapshots === 'missing';
|
||||||
const message = `${this.snapshotPath} is missing in snapshots${isWriteMissingMode ? ', matchers using ".not" won\'t write them automatically.' : '.'}`;
|
const message = `${this.snapshotPath} is missing in snapshots${isWriteMissingMode ? ', matchers using ".not" won\'t write them automatically.' : '.'}`;
|
||||||
return {
|
return this.decorateTitle({
|
||||||
// NOTE: 'isNot' matcher implies inversed value.
|
// NOTE: 'isNot' matcher implies inversed value.
|
||||||
pass: true,
|
pass: true,
|
||||||
message: () => message,
|
message: () => message,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDifferentNegated() {
|
handleDifferentNegated() {
|
||||||
// NOTE: 'isNot' matcher implies inversed value.
|
// NOTE: 'isNot' matcher implies inversed value.
|
||||||
return { pass: false, message: () => '' };
|
return this.decorateTitle({ pass: false, message: () => '' });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMatchingNegated() {
|
handleMatchingNegated() {
|
||||||
|
|
@ -165,7 +140,7 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
indent('Expected result should be different from the actual one.', ' '),
|
indent('Expected result should be different from the actual one.', ' '),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
// NOTE: 'isNot' matcher implies inversed value.
|
// NOTE: 'isNot' matcher implies inversed value.
|
||||||
return { pass: true, message: () => message };
|
return this.decorateTitle({ pass: true, message: () => message });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMissing(actual: Buffer | string) {
|
handleMissing(actual: Buffer | string) {
|
||||||
|
|
@ -178,13 +153,13 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
if (this.updateSnapshots === 'all') {
|
if (this.updateSnapshots === 'all') {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log(message);
|
console.log(message);
|
||||||
return { pass: true, message: () => message };
|
return this.decorateTitle({ pass: true, message: () => message });
|
||||||
}
|
}
|
||||||
if (this.updateSnapshots === 'missing') {
|
if (this.updateSnapshots === 'missing') {
|
||||||
this.testInfo._failWithError(serializeError(new Error(message)), false /* isHardError */);
|
this.testInfo._failWithError(serializeError(new Error(message)), false /* isHardError */);
|
||||||
return { pass: true, message: () => '' };
|
return this.decorateTitle({ pass: true, message: () => '' });
|
||||||
}
|
}
|
||||||
return { pass: false, message: () => message };
|
return this.decorateTitle({ pass: false, message: () => message });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDifferent(
|
handleDifferent(
|
||||||
|
|
@ -226,11 +201,11 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||||
this.testInfo.attachments.push({ name: path.basename(this.diffPath), contentType: this.mimeType, path: this.diffPath });
|
this.testInfo.attachments.push({ name: path.basename(this.diffPath), contentType: this.mimeType, path: this.diffPath });
|
||||||
output.push(` Diff: ${colors.yellow(this.diffPath)}`);
|
output.push(` Diff: ${colors.yellow(this.diffPath)}`);
|
||||||
}
|
}
|
||||||
return { pass: false, message: () => output.join('\n'), };
|
return this.decorateTitle({ pass: false, message: () => output.join('\n'), });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMatching() {
|
handleMatching() {
|
||||||
return { pass: true, message: () => '' };
|
return this.decorateTitle({ pass: true, message: () => '' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +214,7 @@ export function toMatchSnapshot(
|
||||||
received: Buffer | string,
|
received: Buffer | string,
|
||||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ImageComparatorOptions = {},
|
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ImageComparatorOptions = {},
|
||||||
optOptions: ImageComparatorOptions = {}
|
optOptions: ImageComparatorOptions = {}
|
||||||
): SyncExpectationResult {
|
): SyncExpectationResult & { titleSuffix: string } {
|
||||||
const testInfo = currentTestInfo();
|
const testInfo = currentTestInfo();
|
||||||
if (!testInfo)
|
if (!testInfo)
|
||||||
throw new Error(`toMatchSnapshot() must be called during the test`);
|
throw new Error(`toMatchSnapshot() must be called during the test`);
|
||||||
|
|
@ -269,7 +244,7 @@ export function toMatchSnapshot(
|
||||||
writeFileSync(helper.snapshotPath, received);
|
writeFileSync(helper.snapshotPath, received);
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log(helper.snapshotPath + ' does not match, writing actual.');
|
console.log(helper.snapshotPath + ' does not match, writing actual.');
|
||||||
return { pass: true, message: () => helper.snapshotPath + ' running with --update-snapshots, writing actual.' };
|
return helper.decorateTitle({ pass: true, message: () => helper.snapshotPath + ' running with --update-snapshots, writing actual.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
return helper.handleDifferent(received, expected, undefined, result.diff, result.errorMessage, undefined);
|
return helper.handleDifferent(received, expected, undefined, result.diff, result.errorMessage, undefined);
|
||||||
|
|
|
||||||
|
|
@ -219,10 +219,10 @@ export class TestInfoImpl implements TestInfo {
|
||||||
const step = this._addStep(stepInfo);
|
const step = this._addStep(stepInfo);
|
||||||
try {
|
try {
|
||||||
const result = await cb();
|
const result = await cb();
|
||||||
step.complete();
|
step.complete({});
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
step.complete(e instanceof SkipError ? undefined : serializeError(e));
|
step.complete({ error: e instanceof SkipError ? undefined : serializeError(e) });
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -216,9 +216,9 @@ export class TestTypeImpl {
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await body();
|
await body();
|
||||||
step.complete();
|
step.complete({});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
step.complete(serializeError(e));
|
step.complete({ error: serializeError(e) });
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export type FixturesWithLocation = {
|
||||||
export type Annotation = { type: string, description?: string };
|
export type Annotation = { type: string, description?: string };
|
||||||
|
|
||||||
export interface TestStepInternal {
|
export interface TestStepInternal {
|
||||||
complete(error?: Error | TestError): void;
|
complete(result: { refinedTitle?: string, error?: Error | TestError }): void;
|
||||||
title: string;
|
title: string;
|
||||||
category: string;
|
category: string;
|
||||||
canHaveChildren: boolean;
|
canHaveChildren: boolean;
|
||||||
|
|
|
||||||
|
|
@ -207,14 +207,14 @@ export class WorkerRunner extends EventEmitter {
|
||||||
let callbackHandled = false;
|
let callbackHandled = false;
|
||||||
const step: TestStepInternal = {
|
const step: TestStepInternal = {
|
||||||
...data,
|
...data,
|
||||||
complete: (error?: Error | TestError) => {
|
complete: result => {
|
||||||
if (callbackHandled)
|
if (callbackHandled)
|
||||||
return;
|
return;
|
||||||
callbackHandled = true;
|
callbackHandled = true;
|
||||||
if (error instanceof Error)
|
const error = result.error instanceof Error ? serializeError(result.error) : result.error;
|
||||||
error = serializeError(error);
|
|
||||||
const payload: StepEndPayload = {
|
const payload: StepEndPayload = {
|
||||||
testId: test._id,
|
testId: test._id,
|
||||||
|
refinedTitle: result.refinedTitle,
|
||||||
stepId,
|
stepId,
|
||||||
wallTime: Date.now(),
|
wallTime: Date.now(),
|
||||||
error,
|
error,
|
||||||
|
|
@ -346,14 +346,14 @@ export class WorkerRunner extends EventEmitter {
|
||||||
// Setup fixtures required by the test.
|
// Setup fixtures required by the test.
|
||||||
testInfo._timeoutManager.setCurrentRunnable({ type: 'test' });
|
testInfo._timeoutManager.setCurrentRunnable({ type: 'test' });
|
||||||
const params = await this._fixtureRunner.resolveParametersForFunction(test.fn, testInfo);
|
const params = await this._fixtureRunner.resolveParametersForFunction(test.fn, testInfo);
|
||||||
beforeHooksStep.complete(); // Report fixture hooks step as completed.
|
beforeHooksStep.complete({}); // Report fixture hooks step as completed.
|
||||||
|
|
||||||
// Now run the test itself.
|
// Now run the test itself.
|
||||||
const fn = test.fn; // Extract a variable to get a better stack trace ("myTest" vs "TestCase.myTest [as fn]").
|
const fn = test.fn; // Extract a variable to get a better stack trace ("myTest" vs "TestCase.myTest [as fn]").
|
||||||
await fn(params, testInfo);
|
await fn(params, testInfo);
|
||||||
}, 'allowSkips');
|
}, 'allowSkips');
|
||||||
|
|
||||||
beforeHooksStep.complete(maybeError); // Second complete is a no-op.
|
beforeHooksStep.complete({ error: maybeError }); // Second complete is a no-op.
|
||||||
});
|
});
|
||||||
|
|
||||||
if (didFailBeforeAllForSuite) {
|
if (didFailBeforeAllForSuite) {
|
||||||
|
|
@ -425,7 +425,7 @@ export class WorkerRunner extends EventEmitter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
afterHooksStep.complete(firstAfterHooksError);
|
afterHooksStep.complete({ error: firstAfterHooksError });
|
||||||
this._currentTest = null;
|
this._currentTest = null;
|
||||||
setCurrentTestInfo(null);
|
setCurrentTestInfo(null);
|
||||||
this.emit('testEnd', buildTestEndPayload(testInfo));
|
this.emit('testEnd', buildTestEndPayload(testInfo));
|
||||||
|
|
|
||||||
|
|
@ -150,8 +150,8 @@ test('should report toHaveScreenshot step with expectation name in title', async
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'reporter.ts': `
|
'reporter.ts': `
|
||||||
class Reporter {
|
class Reporter {
|
||||||
onStepBegin(test, result, step) {
|
onStepEnd(test, result, step) {
|
||||||
console.log('%% begin ' + step.title);
|
console.log('%% end ' + step.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Reporter;
|
module.exports = Reporter;
|
||||||
|
|
@ -173,12 +173,12 @@ test('should report toHaveScreenshot step with expectation name in title', async
|
||||||
|
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||||
`%% begin Before Hooks`,
|
`%% end browserContext.newPage`,
|
||||||
`%% begin browserContext.newPage`,
|
`%% end Before Hooks`,
|
||||||
`%% begin expect.toHaveScreenshot(foo.png)`,
|
`%% end expect.toHaveScreenshot(foo.png)`,
|
||||||
`%% begin expect.toHaveScreenshot(is-a-test-1.png)`,
|
`%% end expect.toHaveScreenshot(is-a-test-1.png)`,
|
||||||
`%% begin After Hooks`,
|
`%% end browserContext.close`,
|
||||||
`%% begin browserContext.close`,
|
`%% end After Hooks`,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue