first impl
This commit is contained in:
parent
8f3353865d
commit
77f6dbfec6
|
|
@ -76,7 +76,8 @@ export const AttachmentLink: React.FunctionComponent<{
|
||||||
href?: string,
|
href?: string,
|
||||||
linkName?: string,
|
linkName?: string,
|
||||||
openInNewTab?: boolean,
|
openInNewTab?: boolean,
|
||||||
}> = ({ attachment, href, linkName, openInNewTab }) => {
|
depth?: number,
|
||||||
|
}> = ({ attachment, href, linkName, openInNewTab, depth }) => {
|
||||||
return <TreeItem title={<span>
|
return <TreeItem title={<span>
|
||||||
{attachment.contentType === kMissingContentType ? icons.warning() : icons.attachment()}
|
{attachment.contentType === kMissingContentType ? icons.warning() : icons.attachment()}
|
||||||
{attachment.path && <a href={href || attachment.path} download={downloadFileNameForAttachment(attachment)}>{linkName || attachment.name}</a>}
|
{attachment.path && <a href={href || attachment.path} download={downloadFileNameForAttachment(attachment)}>{linkName || attachment.name}</a>}
|
||||||
|
|
@ -87,7 +88,7 @@ export const AttachmentLink: React.FunctionComponent<{
|
||||||
)}
|
)}
|
||||||
</span>} loadChildren={attachment.body ? () => {
|
</span>} loadChildren={attachment.body ? () => {
|
||||||
return [<div key={1} className='attachment-body'><CopyToClipboard value={attachment.body!}/>{linkifyText(attachment.body!)}</div>];
|
return [<div key={1} className='attachment-body'><CopyToClipboard value={attachment.body!}/>{linkifyText(attachment.body!)}</div>];
|
||||||
} : undefined} depth={0} style={{ lineHeight: '32px' }}></TreeItem>;
|
} : undefined} depth={depth ?? 0} style={{ lineHeight: '32px' }}></TreeItem>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function downloadFileNameForAttachment(attachment: TestAttachment): string {
|
function downloadFileNameForAttachment(attachment: TestAttachment): string {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ export const TestResultView: React.FC<{
|
||||||
{result.errors.map((error, index) => <TestErrorView key={'test-result-error-message-' + index} error={error}></TestErrorView>)}
|
{result.errors.map((error, index) => <TestErrorView key={'test-result-error-message-' + index} error={error}></TestErrorView>)}
|
||||||
</AutoChip>}
|
</AutoChip>}
|
||||||
{!!result.steps.length && <AutoChip header='Test Steps'>
|
{!!result.steps.length && <AutoChip header='Test Steps'>
|
||||||
{result.steps.map((step, i) => <StepTreeItem key={`step-${i}`} step={step} depth={0}></StepTreeItem>)}
|
{result.steps.map((step, i) => <StepTreeItem key={`step-${i}`} step={step} attachments={result.attachments} depth={0}></StepTreeItem>)}
|
||||||
</AutoChip>}
|
</AutoChip>}
|
||||||
|
|
||||||
{diffs.map((diff, index) =>
|
{diffs.map((diff, index) =>
|
||||||
|
|
@ -148,7 +148,15 @@ export const TestResultView: React.FC<{
|
||||||
const StepTreeItem: React.FC<{
|
const StepTreeItem: React.FC<{
|
||||||
step: TestStep;
|
step: TestStep;
|
||||||
depth: number,
|
depth: number,
|
||||||
}> = ({ step, depth }) => {
|
attachments: TestAttachment[],
|
||||||
|
}> = ({ step, depth, attachments }) => {
|
||||||
|
if (step.category === 'attach') {
|
||||||
|
const attachmentName = step.title.match(/^attach "(.*)"$/)?.[1];
|
||||||
|
const attachment = attachments.find(a => a.name === attachmentName);
|
||||||
|
if (attachment)
|
||||||
|
return <AttachmentLink attachment={attachment} depth={depth} />;
|
||||||
|
}
|
||||||
|
|
||||||
return <TreeItem title={<span>
|
return <TreeItem title={<span>
|
||||||
<span style={{ float: 'right' }}>{msToString(step.duration)}</span>
|
<span style={{ float: 'right' }}>{msToString(step.duration)}</span>
|
||||||
{statusIcon(step.error || step.duration === -1 ? 'failed' : 'passed')}
|
{statusIcon(step.error || step.duration === -1 ? 'failed' : 'passed')}
|
||||||
|
|
@ -156,7 +164,7 @@ const StepTreeItem: React.FC<{
|
||||||
{step.count > 1 && <> ✕ <span className='test-result-counter'>{step.count}</span></>}
|
{step.count > 1 && <> ✕ <span className='test-result-counter'>{step.count}</span></>}
|
||||||
{step.location && <span className='test-result-path'>— {step.location.file}:{step.location.line}</span>}
|
{step.location && <span className='test-result-path'>— {step.location.file}:{step.location.line}</span>}
|
||||||
</span>} loadChildren={step.steps.length + (step.snippet ? 1 : 0) ? () => {
|
</span>} loadChildren={step.steps.length + (step.snippet ? 1 : 0) ? () => {
|
||||||
const children = step.steps.map((s, i) => <StepTreeItem key={i} step={s} depth={depth + 1}></StepTreeItem>);
|
const children = step.steps.map((s, i) => <StepTreeItem key={i} step={s} depth={depth + 1} attachments={attachments}></StepTreeItem>);
|
||||||
if (step.snippet)
|
if (step.snippet)
|
||||||
children.unshift(<TestErrorView key='line' error={step.snippet}></TestErrorView>);
|
children.unshift(<TestErrorView key='line' error={step.snippet}></TestErrorView>);
|
||||||
return children;
|
return children;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ export type TestResult = {
|
||||||
|
|
||||||
export type TestStep = {
|
export type TestStep = {
|
||||||
title: string;
|
title: string;
|
||||||
|
category: 'hook' | 'fixture' | 'test.step' | 'expect' | 'attach' | string;
|
||||||
startTime: string;
|
startTime: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
|
|
|
||||||
|
|
@ -498,7 +498,9 @@ class HtmlBuilder {
|
||||||
const { step, duration, count } = dedupedStep;
|
const { step, duration, count } = dedupedStep;
|
||||||
const result: TestStep = {
|
const result: TestStep = {
|
||||||
title: step.title,
|
title: step.title,
|
||||||
|
category: step.category,
|
||||||
startTime: step.startTime.toISOString(),
|
startTime: step.startTime.toISOString(),
|
||||||
|
params: step.params,
|
||||||
duration,
|
duration,
|
||||||
steps: dedupeSteps(step.steps).map(s => this._createTestStep(s)),
|
steps: dedupeSteps(step.steps).map(s => this._createTestStep(s)),
|
||||||
location: this._relativeLocation(step.location),
|
location: this._relativeLocation(step.location),
|
||||||
|
|
|
||||||
|
|
@ -876,6 +876,33 @@ for (const useIntermediateMergeReport of [false] as const) {
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should show stwep ID', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32748' } }, async ({ runInlineTest, page, showReport }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'a.test.js': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('passing', async ({ page }, testInfo) => {
|
||||||
|
testInfo.attachments.push({
|
||||||
|
name: 'top-level.txt',
|
||||||
|
contentType: 'text/plain',
|
||||||
|
body: Buffer.from('foo'),
|
||||||
|
});
|
||||||
|
await test.step('step', async () => {
|
||||||
|
testInfo.attachments.push({
|
||||||
|
name: 'step-attachment.txt',
|
||||||
|
contentType: 'text/plain',
|
||||||
|
body: Buffer.from('foo'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
|
||||||
|
await showReport();
|
||||||
|
|
||||||
|
await page.pause();
|
||||||
|
});
|
||||||
|
|
||||||
test('should strikethrough textual diff', async ({ runInlineTest, showReport, page }) => {
|
test('should strikethrough textual diff', async ({ runInlineTest, showReport, page }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'helper.ts': `
|
'helper.ts': `
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue