This commit is contained in:
parent
cb2d94e467
commit
09529e9275
|
@ -19,7 +19,6 @@ test('basic test', async ({ page }, testInfo) => {
|
|||
- type: <[Array]<[Object]>>
|
||||
- `type` <[string]> Annotation type, for example `'skip'` or `'fail'`.
|
||||
- `description` ?<[string]> Optional description.
|
||||
- `location` ?<[Location]> Optional location in the source where the annotation is added.
|
||||
|
||||
The list of annotations applicable to the current test. Includes annotations from the test, annotations from all [`method: Test.describe`] groups the test belongs to and file-level annotations for the test file.
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
- type: <[Array]<[Object]>>
|
||||
- `type` <[string]> Annotation type, for example `'skip'` or `'fail'`.
|
||||
- `description` ?<[string]> Optional description.
|
||||
- `location` ?<[Location]> Optional location in the source where the annotation is added.
|
||||
|
||||
[`property: TestResult.annotations`] of the last test run.
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ The list of files or buffers attached during the test execution through [`proper
|
|||
- type: <[Array]<[Object]>>
|
||||
- `type` <[string]> Annotation type, for example `'skip'` or `'fail'`.
|
||||
- `description` ?<[string]> Optional description.
|
||||
- `location` ?<[Location]> Optional location in the source where the annotation is added.
|
||||
|
||||
The list of annotations applicable to the current test. Includes:
|
||||
* annotations defined on the test or suite via [`method: Test.(call)`] and [`method: Test.describe`];
|
||||
|
|
|
@ -55,7 +55,6 @@ List of steps inside this step.
|
|||
- type: <[Array]<[Object]>>
|
||||
- `type` <[string]> Annotation type, for example `'skip'`.
|
||||
- `description` ?<[string]> Optional description.
|
||||
- `location` ?<[Location]> Optional location in the source where the annotation is added.
|
||||
|
||||
The list of annotations applicable to the current test step.
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import type { TestAnnotation } from '@playwright/test';
|
||||
import type { TestCase, TestCaseSummary } from './types';
|
||||
import type { TestCase, TestAnnotation, TestCaseSummary } from './types';
|
||||
import * as React from 'react';
|
||||
import { TabbedPane } from './tabbedPane';
|
||||
import { AutoChip } from './chip';
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { TestAnnotation, Metadata } from '@playwright/test';
|
||||
import type { Metadata } from '@playwright/test';
|
||||
|
||||
export type Stats = {
|
||||
total: number;
|
||||
|
@ -59,6 +59,8 @@ export type TestFileSummary = {
|
|||
stats: Stats;
|
||||
};
|
||||
|
||||
export type TestAnnotation = { type: string, description?: string };
|
||||
|
||||
export type TestCaseSummary = {
|
||||
testId: string,
|
||||
title: string;
|
||||
|
|
|
@ -36,6 +36,7 @@ export type FixturesWithLocation = {
|
|||
fixtures: Fixtures;
|
||||
location: Location;
|
||||
};
|
||||
export type Annotation = { type: string, description?: string };
|
||||
|
||||
export const defaultTimeout = 30000;
|
||||
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
import { rootTestType } from './testType';
|
||||
import { computeTestCaseOutcome } from '../isomorphic/teleReceiver';
|
||||
|
||||
import type { FixturesWithLocation, FullProjectInternal } from './config';
|
||||
import type { Annotation, FixturesWithLocation, FullProjectInternal } from './config';
|
||||
import type { FixturePool } from './fixtures';
|
||||
import type { TestTypeImpl } from './testType';
|
||||
import type { TestAnnotation } from '../../types/test';
|
||||
import type * as reporterTypes from '../../types/testReporter';
|
||||
import type { FullProject, Location } from '../../types/testReporter';
|
||||
|
||||
|
@ -51,7 +50,7 @@ export class Suite extends Base {
|
|||
_timeout: number | undefined;
|
||||
_retries: number | undefined;
|
||||
// Annotations known statically before running the test, e.g. `test.describe.skip()` or `test.describe({ annotation }, body)`.
|
||||
_staticAnnotations: TestAnnotation[] = [];
|
||||
_staticAnnotations: Annotation[] = [];
|
||||
// Explicitly declared tags that are not a part of the title.
|
||||
_tags: string[] = [];
|
||||
_modifiers: Modifier[] = [];
|
||||
|
@ -253,7 +252,7 @@ export class TestCase extends Base implements reporterTypes.TestCase {
|
|||
|
||||
expectedStatus: reporterTypes.TestStatus = 'passed';
|
||||
timeout = 0;
|
||||
annotations: TestAnnotation[] = [];
|
||||
annotations: Annotation[] = [];
|
||||
retries = 0;
|
||||
repeatEachIndex = 0;
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ export class TestTypeImpl {
|
|||
details = fnOrDetails;
|
||||
}
|
||||
|
||||
const validatedDetails = validateTestDetails(details, location);
|
||||
const validatedDetails = validateTestDetails(details);
|
||||
const test = new TestCase(title, body, this, location);
|
||||
test._requireFile = suite._requireFile;
|
||||
test.annotations.push(...validatedDetails.annotations);
|
||||
|
@ -114,9 +114,9 @@ export class TestTypeImpl {
|
|||
if (type === 'only' || type === 'fail.only')
|
||||
test._only = true;
|
||||
if (type === 'skip' || type === 'fixme' || type === 'fail')
|
||||
test.annotations.push({ type, location });
|
||||
test.annotations.push({ type });
|
||||
else if (type === 'fail.only')
|
||||
test.annotations.push({ type: 'fail', location });
|
||||
test.annotations.push({ type: 'fail' });
|
||||
}
|
||||
|
||||
private _describe(type: 'default' | 'only' | 'serial' | 'serial.only' | 'parallel' | 'parallel.only' | 'skip' | 'fixme', location: Location, titleOrFn: string | Function, fnOrDetails?: TestDetails | Function, fn?: Function) {
|
||||
|
@ -143,7 +143,7 @@ export class TestTypeImpl {
|
|||
body = fn!;
|
||||
}
|
||||
|
||||
const validatedDetails = validateTestDetails(details, location);
|
||||
const validatedDetails = validateTestDetails(details);
|
||||
const child = new Suite(title, 'describe');
|
||||
child._requireFile = suite._requireFile;
|
||||
child.location = location;
|
||||
|
@ -158,7 +158,7 @@ export class TestTypeImpl {
|
|||
if (type === 'parallel' || type === 'parallel.only')
|
||||
child._parallelMode = 'parallel';
|
||||
if (type === 'skip' || type === 'fixme')
|
||||
child._staticAnnotations.push({ type, location });
|
||||
child._staticAnnotations.push({ type });
|
||||
|
||||
for (let parent: Suite | undefined = suite; parent; parent = parent.parent) {
|
||||
if (parent._parallelMode === 'serial' && child._parallelMode === 'parallel')
|
||||
|
@ -229,7 +229,7 @@ export class TestTypeImpl {
|
|||
if (modifierArgs.length >= 1 && !modifierArgs[0])
|
||||
return;
|
||||
const description = modifierArgs[1];
|
||||
suite._staticAnnotations.push({ type, description, location });
|
||||
suite._staticAnnotations.push({ type, description });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ export class TestTypeImpl {
|
|||
throw new Error(`test.${type}() can only be called inside test, describe block or fixture`);
|
||||
if (typeof modifierArgs[0] === 'function')
|
||||
throw new Error(`test.${type}() with a function can only be called inside describe block`);
|
||||
testInfo._modifier(type, location, modifierArgs as [any, any]);
|
||||
testInfo[type](...modifierArgs as [any, any]);
|
||||
}
|
||||
|
||||
private _setTimeout(location: Location, timeout: number) {
|
||||
|
@ -276,7 +276,7 @@ export class TestTypeImpl {
|
|||
let result: Awaited<ReturnType<typeof raceAgainstDeadline<T>>> | undefined = undefined;
|
||||
result = await raceAgainstDeadline(async () => {
|
||||
try {
|
||||
return await step.info._runStepBody(expectation === 'skip', body, step.location);
|
||||
return await step.info._runStepBody(expectation === 'skip', body);
|
||||
} catch (e) {
|
||||
// If the step timed out, the test fixtures will tear down, which in turn
|
||||
// will abort unfinished actions in the step body. Record such errors here.
|
||||
|
@ -315,9 +315,8 @@ function throwIfRunningInsideJest() {
|
|||
}
|
||||
}
|
||||
|
||||
function validateTestDetails(details: TestDetails, location: Location) {
|
||||
const originalAnnotations = Array.isArray(details.annotation) ? details.annotation : (details.annotation ? [details.annotation] : []);
|
||||
const annotations = originalAnnotations.map(annotation => ({ ...annotation, location }));
|
||||
function validateTestDetails(details: TestDetails) {
|
||||
const annotations = Array.isArray(details.annotation) ? details.annotation : (details.annotation ? [details.annotation] : []);
|
||||
const tags = Array.isArray(details.tag) ? details.tag : (details.tag ? [details.tag] : []);
|
||||
for (const tag of tags) {
|
||||
if (tag[0] !== '@')
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Metadata, TestAnnotation } from '../../types/test';
|
||||
import type { Metadata } from '../../types/test';
|
||||
import type * as reporterTypes from '../../types/testReporter';
|
||||
import type { Annotation } from '../common/config';
|
||||
import type { ReporterV2 } from '../reporters/reporterV2';
|
||||
|
||||
export type StringIntern = (s: string) => string;
|
||||
|
@ -67,7 +68,7 @@ export type JsonTestCase = {
|
|||
retries: number;
|
||||
tags?: string[];
|
||||
repeatEachIndex: number;
|
||||
annotations?: TestAnnotation[];
|
||||
annotations?: Annotation[];
|
||||
};
|
||||
|
||||
export type JsonTestEnd = {
|
||||
|
@ -94,7 +95,7 @@ export type JsonTestResultEnd = {
|
|||
status: reporterTypes.TestStatus;
|
||||
errors: reporterTypes.TestError[];
|
||||
attachments: JsonAttachment[];
|
||||
annotations?: TestAnnotation[];
|
||||
annotations?: Annotation[];
|
||||
};
|
||||
|
||||
export type JsonTestStepStart = {
|
||||
|
@ -111,7 +112,7 @@ export type JsonTestStepEnd = {
|
|||
duration: number;
|
||||
error?: reporterTypes.TestError;
|
||||
attachments?: number[]; // index of JsonTestResultEnd.attachments
|
||||
annotations?: TestAnnotation[];
|
||||
annotations?: Annotation[];
|
||||
};
|
||||
|
||||
export type JsonFullResult = {
|
||||
|
@ -242,7 +243,7 @@ export class TeleReporterReceiver {
|
|||
result.error = result.errors?.[0];
|
||||
result.attachments = this._parseAttachments(payload.attachments);
|
||||
if (payload.annotations) {
|
||||
result.annotations = this._absoluteAnnotationLocations(payload.annotations);
|
||||
result.annotations = payload.annotations;
|
||||
test.annotations = result.annotations;
|
||||
}
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
|
@ -374,18 +375,10 @@ export class TeleReporterReceiver {
|
|||
test.location = this._absoluteLocation(payload.location);
|
||||
test.retries = payload.retries;
|
||||
test.tags = payload.tags ?? [];
|
||||
test.annotations = this._absoluteAnnotationLocations(payload.annotations ?? []);
|
||||
test.annotations = payload.annotations ?? [];
|
||||
return test;
|
||||
}
|
||||
|
||||
private _absoluteAnnotationLocations(annotations: TestAnnotation[]): TestAnnotation[] {
|
||||
return annotations.map(annotation => {
|
||||
if (annotation.location)
|
||||
annotation.location = this._absoluteLocation(annotation.location);
|
||||
return annotation;
|
||||
});
|
||||
}
|
||||
|
||||
private _absoluteLocation(location: reporterTypes.Location): reporterTypes.Location;
|
||||
private _absoluteLocation(location?: reporterTypes.Location): reporterTypes.Location | undefined;
|
||||
private _absoluteLocation(location: reporterTypes.Location | undefined): reporterTypes.Location | undefined {
|
||||
|
@ -486,7 +479,7 @@ export class TeleTestCase implements reporterTypes.TestCase {
|
|||
|
||||
expectedStatus: reporterTypes.TestStatus = 'passed';
|
||||
timeout = 0;
|
||||
annotations: TestAnnotation[] = [];
|
||||
annotations: Annotation[] = [];
|
||||
retries = 0;
|
||||
tags: string[] = [];
|
||||
repeatEachIndex = 0;
|
||||
|
|
|
@ -26,7 +26,6 @@ import { getEastAsianWidth } from '../utilsBundle';
|
|||
import type { ReporterV2 } from './reporterV2';
|
||||
import type { FullConfig, FullResult, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';
|
||||
import type { Colors } from '@isomorphic/colors';
|
||||
import type { TestAnnotation } from '../../types/test';
|
||||
|
||||
export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' };
|
||||
export const kOutputSymbol = Symbol('output');
|
||||
|
@ -377,27 +376,6 @@ export function formatFailure(screen: Screen, config: FullConfig, test: TestCase
|
|||
return lines.join('\n');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function formatTestWarning(screen: Screen, config: FullConfig, warnings: TestAnnotation[]): string[] {
|
||||
warnings.sort((a, b) => {
|
||||
const aLocationKey = a.location ? `${a.location.file}:${a.location.line}:${a.location.column}` : undefined;
|
||||
const bLocationKey = b.location ? `${b.location.file}:${b.location.line}:${b.location.column}` : undefined;
|
||||
|
||||
if (!aLocationKey && !bLocationKey)
|
||||
return 0;
|
||||
if (!aLocationKey)
|
||||
return 1;
|
||||
if (!bLocationKey)
|
||||
return -1;
|
||||
return aLocationKey.localeCompare(bLocationKey);
|
||||
});
|
||||
|
||||
return warnings.filter(w => !!w.description).map(w => {
|
||||
const location = !!w.location ? `${relativeFilePath(screen, config, w.location.file)}:${w.location.line}:${w.location.column}: ` : '';
|
||||
return `${screen.colors.yellow(` Warning: ${location}${w.description}`)}`;
|
||||
});
|
||||
}
|
||||
|
||||
export function formatRetry(screen: Screen, result: TestResult) {
|
||||
const retryLines = [];
|
||||
if (result.retry) {
|
||||
|
|
|
@ -29,9 +29,9 @@ import { codeFrameColumns } from '../transform/babelBundle';
|
|||
import { resolveReporterOutputPath, stripAnsiEscapes } from '../util';
|
||||
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
import type { Metadata, TestAnnotation } from '../../types/test';
|
||||
import type { Metadata } from '../../types/test';
|
||||
import type * as api from '../../types/testReporter';
|
||||
import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep } from '@html-reporter/types';
|
||||
import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep, TestAnnotation } from '@html-reporter/types';
|
||||
import type { ZipFile } from 'playwright-core/lib/zipBundle';
|
||||
import type { TransformCallback } from 'stream';
|
||||
|
||||
|
@ -503,7 +503,7 @@ class HtmlBuilder {
|
|||
|
||||
private _serializeAnnotations(annotations: api.TestCase['annotations']): TestAnnotation[] {
|
||||
// Annotations can be pushed directly, with a wrong type.
|
||||
return annotations.map(a => ({ type: a.type, description: a.description === undefined ? undefined : String(a.description), location: a.location }));
|
||||
return annotations.map(a => ({ type: a.type, description: a.description === undefined ? undefined : String(a.description) }));
|
||||
}
|
||||
|
||||
private _createTestResult(test: api.TestCase, result: api.TestResult): TestResult {
|
||||
|
|
|
@ -27,10 +27,10 @@ import { createReporters } from '../runner/reporters';
|
|||
import { relativeFilePath } from '../util';
|
||||
|
||||
import type { BlobReportMetadata } from './blob';
|
||||
import type { ReporterDescription, TestAnnotation } from '../../types/test';
|
||||
import type { ReporterDescription } from '../../types/test';
|
||||
import type { TestError } from '../../types/testReporter';
|
||||
import type { FullConfigInternal } from '../common/config';
|
||||
import type { JsonConfig, JsonEvent, JsonFullResult, JsonLocation, JsonProject, JsonSuite, JsonTestCase, JsonTestEnd, JsonTestResultEnd, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver';
|
||||
import type { JsonConfig, JsonEvent, JsonFullResult, JsonLocation, JsonProject, JsonSuite, JsonTestCase, JsonTestResultEnd, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver';
|
||||
import type * as blobV1 from './versions/blobV1';
|
||||
|
||||
type StatusCallback = (message: string) => void;
|
||||
|
@ -474,10 +474,7 @@ class PathSeparatorPatcher {
|
|||
return;
|
||||
}
|
||||
if (jsonEvent.method === 'onTestEnd') {
|
||||
const test = jsonEvent.params.test as JsonTestEnd;
|
||||
test.annotations?.forEach(annotation => this._updateAnnotationLocations(annotation));
|
||||
const testResult = jsonEvent.params.result as JsonTestResultEnd;
|
||||
testResult.annotations?.forEach(annotation => this._updateAnnotationLocations(annotation));
|
||||
testResult.errors.forEach(error => this._updateErrorLocations(error));
|
||||
testResult.attachments.forEach(attachment => {
|
||||
if (attachment.path)
|
||||
|
@ -493,7 +490,6 @@ class PathSeparatorPatcher {
|
|||
if (jsonEvent.method === 'onStepEnd') {
|
||||
const step = jsonEvent.params.step as JsonTestStepEnd;
|
||||
this._updateErrorLocations(step.error);
|
||||
step.annotations?.forEach(annotation => this._updateAnnotationLocations(annotation));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -510,12 +506,10 @@ class PathSeparatorPatcher {
|
|||
if (isFileSuite)
|
||||
suite.title = this._updatePath(suite.title);
|
||||
for (const entry of suite.entries) {
|
||||
if ('testId' in entry) {
|
||||
if ('testId' in entry)
|
||||
this._updateLocation(entry.location);
|
||||
entry.annotations?.forEach(annotation => this._updateAnnotationLocations(annotation));
|
||||
} else {
|
||||
else
|
||||
this._updateSuite(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,10 +520,6 @@ class PathSeparatorPatcher {
|
|||
}
|
||||
}
|
||||
|
||||
private _updateAnnotationLocations(annotation: TestAnnotation) {
|
||||
this._updateLocation(annotation.location);
|
||||
}
|
||||
|
||||
private _updateLocation(location?: JsonLocation) {
|
||||
if (location)
|
||||
location.file = this._updatePath(location.file);
|
||||
|
|
|
@ -22,7 +22,6 @@ import { serializeRegexPatterns } from '../isomorphic/teleReceiver';
|
|||
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
import type * as reporterTypes from '../../types/testReporter';
|
||||
import type { TestAnnotation } from '../../types/test';
|
||||
import type * as teleReceiver from '../isomorphic/teleReceiver';
|
||||
|
||||
export type TeleReporterEmitterOptions = {
|
||||
|
@ -217,7 +216,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
retries: test.retries,
|
||||
tags: test.tags,
|
||||
repeatEachIndex: test.repeatEachIndex,
|
||||
annotations: this._relativeAnnotationLocations(test.annotations),
|
||||
annotations: test.annotations,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -238,7 +237,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
status: result.status,
|
||||
errors: result.errors,
|
||||
attachments: this._serializeAttachments(result.attachments),
|
||||
annotations: result.annotations?.length ? this._relativeAnnotationLocations(result.annotations) : undefined,
|
||||
annotations: result.annotations?.length ? result.annotations : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -269,18 +268,10 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
duration: step.duration,
|
||||
error: step.error,
|
||||
attachments: step.attachments.length ? step.attachments.map(a => result.attachments.indexOf(a)) : undefined,
|
||||
annotations: step.annotations.length ? this._relativeAnnotationLocations(step.annotations) : undefined,
|
||||
annotations: step.annotations.length ? step.annotations : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private _relativeAnnotationLocations(annotations: TestAnnotation[]): TestAnnotation[] {
|
||||
return annotations.map(annotation => {
|
||||
if (annotation.location)
|
||||
annotation.location = this._relativeLocation(annotation.location);
|
||||
return annotation;
|
||||
});
|
||||
}
|
||||
|
||||
private _relativeLocation(location: reporterTypes.Location): reporterTypes.Location;
|
||||
private _relativeLocation(location?: reporterTypes.Location): reporterTypes.Location | undefined;
|
||||
private _relativeLocation(location: reporterTypes.Location | undefined): reporterTypes.Location | undefined {
|
||||
|
|
|
@ -24,16 +24,16 @@ import { filteredStackTrace, getContainedPath, normalizeAndSaveAttachment, trimL
|
|||
import { TestTracing } from './testTracing';
|
||||
import { testInfoError } from './util';
|
||||
import { FloatingPromiseScope } from './floatingPromiseScope';
|
||||
import { wrapFunctionWithLocation } from '../transform/transform';
|
||||
|
||||
import type { RunnableDescription } from './timeoutManager';
|
||||
import type { FullProject, TestAnnotation, TestInfo, TestStatus, TestStepInfo } from '../../types/test';
|
||||
import type { FullProject, TestInfo, TestStatus, TestStepInfo } from '../../types/test';
|
||||
import type { FullConfig, Location } from '../../types/testReporter';
|
||||
import type { FullConfigInternal, FullProjectInternal } from '../common/config';
|
||||
import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config';
|
||||
import type { AttachmentPayload, StepBeginPayload, StepEndPayload, TestInfoErrorImpl, WorkerInitParams } from '../common/ipc';
|
||||
import type { TestCase } from '../common/test';
|
||||
import type { StackFrame } from '@protocol/channels';
|
||||
|
||||
|
||||
export interface TestStepInternal {
|
||||
complete(result: { error?: Error | unknown, suggestedRebaseline?: string }): void;
|
||||
info: TestStepInfoImpl
|
||||
|
@ -75,12 +75,6 @@ export class TestInfoImpl implements TestInfo {
|
|||
_hasUnhandledError = false;
|
||||
_allowSkips = false;
|
||||
|
||||
// ------------ Main methods ------------
|
||||
skip: (arg?: any, description?: string) => void;
|
||||
fixme: (arg?: any, description?: string) => void;
|
||||
fail: (arg?: any, description?: string) => void;
|
||||
slow: (arg?: any, description?: string) => void;
|
||||
|
||||
// ------------ TestInfo fields ------------
|
||||
readonly testId: string;
|
||||
readonly repeatEachIndex: number;
|
||||
|
@ -98,7 +92,7 @@ export class TestInfoImpl implements TestInfo {
|
|||
readonly fn: Function;
|
||||
expectedStatus: TestStatus;
|
||||
duration: number = 0;
|
||||
readonly annotations: TestAnnotation[] = [];
|
||||
readonly annotations: Annotation[] = [];
|
||||
readonly attachments: TestInfo['attachments'] = [];
|
||||
status: TestStatus = 'passed';
|
||||
snapshotSuffix: string = '';
|
||||
|
@ -206,14 +200,9 @@ export class TestInfoImpl implements TestInfo {
|
|||
};
|
||||
|
||||
this._tracing = new TestTracing(this, workerParams.artifactsDir);
|
||||
|
||||
this.skip = wrapFunctionWithLocation((location, ...args) => this._modifier('skip', location, args));
|
||||
this.fixme = wrapFunctionWithLocation((location, ...args) => this._modifier('fixme', location, args));
|
||||
this.fail = wrapFunctionWithLocation((location, ...args) => this._modifier('fail', location, args));
|
||||
this.slow = wrapFunctionWithLocation((location, ...args) => this._modifier('slow', location, args));
|
||||
}
|
||||
|
||||
_modifier(type: 'skip' | 'fail' | 'fixme' | 'slow', location: Location, modifierArgs: [arg?: any, description?: string]) {
|
||||
private _modifier(type: 'skip' | 'fail' | 'fixme' | 'slow', modifierArgs: [arg?: any, description?: string]) {
|
||||
if (typeof modifierArgs[1] === 'function') {
|
||||
throw new Error([
|
||||
'It looks like you are calling test.skip() inside the test and pass a callback.',
|
||||
|
@ -228,7 +217,7 @@ export class TestInfoImpl implements TestInfo {
|
|||
return;
|
||||
|
||||
const description = modifierArgs[1];
|
||||
this.annotations.push({ type, description, location });
|
||||
this.annotations.push({ type, description });
|
||||
if (type === 'slow') {
|
||||
this._timeoutManager.slow();
|
||||
} else if (type === 'skip' || type === 'fixme') {
|
||||
|
@ -492,13 +481,29 @@ export class TestInfoImpl implements TestInfo {
|
|||
return this._resolveSnapshotPath(undefined, legacyTemplate, pathSegments);
|
||||
}
|
||||
|
||||
skip(...args: [arg?: any, description?: string]) {
|
||||
this._modifier('skip', args);
|
||||
}
|
||||
|
||||
fixme(...args: [arg?: any, description?: string]) {
|
||||
this._modifier('fixme', args);
|
||||
}
|
||||
|
||||
fail(...args: [arg?: any, description?: string]) {
|
||||
this._modifier('fail', args);
|
||||
}
|
||||
|
||||
slow(...args: [arg?: any, description?: string]) {
|
||||
this._modifier('slow', args);
|
||||
}
|
||||
|
||||
setTimeout(timeout: number) {
|
||||
this._timeoutManager.setTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
export class TestStepInfoImpl implements TestStepInfo {
|
||||
annotations: TestAnnotation[] = [];
|
||||
annotations: Annotation[] = [];
|
||||
|
||||
private _testInfo: TestInfoImpl;
|
||||
private _stepId: string;
|
||||
|
@ -508,9 +513,9 @@ export class TestStepInfoImpl implements TestStepInfo {
|
|||
this._stepId = stepId;
|
||||
}
|
||||
|
||||
async _runStepBody<T>(skip: boolean, body: (step: TestStepInfo) => T | Promise<T>, location?: Location) {
|
||||
async _runStepBody<T>(skip: boolean, body: (step: TestStepInfo) => T | Promise<T>) {
|
||||
if (skip) {
|
||||
this.annotations.push({ type: 'skip', location });
|
||||
this.annotations.push({ type: 'skip' });
|
||||
return undefined as T;
|
||||
}
|
||||
try {
|
||||
|
@ -530,15 +535,15 @@ export class TestStepInfoImpl implements TestStepInfo {
|
|||
this._attachToStep(await normalizeAndSaveAttachment(this._testInfo.outputPath(), name, options));
|
||||
}
|
||||
|
||||
skip = wrapFunctionWithLocation((location: Location, ...args: unknown[]) => {
|
||||
skip(...args: unknown[]) {
|
||||
// skip();
|
||||
// skip(condition: boolean, description: string);
|
||||
if (args.length > 0 && !args[0])
|
||||
return;
|
||||
const description = args[1] as (string|undefined);
|
||||
this.annotations.push({ type: 'skip', description, location });
|
||||
this.annotations.push({ type: 'skip', description });
|
||||
throw new StepSkipError(description);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class TestSkipError extends Error {
|
||||
|
|
|
@ -32,10 +32,9 @@ import { loadTestFile } from '../common/testLoader';
|
|||
|
||||
import type { TimeSlot } from './timeoutManager';
|
||||
import type { Location } from '../../types/testReporter';
|
||||
import type { FullConfigInternal, FullProjectInternal } from '../common/config';
|
||||
import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config';
|
||||
import type { DonePayload, RunPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestInfoErrorImpl, WorkerInitParams } from '../common/ipc';
|
||||
import type { Suite, TestCase } from '../common/test';
|
||||
import type { TestAnnotation } from '../../types/test';
|
||||
|
||||
export class WorkerMain extends ProcessRunner {
|
||||
private _params: WorkerInitParams;
|
||||
|
@ -61,7 +60,7 @@ export class WorkerMain extends ProcessRunner {
|
|||
// Suites that had their beforeAll hooks, but not afterAll hooks executed.
|
||||
// These suites still need afterAll hooks to be executed for the proper cleanup.
|
||||
// Contains dynamic annotations originated by modifiers with a callback, e.g. `test.skip(() => true)`.
|
||||
private _activeSuites = new Map<Suite, TestAnnotation[]>();
|
||||
private _activeSuites = new Map<Suite, Annotation[]>();
|
||||
|
||||
constructor(params: WorkerInitParams) {
|
||||
super();
|
||||
|
@ -265,7 +264,7 @@ export class WorkerMain extends ProcessRunner {
|
|||
stepEndPayload => this.dispatchEvent('stepEnd', stepEndPayload),
|
||||
attachment => this.dispatchEvent('attach', attachment));
|
||||
|
||||
const processAnnotation = (annotation: TestAnnotation) => {
|
||||
const processAnnotation = (annotation: Annotation) => {
|
||||
testInfo.annotations.push(annotation);
|
||||
switch (annotation.type) {
|
||||
case 'fixme':
|
||||
|
@ -511,7 +510,7 @@ export class WorkerMain extends ProcessRunner {
|
|||
continue;
|
||||
const fn = async (fixtures: any) => {
|
||||
const result = await modifier.fn(fixtures);
|
||||
testInfo._modifier(modifier.type, modifier.location, [!!result, modifier.description]);
|
||||
testInfo[modifier.type](!!result, modifier.description);
|
||||
};
|
||||
inheritFixtureNames(modifier.fn, fn);
|
||||
runnables.push({
|
||||
|
@ -529,12 +528,12 @@ export class WorkerMain extends ProcessRunner {
|
|||
private async _runBeforeAllHooksForSuite(suite: Suite, testInfo: TestInfoImpl) {
|
||||
if (this._activeSuites.has(suite))
|
||||
return;
|
||||
const extraAnnotations: TestAnnotation[] = [];
|
||||
const extraAnnotations: Annotation[] = [];
|
||||
this._activeSuites.set(suite, extraAnnotations);
|
||||
await this._runAllHooksForSuite(suite, testInfo, 'beforeAll', extraAnnotations);
|
||||
}
|
||||
|
||||
private async _runAllHooksForSuite(suite: Suite, testInfo: TestInfoImpl, type: 'beforeAll' | 'afterAll', extraAnnotations?: TestAnnotation[]) {
|
||||
private async _runAllHooksForSuite(suite: Suite, testInfo: TestInfoImpl, type: 'beforeAll' | 'afterAll', extraAnnotations?: Annotation[]) {
|
||||
// Always run all the hooks, and capture the first error.
|
||||
let firstError: Error | undefined;
|
||||
for (const hook of this._collectHooksAndModifiers(suite, type, testInfo)) {
|
||||
|
|
|
@ -2049,10 +2049,6 @@ export type TestDetailsAnnotation = {
|
|||
description?: string;
|
||||
};
|
||||
|
||||
export type TestAnnotation = TestDetailsAnnotation & {
|
||||
location?: Location;
|
||||
};
|
||||
|
||||
export type TestDetails = {
|
||||
tag?: string | string[];
|
||||
annotation?: TestDetailsAnnotation | TestDetailsAnnotation[];
|
||||
|
@ -9442,11 +9438,6 @@ export interface TestInfo {
|
|||
* Optional description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Optional location in the source where the annotation is added.
|
||||
*/
|
||||
location?: Location;
|
||||
}>;
|
||||
|
||||
/**
|
||||
|
|
|
@ -451,11 +451,6 @@ export interface TestCase {
|
|||
* Optional description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Optional location in the source where the annotation is added.
|
||||
*/
|
||||
location?: Location;
|
||||
}>;
|
||||
|
||||
/**
|
||||
|
@ -612,11 +607,6 @@ export interface TestResult {
|
|||
* Optional description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Optional location in the source where the annotation is added.
|
||||
*/
|
||||
location?: Location;
|
||||
}>;
|
||||
|
||||
/**
|
||||
|
@ -732,11 +722,6 @@ export interface TestStep {
|
|||
* Optional description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Optional location in the source where the annotation is added.
|
||||
*/
|
||||
location?: Location;
|
||||
}>;
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,10 +18,11 @@ import * as React from 'react';
|
|||
import './annotationsTab.css';
|
||||
import { PlaceholderPanel } from './placeholderPanel';
|
||||
import { linkifyText } from '@web/renderUtils';
|
||||
import type { TestAnnotation } from '@playwright/test';
|
||||
|
||||
type Annotation = { type: string; description?: string; };
|
||||
|
||||
export const AnnotationsTab: React.FunctionComponent<{
|
||||
annotations: TestAnnotation[],
|
||||
annotations: Annotation[],
|
||||
}> = ({ annotations }) => {
|
||||
|
||||
if (!annotations.length)
|
||||
|
|
|
@ -42,7 +42,6 @@ import { testStatusIcon, testStatusText } from './testUtils';
|
|||
import type { UITestStatus } from './testUtils';
|
||||
import type { AfterActionTraceEventAttachment } from '@trace/trace';
|
||||
import type { HighlightedElement } from './snapshotTab';
|
||||
import type { TestAnnotation } from '@playwright/test';
|
||||
|
||||
export const Workbench: React.FunctionComponent<{
|
||||
model?: modelUtil.MultiTraceModel,
|
||||
|
@ -52,7 +51,7 @@ export const Workbench: React.FunctionComponent<{
|
|||
isLive?: boolean,
|
||||
hideTimeline?: boolean,
|
||||
status?: UITestStatus,
|
||||
annotations?: TestAnnotation[];
|
||||
annotations?: { type: string; description?: string; }[];
|
||||
inert?: boolean,
|
||||
onOpenExternally?: (location: modelUtil.SourceLocation) => void,
|
||||
revealSource?: boolean,
|
||||
|
|
|
@ -61,7 +61,7 @@ test('should access annotations in fixture', async ({ runInlineTest }) => {
|
|||
expect(exitCode).toBe(0);
|
||||
const test = report.suites[0].specs[0].tests[0];
|
||||
expect(test.annotations).toEqual([
|
||||
{ type: 'slow', description: 'just slow', location: { file: expect.any(String), line: 10, column: 14 } },
|
||||
{ type: 'slow', description: 'just slow' },
|
||||
{ type: 'myname', description: 'hello' }
|
||||
]);
|
||||
expect(test.results[0].stdout).toEqual([{ text: 'console.log\n' }]);
|
||||
|
|
|
@ -1721,9 +1721,6 @@ test('merge reports with different rootDirs and path separators', async ({ runIn
|
|||
console.log('test:', test.location.file);
|
||||
console.log('test title:', test.titlePath()[2]);
|
||||
}
|
||||
onTestEnd(test) {
|
||||
console.log('annotations:', test.annotations.map(a => 'type: ' + a.type + ', description: ' + a.description + ', file: ' + a.location.file).join(','));
|
||||
}
|
||||
};
|
||||
`,
|
||||
'merge.config.ts': `module.exports = {
|
||||
|
@ -1735,7 +1732,7 @@ test('merge reports with different rootDirs and path separators', async ({ runIn
|
|||
};`,
|
||||
'dir1/tests1/a.test.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('math 1', { annotation: { type: 'warning', description: 'Some warning' } }, async ({}) => { });
|
||||
test('math 1', async ({}) => { });
|
||||
`,
|
||||
};
|
||||
await runInlineTest(files1, { workers: 1 }, undefined, { additionalArgs: ['--config', test.info().outputPath('dir1/playwright.config.ts')] });
|
||||
|
@ -1746,7 +1743,7 @@ test('merge reports with different rootDirs and path separators', async ({ runIn
|
|||
};`,
|
||||
'dir2/tests2/b.test.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('math 2', { annotation: { type: 'issue' } }, async ({}) => { });
|
||||
test('math 2', async ({}) => { });
|
||||
`,
|
||||
};
|
||||
await runInlineTest(files2, { workers: 1 }, undefined, { additionalArgs: ['--config', test.info().outputPath('dir2/playwright.config.ts')] });
|
||||
|
@ -1768,16 +1765,12 @@ test('merge reports with different rootDirs and path separators', async ({ runIn
|
|||
|
||||
{
|
||||
const { exitCode, output } = await mergeReports(allReportsDir, undefined, { additionalArgs: ['--config', 'merge.config.ts'] });
|
||||
const testPath1 = test.info().outputPath('mergeRoot', 'tests1', 'a.test.js');
|
||||
const testPath2 = test.info().outputPath('mergeRoot', 'tests2', 'b.test.js');
|
||||
expect(exitCode).toBe(0);
|
||||
expect(output).toContain(`rootDir: ${test.info().outputPath('mergeRoot')}`);
|
||||
expect(output).toContain(`test: ${testPath1}`);
|
||||
expect(output).toContain(`test: ${test.info().outputPath('mergeRoot', 'tests1', 'a.test.js')}`);
|
||||
expect(output).toContain(`test title: ${'tests1' + path.sep + 'a.test.js'}`);
|
||||
expect(output).toContain(`annotations: type: warning, description: Some warning, file: ${testPath1}`);
|
||||
expect(output).toContain(`test: ${testPath2}`);
|
||||
expect(output).toContain(`test: ${test.info().outputPath('mergeRoot', 'tests2', 'b.test.js')}`);
|
||||
expect(output).toContain(`test title: ${'tests2' + path.sep + 'b.test.js'}`);
|
||||
expect(output).toContain(`annotations: type: issue, description: undefined, file: ${testPath2}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1793,9 +1786,6 @@ test('merge reports without --config preserves path separators', async ({ runInl
|
|||
console.log('test:', test.location.file);
|
||||
console.log('test title:', test.titlePath()[2]);
|
||||
}
|
||||
onTestEnd(test) {
|
||||
console.log('annotations:', test.annotations.map(a => 'type: ' + a.type + ', description: ' + a.description + ', file: ' + a.location.file).join(','));
|
||||
}
|
||||
};
|
||||
`,
|
||||
'dir1/playwright.config.ts': `module.exports = {
|
||||
|
@ -1803,11 +1793,11 @@ test('merge reports without --config preserves path separators', async ({ runInl
|
|||
};`,
|
||||
'dir1/tests1/a.test.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('math 1', { annotation: { type: 'warning', description: 'Some warning' } }, async ({}) => { });
|
||||
test('math 1', async ({}) => { });
|
||||
`,
|
||||
'dir1/tests2/b.test.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('math 2', { annotation: { type: 'issue' } }, async ({}) => { });
|
||||
test('math 2', async ({}) => { });
|
||||
`,
|
||||
};
|
||||
await runInlineTest(files1, { workers: 1 }, undefined, { additionalArgs: ['--config', test.info().outputPath('dir1/playwright.config.ts')] });
|
||||
|
@ -1827,15 +1817,11 @@ test('merge reports without --config preserves path separators', async ({ runInl
|
|||
const { exitCode, output } = await mergeReports(allReportsDir, undefined, { additionalArgs: ['--reporter', './echo-reporter.js'] });
|
||||
expect(exitCode).toBe(0);
|
||||
const otherSeparator = path.sep === '/' ? '\\' : '/';
|
||||
const testPath1 = test.info().outputPath('dir1', 'tests1', 'a.test.js').replaceAll(path.sep, otherSeparator);
|
||||
const testPath2 = test.info().outputPath('dir1', 'tests2', 'b.test.js').replaceAll(path.sep, otherSeparator);
|
||||
expect(output).toContain(`rootDir: ${test.info().outputPath('dir1').replaceAll(path.sep, otherSeparator)}`);
|
||||
expect(output).toContain(`test: ${testPath1}`);
|
||||
expect(output).toContain(`test: ${test.info().outputPath('dir1', 'tests1', 'a.test.js').replaceAll(path.sep, otherSeparator)}`);
|
||||
expect(output).toContain(`test title: ${'tests1' + otherSeparator + 'a.test.js'}`);
|
||||
expect(output).toContain(`annotations: type: warning, description: Some warning, file: ${testPath1}`);
|
||||
expect(output).toContain(`test: ${testPath2}`);
|
||||
expect(output).toContain(`test: ${test.info().outputPath('dir1', 'tests2', 'b.test.js').replaceAll(path.sep, otherSeparator)}`);
|
||||
expect(output).toContain(`test title: ${'tests2' + otherSeparator + 'b.test.js'}`);
|
||||
expect(output).toContain(`annotations: type: issue, description: undefined, file: ${testPath2}`);
|
||||
});
|
||||
|
||||
test('merge reports must not change test ids when there is no need to', async ({ runInlineTest, mergeReports }) => {
|
||||
|
|
|
@ -584,9 +584,7 @@ test('should report annotations from test declaration', async ({ runInlineTest }
|
|||
const visit = suite => {
|
||||
for (const test of suite.tests || []) {
|
||||
const annotations = test.annotations.map(a => {
|
||||
const description = a.description ? a.type + '=' + a.description : a.type;
|
||||
const location = a.location ? '(' + a.location.line + ':' + a.location.column + ')' : '';
|
||||
return description + location;
|
||||
return a.description ? a.type + '=' + a.description : a.type;
|
||||
});
|
||||
console.log('\\n%%title=' + test.title + ', annotations=' + annotations.join(','));
|
||||
}
|
||||
|
@ -611,7 +609,7 @@ test('should report annotations from test declaration', async ({ runInlineTest }
|
|||
expect(test.info().annotations).toEqual([]);
|
||||
});
|
||||
test('foo', { annotation: { type: 'foo' } }, () => {
|
||||
expect(test.info().annotations).toEqual([{ type: 'foo', location: { file: expect.any(String), line: 6, column: 11 } }]);
|
||||
expect(test.info().annotations).toEqual([{ type: 'foo' }]);
|
||||
});
|
||||
test('foo-bar', {
|
||||
annotation: [
|
||||
|
@ -620,8 +618,8 @@ test('should report annotations from test declaration', async ({ runInlineTest }
|
|||
],
|
||||
}, () => {
|
||||
expect(test.info().annotations).toEqual([
|
||||
{ type: 'foo', description: 'desc', location: { file: expect.any(String), line: 9, column: 11 } },
|
||||
{ type: 'bar', location: { file: expect.any(String), line: 9, column: 11 } },
|
||||
{ type: 'foo', description: 'desc' },
|
||||
{ type: 'bar' },
|
||||
]);
|
||||
});
|
||||
test.skip('skip-foo', { annotation: { type: 'foo' } }, () => {
|
||||
|
@ -638,14 +636,11 @@ test('should report annotations from test declaration', async ({ runInlineTest }
|
|||
});
|
||||
test.describe('suite', { annotation: { type: 'foo' } }, () => {
|
||||
test('foo-suite', () => {
|
||||
expect(test.info().annotations).toEqual([{ type: 'foo', location: { file: expect.any(String), line: 32, column: 12 } }]);
|
||||
expect(test.info().annotations).toEqual([{ type: 'foo' }]);
|
||||
});
|
||||
test.describe('inner', { annotation: { type: 'bar' } }, () => {
|
||||
test('foo-bar-suite', () => {
|
||||
expect(test.info().annotations).toEqual([
|
||||
{ type: 'foo', location: { file: expect.any(String), line: 32, column: 12 } },
|
||||
{ type: 'bar', location: { file: expect.any(String), line: 36, column: 14 } }
|
||||
]);
|
||||
expect(test.info().annotations).toEqual([{ type: 'foo' }, { type: 'bar' }]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -662,15 +657,15 @@ test('should report annotations from test declaration', async ({ runInlineTest }
|
|||
expect(result.exitCode).toBe(0);
|
||||
expect(result.outputLines).toEqual([
|
||||
`title=none, annotations=`,
|
||||
`title=foo, annotations=foo(6:11)`,
|
||||
`title=foo-bar, annotations=foo=desc(9:11),bar(9:11)`,
|
||||
`title=skip-foo, annotations=foo(20:12),skip(20:12)`,
|
||||
`title=fixme-bar, annotations=bar(22:12),fixme(22:12)`,
|
||||
`title=fail-foo-bar, annotations=foo(24:12),bar=desc(24:12),fail(24:12)`,
|
||||
`title=foo-suite, annotations=foo(32:12)`,
|
||||
`title=foo-bar-suite, annotations=foo(32:12),bar(36:14)`,
|
||||
`title=skip-foo-suite, annotations=foo(45:21),skip(45:21)`,
|
||||
`title=fixme-bar-suite, annotations=bar(49:21),fixme(49:21)`,
|
||||
`title=foo, annotations=foo`,
|
||||
`title=foo-bar, annotations=foo=desc,bar`,
|
||||
`title=skip-foo, annotations=foo,skip`,
|
||||
`title=fixme-bar, annotations=bar,fixme`,
|
||||
`title=fail-foo-bar, annotations=foo,bar=desc,fail`,
|
||||
`title=foo-suite, annotations=foo`,
|
||||
`title=foo-bar-suite, annotations=foo,bar`,
|
||||
`title=skip-foo-suite, annotations=foo,skip`,
|
||||
`title=fixme-bar-suite, annotations=bar,fixme`,
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -260,5 +260,5 @@ test('failed and skipped on retry should be marked as flaky', async ({ runInline
|
|||
expect(result.failed).toBe(0);
|
||||
expect(result.flaky).toBe(1);
|
||||
expect(result.output).toContain('Failed on first run');
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'Skipped on first retry', location: expect.anything() }]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'Skipped on first retry' }]);
|
||||
});
|
||||
|
|
|
@ -113,19 +113,19 @@ test('test modifiers should work', async ({ runInlineTest }) => {
|
|||
expectTest('passed3', 'passed', 'passed', []);
|
||||
expectTest('passed4', 'passed', 'passed', []);
|
||||
expectTest('passed5', 'passed', 'passed', []);
|
||||
expectTest('skipped1', 'skipped', 'skipped', [{ type: 'skip', location: { file: expect.any(String), line: 20, column: 14 } }]);
|
||||
expectTest('skipped2', 'skipped', 'skipped', [{ type: 'skip', location: { file: expect.any(String), line: 23, column: 14 } }]);
|
||||
expectTest('skipped3', 'skipped', 'skipped', [{ type: 'skip', location: { file: expect.any(String), line: 26, column: 14 } }]);
|
||||
expectTest('skipped4', 'skipped', 'skipped', [{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 29, column: 14 } }]);
|
||||
expectTest('skipped5', 'skipped', 'skipped', [{ type: 'fixme', location: { file: expect.any(String), line: 32, column: 14 } }]);
|
||||
expectTest('skipped6', 'skipped', 'skipped', [{ type: 'fixme', description: 'reason', location: { file: expect.any(String), line: 35, column: 14 } }]);
|
||||
expectTest('failed1', 'failed', 'failed', [{ type: 'fail', location: { file: expect.any(String), line: 39, column: 14 } }]);
|
||||
expectTest('failed2', 'failed', 'failed', [{ type: 'fail', location: { file: expect.any(String), line: 43, column: 14 } }]);
|
||||
expectTest('failed3', 'failed', 'failed', [{ type: 'fail', location: { file: expect.any(String), line: 47, column: 14 } }]);
|
||||
expectTest('failed4', 'failed', 'failed', [{ type: 'fail', description: 'reason', location: { file: expect.any(String), line: 51, column: 14 } }]);
|
||||
expectTest('suite1', 'skipped', 'skipped', [{ type: 'skip', location: { file: expect.any(String), line: 56, column: 14 } }]);
|
||||
expectTest('suite2', 'skipped', 'skipped', [{ type: 'skip', location: { file: expect.any(String), line: 61, column: 14 } }]);
|
||||
expectTest('suite3', 'skipped', 'skipped', [{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 66, column: 14 } }]);
|
||||
expectTest('skipped1', 'skipped', 'skipped', [{ type: 'skip' }]);
|
||||
expectTest('skipped2', 'skipped', 'skipped', [{ type: 'skip' }]);
|
||||
expectTest('skipped3', 'skipped', 'skipped', [{ type: 'skip' }]);
|
||||
expectTest('skipped4', 'skipped', 'skipped', [{ type: 'skip', description: 'reason' }]);
|
||||
expectTest('skipped5', 'skipped', 'skipped', [{ type: 'fixme' }]);
|
||||
expectTest('skipped6', 'skipped', 'skipped', [{ type: 'fixme', description: 'reason' }]);
|
||||
expectTest('failed1', 'failed', 'failed', [{ type: 'fail' }]);
|
||||
expectTest('failed2', 'failed', 'failed', [{ type: 'fail' }]);
|
||||
expectTest('failed3', 'failed', 'failed', [{ type: 'fail' }]);
|
||||
expectTest('failed4', 'failed', 'failed', [{ type: 'fail', description: 'reason' }]);
|
||||
expectTest('suite1', 'skipped', 'skipped', [{ type: 'skip' }]);
|
||||
expectTest('suite2', 'skipped', 'skipped', [{ type: 'skip' }]);
|
||||
expectTest('suite3', 'skipped', 'skipped', [{ type: 'skip', description: 'reason' }]);
|
||||
expectTest('suite4', 'passed', 'passed', []);
|
||||
expect(result.passed).toBe(10);
|
||||
expect(result.skipped).toBe(9);
|
||||
|
@ -407,7 +407,7 @@ test('should skip inside fixture', async ({ runInlineTest }) => {
|
|||
});
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.skipped).toBe(1);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 5, column: 20 } }]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
});
|
||||
|
||||
test('modifier with a function should throw in the test', async ({ runInlineTest }) => {
|
||||
|
@ -460,8 +460,8 @@ test('test.skip with worker fixtures only should skip before hooks and tests', a
|
|||
expect(result.passed).toBe(1);
|
||||
expect(result.skipped).toBe(2);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([]);
|
||||
expect(result.report.suites[0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 14, column: 14 } }]);
|
||||
expect(result.report.suites[0].suites![0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 14, column: 14 } }]);
|
||||
expect(result.report.suites[0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
expect(result.report.suites[0].suites![0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
expect(result.outputLines).toEqual([
|
||||
'beforeEach',
|
||||
'passed',
|
||||
|
@ -493,8 +493,8 @@ test('test.skip without a callback in describe block should skip hooks', async (
|
|||
});
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.skipped).toBe(2);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 10, column: 12 } }]);
|
||||
expect(result.report.suites[0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 10, column: 12 } }]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
expect(result.report.suites[0].suites![0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
expect(result.output).not.toContain('%%');
|
||||
});
|
||||
|
||||
|
@ -598,8 +598,8 @@ test('should skip all tests from beforeAll', async ({ runInlineTest }) => {
|
|||
'beforeAll',
|
||||
'afterAll',
|
||||
]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 5, column: 14 } }]);
|
||||
expect(result.report.suites[0].specs[1].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason', location: { file: expect.any(String), line: 5, column: 14 } }]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
expect(result.report.suites[0].specs[1].tests[0].annotations).toEqual([{ type: 'skip', description: 'reason' }]);
|
||||
});
|
||||
|
||||
test('should report skipped tests in-order with correct properties', async ({ runInlineTest }) => {
|
||||
|
@ -695,9 +695,9 @@ test('static modifiers should be added in serial mode', async ({ runInlineTest }
|
|||
expect(result.passed).toBe(0);
|
||||
expect(result.skipped).toBe(2);
|
||||
expect(result.didNotRun).toBe(1);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'slow', location: { file: expect.any(String), line: 6, column: 14 } }]);
|
||||
expect(result.report.suites[0].specs[1].tests[0].annotations).toEqual([{ type: 'fixme', location: { file: expect.any(String), line: 9, column: 12 } }]);
|
||||
expect(result.report.suites[0].specs[2].tests[0].annotations).toEqual([{ type: 'skip', location: { file: expect.any(String), line: 11, column: 12 } }]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'slow' }]);
|
||||
expect(result.report.suites[0].specs[1].tests[0].annotations).toEqual([{ type: 'fixme' }]);
|
||||
expect(result.report.suites[0].specs[2].tests[0].annotations).toEqual([{ type: 'skip' }]);
|
||||
expect(result.report.suites[0].specs[3].tests[0].annotations).toEqual([]);
|
||||
});
|
||||
|
||||
|
@ -721,18 +721,9 @@ test('should contain only one slow modifier', async ({ runInlineTest }) => {
|
|||
});
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([
|
||||
{ type: 'fixme', location: { file: expect.any(String), line: 3, column: 12 } },
|
||||
{ type: 'issue', description: 'my-value', location: { file: expect.any(String), line: 4, column: 11 } }
|
||||
]);
|
||||
expect(result.report.suites[1].specs[0].tests[0].annotations).toEqual([
|
||||
{ type: 'skip', location: { file: expect.any(String), line: 3, column: 12 } },
|
||||
{ type: 'issue', description: 'my-value', location: { file: expect.any(String), line: 4, column: 11 } }
|
||||
]);
|
||||
expect(result.report.suites[2].specs[0].tests[0].annotations).toEqual([
|
||||
{ type: 'slow', location: { file: expect.any(String), line: 3, column: 12 } },
|
||||
{ type: 'issue', description: 'my-value', location: { file: expect.any(String), line: 4, column: 11 } }
|
||||
]);
|
||||
expect(result.report.suites[0].specs[0].tests[0].annotations).toEqual([{ type: 'fixme' }, { type: 'issue', description: 'my-value' }]);
|
||||
expect(result.report.suites[1].specs[0].tests[0].annotations).toEqual([{ type: 'skip' }, { type: 'issue', description: 'my-value' }]);
|
||||
expect(result.report.suites[2].specs[0].tests[0].annotations).toEqual([{ type: 'slow' }, { type: 'issue', description: 'my-value' }]);
|
||||
});
|
||||
|
||||
test('should skip beforeEach hooks upon modifiers', async ({ runInlineTest }) => {
|
||||
|
|
|
@ -70,10 +70,6 @@ export type TestDetailsAnnotation = {
|
|||
description?: string;
|
||||
};
|
||||
|
||||
export type TestAnnotation = TestDetailsAnnotation & {
|
||||
location?: Location;
|
||||
};
|
||||
|
||||
export type TestDetails = {
|
||||
tag?: string | string[];
|
||||
annotation?: TestDetailsAnnotation | TestDetailsAnnotation[];
|
||||
|
|
Loading…
Reference in New Issue