Avoid dependency common -> worker

This commit is contained in:
Yury Semikhatsky 2025-01-31 14:29:26 -08:00
parent 27586cf912
commit 822eef7d3f
2 changed files with 26 additions and 22 deletions

View file

@ -23,7 +23,6 @@ import type { Fixtures, TestType, TestDetails, TestStepInfo } from '../../types/
import type { Location } from '../../types/testReporter'; import type { Location } from '../../types/testReporter';
import { getPackageManagerExecCommand, monotonicTime, raceAgainstDeadline, zones } from 'playwright-core/lib/utils'; import { getPackageManagerExecCommand, monotonicTime, raceAgainstDeadline, zones } from 'playwright-core/lib/utils';
import { errors } from 'playwright-core'; import { errors } from 'playwright-core';
import { SkipError, TestStepInfoImpl } from '../worker/testInfo';
const testTypeSymbol = Symbol('testType'); const testTypeSymbol = Symbol('testType');
@ -263,27 +262,18 @@ export class TestTypeImpl {
const testInfo = currentTestInfo(); const testInfo = currentTestInfo();
if (!testInfo) if (!testInfo)
throw new Error(`test.step() can only be called from a test`); throw new Error(`test.step() can only be called from a test`);
if (expectation === 'skip') {
const step = testInfo._addStep({ category: 'test.step', title, location: options.location, box: options.box }); const step = testInfo._addStep({ category: 'test.step', title, location: options.location, box: options.box });
step.annotations = [{ type: 'skip' }];
step.complete({});
return undefined as T;
}
const step = testInfo._addStep({ category: 'test.step', title, location: options.location, box: options.box });
const stepInfo = new TestStepInfoImpl(step, testInfo);
return await zones.run('stepZone', step, async () => { return await zones.run('stepZone', step, async () => {
try { try {
let result: Awaited<ReturnType<typeof raceAgainstDeadline<T>>> | undefined = undefined; let result: Awaited<ReturnType<typeof raceAgainstDeadline<T>>> | undefined = undefined;
result = await raceAgainstDeadline(async () => { result = await raceAgainstDeadline(async () => {
try { try {
return await body(stepInfo); return await step.info._runStepBody(expectation === 'skip', body);
} catch (e) { } catch (e) {
// If the step timed out, the test fixtures will tear down, which in turn // 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. // will abort unfinished actions in the step body. Record such errors here.
if (result?.timedOut) if (result?.timedOut)
testInfo._failWithError(e); testInfo._failWithError(e);
if (e instanceof SkipError)
return undefined as T;
throw e; throw e;
} }
}, options.timeout ? monotonicTime() + options.timeout : 0); }, options.timeout ? monotonicTime() + options.timeout : 0);

View file

@ -28,11 +28,10 @@ import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normal
import { TestTracing } from './testTracing'; import { TestTracing } from './testTracing';
import type { StackFrame } from '@protocol/channels'; import type { StackFrame } from '@protocol/channels';
import { testInfoError } from './util'; import { testInfoError } from './util';
import { wrapFunctionWithLocation } from '../transform/transform';
export interface TestStepInternal { export interface TestStepInternal {
complete(result: { error?: Error | unknown, suggestedRebaseline?: string }): void; complete(result: { error?: Error | unknown, suggestedRebaseline?: string }): void;
annotations?: Annotation[]; info: TestStepInfoImpl
attachmentIndices: number[]; attachmentIndices: number[];
stepId: string; stepId: string;
title: string; title: string;
@ -246,7 +245,7 @@ export class TestInfoImpl implements TestInfo {
?? this._findLastStageStep(this._steps); // If no parent step on stack, assume the current stage as parent. ?? this._findLastStageStep(this._steps); // If no parent step on stack, assume the current stage as parent.
} }
_addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps' | 'attachmentIndices'>, parentStep?: TestStepInternal): TestStepInternal { _addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps' | 'attachmentIndices' | 'info'>, parentStep?: TestStepInternal): TestStepInternal {
const stepId = `${data.category}@${++this._lastStepId}`; const stepId = `${data.category}@${++this._lastStepId}`;
if (data.isStage) { if (data.isStage) {
@ -271,6 +270,7 @@ export class TestInfoImpl implements TestInfo {
...data, ...data,
steps: [], steps: [],
attachmentIndices, attachmentIndices,
info: new TestStepInfoImpl(),
complete: result => { complete: result => {
if (step.endWallTime) if (step.endWallTime)
return; return;
@ -304,12 +304,12 @@ export class TestInfoImpl implements TestInfo {
wallTime: step.endWallTime, wallTime: step.endWallTime,
error: step.error, error: step.error,
suggestedRebaseline: result.suggestedRebaseline, suggestedRebaseline: result.suggestedRebaseline,
annotations: step.annotations, annotations: step.info.annotations,
}; };
this._onStepEnd(payload); this._onStepEnd(payload);
const errorForTrace = step.error ? { name: '', message: step.error.message || '', stack: step.error.stack } : undefined; const errorForTrace = step.error ? { name: '', message: step.error.message || '', stack: step.error.stack } : undefined;
const attachments = attachmentIndices.map(i => this.attachments[i]); const attachments = attachmentIndices.map(i => this.attachments[i]);
this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments, step.annotations); this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments, step.info.annotations);
} }
}; };
const parentStepList = parentStep ? parentStep.steps : this._steps; const parentStepList = parentStep ? parentStep.steps : this._steps;
@ -508,20 +508,34 @@ export class TestInfoImpl implements TestInfo {
} }
export class TestStepInfoImpl implements TestStepInfo { export class TestStepInfoImpl implements TestStepInfo {
skip; annotations?: Annotation[];
constructor(private _step: TestStepInternal, private _testInfo: TestInfoImpl) { private _addAnnotation(type: string, description?: string) {
this.skip = wrapFunctionWithLocation(this._skip.bind(this)); this.annotations ??= [];
this.annotations.push({ type, description });
} }
private _skip(location: Location, ...args: unknown[]) { async _runStepBody<T>(skip: boolean, body: (step: TestStepInfo) => T | Promise<T>) {
if (skip) {
this._addAnnotation('skip');
return undefined as T;
}
try {
return await body(this);
} catch (e) {
if (e instanceof SkipError)
return undefined as T;
throw e;
}
}
skip(...args: unknown[]) {
// skip(); // skip();
// skip(condition: boolean, description: string); // skip(condition: boolean, description: string);
if (args.length > 0 && !args[0]) if (args.length > 0 && !args[0])
return; return;
const description = args[1] as (string|undefined); const description = args[1] as (string|undefined);
this._step.annotations ??= []; this._addAnnotation('skip', description);
this._step.annotations.push({ type: 'skip', description });
throw new SkipError(description); throw new SkipError(description);
} }
} }