trace viewer
This commit is contained in:
parent
3b0f0a9798
commit
4fe6927c5d
|
|
@ -27,12 +27,12 @@ import type { Annotation, FullConfigInternal, FullProjectInternal } from '../com
|
||||||
import type { FullConfig, Location } from '../../types/testReporter';
|
import type { FullConfig, Location } from '../../types/testReporter';
|
||||||
import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normalizeAndSaveAttachment, trimLongString, windowsFilesystemFriendlyLength } from '../util';
|
import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normalizeAndSaveAttachment, trimLongString, windowsFilesystemFriendlyLength } from '../util';
|
||||||
import { TestTracing } from './testTracing';
|
import { TestTracing } from './testTracing';
|
||||||
import type { Attachment } from './testTracing';
|
|
||||||
import type { StackFrame } from '@protocol/channels';
|
import type { StackFrame } from '@protocol/channels';
|
||||||
import { testInfoError } from './util';
|
import { testInfoError } from './util';
|
||||||
|
|
||||||
export interface TestStepInternal {
|
export interface TestStepInternal {
|
||||||
complete(result: { error?: Error | unknown, attachments?: Attachment[], suggestedRebaseline?: string }): void;
|
complete(result: { error?: Error | unknown, suggestedRebaseline?: string }): void;
|
||||||
|
attachmentIndexes: number[];
|
||||||
stepId: string;
|
stepId: string;
|
||||||
title: string;
|
title: string;
|
||||||
category: 'hook' | 'fixture' | 'test.step' | 'expect' | 'attach' | string;
|
category: 'hook' | 'fixture' | 'test.step' | 'expect' | 'attach' | string;
|
||||||
|
|
@ -70,6 +70,7 @@ export class TestInfoImpl implements TestInfo {
|
||||||
readonly _projectInternal: FullProjectInternal;
|
readonly _projectInternal: FullProjectInternal;
|
||||||
readonly _configInternal: FullConfigInternal;
|
readonly _configInternal: FullConfigInternal;
|
||||||
private readonly _steps: TestStepInternal[] = [];
|
private readonly _steps: TestStepInternal[] = [];
|
||||||
|
private readonly _stepMap = new Map<string, TestStepInternal>();
|
||||||
_onDidFinishTestFunction: (() => Promise<void>) | undefined;
|
_onDidFinishTestFunction: (() => Promise<void>) | undefined;
|
||||||
_hasNonRetriableError = false;
|
_hasNonRetriableError = false;
|
||||||
_hasUnhandledError = false;
|
_hasUnhandledError = false;
|
||||||
|
|
@ -248,7 +249,7 @@ export class TestInfoImpl implements TestInfo {
|
||||||
return zones.zoneData<ExpectZone>('expectZone')?.stepId;
|
return zones.zoneData<ExpectZone>('expectZone')?.stepId;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps' | 'attachments'>, parentStep?: TestStepInternal): TestStepInternal {
|
_addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps' | 'attachmentIndexes'>, parentStep?: TestStepInternal): TestStepInternal {
|
||||||
const stepId = `${data.category}@${++this._lastStepId}`;
|
const stepId = `${data.category}@${++this._lastStepId}`;
|
||||||
|
|
||||||
if (data.isStage) {
|
if (data.isStage) {
|
||||||
|
|
@ -267,10 +268,12 @@ export class TestInfoImpl implements TestInfo {
|
||||||
}
|
}
|
||||||
data.location = data.location || filteredStack[0];
|
data.location = data.location || filteredStack[0];
|
||||||
|
|
||||||
|
const attachmentIndexes: number[] = [];
|
||||||
const step: TestStepInternal = {
|
const step: TestStepInternal = {
|
||||||
stepId,
|
stepId,
|
||||||
...data,
|
...data,
|
||||||
steps: [],
|
steps: [],
|
||||||
|
attachmentIndexes,
|
||||||
complete: result => {
|
complete: result => {
|
||||||
if (step.endWallTime)
|
if (step.endWallTime)
|
||||||
return;
|
return;
|
||||||
|
|
@ -307,11 +310,13 @@ export class TestInfoImpl implements TestInfo {
|
||||||
};
|
};
|
||||||
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;
|
||||||
this._tracing.appendAfterActionForStep(stepId, errorForTrace, result.attachments);
|
const attachments = attachmentIndexes.map(i => this.attachments[i]);
|
||||||
|
this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const parentStepList = parentStep ? parentStep.steps : this._steps;
|
const parentStepList = parentStep ? parentStep.steps : this._steps;
|
||||||
parentStepList.push(step);
|
parentStepList.push(step);
|
||||||
|
this._stepMap.set(stepId, step);
|
||||||
const payload: StepBeginPayload = {
|
const payload: StepBeginPayload = {
|
||||||
testId: this.testId,
|
testId: this.testId,
|
||||||
stepId,
|
stepId,
|
||||||
|
|
@ -410,13 +415,14 @@ export class TestInfoImpl implements TestInfo {
|
||||||
title: `attach "${name}"`,
|
title: `attach "${name}"`,
|
||||||
category: 'attach',
|
category: 'attach',
|
||||||
});
|
});
|
||||||
const attachment = await normalizeAndSaveAttachment(this.outputPath(), name, options);
|
this._attach(await normalizeAndSaveAttachment(this.outputPath(), name, options), step.stepId);
|
||||||
this._attach(attachment, step.stepId);
|
step.complete({});
|
||||||
step.complete({ attachments: [attachment] });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _attach(attachment: TestInfo['attachments'][0], stepId: string | undefined) {
|
private _attach(attachment: TestInfo['attachments'][0], stepId: string | undefined) {
|
||||||
this._attachmentsPush(attachment);
|
const index = this._attachmentsPush(attachment) - 1;
|
||||||
|
if (stepId)
|
||||||
|
this._stepMap.get(stepId)!.attachmentIndexes.push(index);
|
||||||
this._onAttach({
|
this._onAttach({
|
||||||
testId: this.testId,
|
testId: this.testId,
|
||||||
name: attachment.name,
|
name: attachment.name,
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,7 @@ test('should show custom fixture titles in actions tree', async ({ runUITest })
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('all attachments are shown in attachments tab', async ({ runUITest }) => {
|
test('attachments tab shows all but top-level .push attachments', async ({ runUITest }) => {
|
||||||
const { page } = await runUITest({
|
const { page } = await runUITest({
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
@ -429,11 +429,10 @@ test('all attachments are shown in attachments tab', async ({ runUITest }) => {
|
||||||
- treeitem /attach \\"bar-attach\\"/
|
- treeitem /attach \\"bar-attach\\"/
|
||||||
`);
|
`);
|
||||||
await page.getByRole('tab', { name: 'Attachments' }).click();
|
await page.getByRole('tab', { name: 'Attachments' }).click();
|
||||||
await expect(page.getByRole('tabpanel', { name: 'Attachments' }), 'attachments tab shows all').toMatchAriaSnapshot(`
|
await expect(page.getByRole('tabpanel', { name: 'Attachments' })).toMatchAriaSnapshot(`
|
||||||
- tabpanel:
|
- tabpanel:
|
||||||
- button /foo-push/
|
- button /foo-push/
|
||||||
- button /foo-attach/
|
- button /foo-attach/
|
||||||
- button /bar-push/
|
|
||||||
- button /bar-attach/
|
- button /bar-attach/
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue