serialize expect fields in worker only

This commit is contained in:
Yury Semikhatsky 2024-10-16 17:24:33 -07:00
parent 896ea2dd67
commit 86de48ef08
3 changed files with 48 additions and 7 deletions

View file

@ -24,10 +24,11 @@ import { TimeoutManager, TimeoutManagerError, kMaxDeadline } from './timeoutMana
import type { RunnableDescription } from './timeoutManager';
import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config';
import type { FullConfig, Location } from '../../types/testReporter';
import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normalizeAndSaveAttachment, serializeError, trimLongString, windowsFilesystemFriendlyLength } from '../util';
import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normalizeAndSaveAttachment, trimLongString, windowsFilesystemFriendlyLength } from '../util';
import { TestTracing } from './testTracing';
import type { Attachment } from './testTracing';
import type { StackFrame } from '@protocol/channels';
import { serializeWorkerError } from './util';
export interface TestStepInternal {
complete(result: { error?: Error | unknown, attachments?: Attachment[] }): void;
@ -272,7 +273,7 @@ export class TestInfoImpl implements TestInfo {
if (result.error) {
if (typeof result.error === 'object' && !(result.error as any)?.[stepSymbol])
(result.error as any)[stepSymbol] = step;
const error = serializeError(result.error);
const error = serializeWorkerError(result.error);
if (data.boxedStack)
error.stack = `${error.message}\n${stringifyStackFrames(data.boxedStack).join('\n')}`;
step.error = error;
@ -330,7 +331,7 @@ export class TestInfoImpl implements TestInfo {
_failWithError(error: Error | unknown) {
if (this.status === 'passed' || this.status === 'skipped')
this.status = error instanceof TimeoutManagerError ? 'timedOut' : 'failed';
const serialized = serializeError(error);
const serialized = serializeWorkerError(error);
const step: TestStepInternal | undefined = typeof error === 'object' ? (error as any)?.[stepSymbol] : undefined;
if (step && step.boxedStack)
serialized.stack = `${(error as Error).name}: ${(error as Error).message}\n${stringifyStackFrames(step.boxedStack).join('\n')}`;

View file

@ -0,0 +1,39 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { TestInfoError } from '../../types/test';
import type { MatcherResult } from '../matchers/matcherHint';
import { serializeError } from '../util';
export function serializeWorkerError(error: Error | any): TestInfoError {
return {
...serializeError(error),
...serializeExpectDetails(error),
};
}
function serializeExpectDetails(e: Error): Pick<TestInfoError, 'shortMessage'|'log'|'expected'|'actual'> {
const matcherResult = (e as any).matcherResult as MatcherResult<unknown, unknown>;
if (!matcherResult)
return {};
return {
shortMessage: matcherResult.shortMessage,
log: matcherResult.log,
expected: matcherResult.expected,
actual: matcherResult.actual,
};
}

View file

@ -15,7 +15,7 @@
*/
import { colors } from 'playwright-core/lib/utilsBundle';
import { debugTest, relativeFilePath, serializeError } from '../util';
import { debugTest, relativeFilePath } from '../util';
import { type TestBeginPayload, type TestEndPayload, type RunPayload, type DonePayload, type WorkerInitParams, type TeardownErrorsPayload, stdioChunkToParams } from '../common/ipc';
import { setCurrentTestInfo, setIsWorkerProcess } from '../common/globals';
import { deserializeConfig } from '../common/configLoader';
@ -32,6 +32,7 @@ import type { TestInfoError } from '../../types/test';
import type { Location } from '../../types/testReporter';
import { inheritFixtureNames } from '../common/fixtures';
import { type TimeSlot } from './timeoutManager';
import { serializeWorkerError } from './util';
export class WorkerMain extends ProcessRunner {
private _params: WorkerInitParams;
@ -112,7 +113,7 @@ export class WorkerMain extends ProcessRunner {
await fakeTestInfo._runAsStage({ title: 'worker cleanup', runnable }, () => gracefullyCloseAll()).catch(() => {});
this._fatalErrors.push(...fakeTestInfo.errors);
} catch (e) {
this._fatalErrors.push(serializeError(e));
this._fatalErrors.push(serializeWorkerError(e));
}
if (this._fatalErrors.length) {
@ -153,7 +154,7 @@ export class WorkerMain extends ProcessRunner {
// No current test - fatal error.
if (!this._currentTest) {
if (!this._fatalErrors.length)
this._fatalErrors.push(serializeError(error));
this._fatalErrors.push(serializeWorkerError(error));
void this._stop();
return;
}
@ -224,7 +225,7 @@ export class WorkerMain extends ProcessRunner {
// In theory, we should run above code without any errors.
// However, in the case we screwed up, or loadTestFile failed in the worker
// but not in the runner, let's do a fatal error.
this._fatalErrors.push(serializeError(e));
this._fatalErrors.push(serializeWorkerError(e));
void this._stop();
} finally {
const donePayload: DonePayload = {