feat(html reporter): open html attachments in new tab (#32389)
Closes https://github.com/microsoft/playwright/issues/32281. HTML attachments get a linkified name that opens the attachment in a new tab.
This commit is contained in:
parent
a6b320e362
commit
cf8c14f884
|
|
@ -75,11 +75,16 @@ export const AttachmentLink: React.FunctionComponent<{
|
|||
attachment: TestAttachment,
|
||||
href?: string,
|
||||
linkName?: string,
|
||||
}> = ({ attachment, href, linkName }) => {
|
||||
openInNewTab?: boolean,
|
||||
}> = ({ attachment, href, linkName, openInNewTab }) => {
|
||||
return <TreeItem title={<span>
|
||||
{attachment.contentType === kMissingContentType ? icons.warning() : icons.attachment()}
|
||||
{attachment.path && <a href={href || attachment.path} download={downloadFileNameForAttachment(attachment)}>{linkName || attachment.name}</a>}
|
||||
{!attachment.path && <span>{linkifyText(attachment.name)}</span>}
|
||||
{!attachment.path && (
|
||||
openInNewTab
|
||||
? <a href={URL.createObjectURL(new Blob([attachment.body!], { type: attachment.contentType }))} target='_blank' rel='noreferrer' onClick={e => e.stopPropagation()}>{attachment.name}</a>
|
||||
: <span>{linkifyText(attachment.name)}</span>
|
||||
)}
|
||||
</span>} loadChildren={attachment.body ? () => {
|
||||
return [<div key={1} className='attachment-body'><CopyToClipboard value={attachment.body!}/>{linkifyText(attachment.body!)}</div>];
|
||||
} : undefined} depth={0} style={{ lineHeight: '32px' }}></TreeItem>;
|
||||
|
|
|
|||
|
|
@ -67,15 +67,16 @@ export const TestResultView: React.FC<{
|
|||
anchor: 'video' | 'diff' | '',
|
||||
}> = ({ result, anchor }) => {
|
||||
|
||||
const { screenshots, videos, traces, otherAttachments, diffs } = React.useMemo(() => {
|
||||
const { screenshots, videos, traces, otherAttachments, diffs, htmls } = React.useMemo(() => {
|
||||
const attachments = result?.attachments || [];
|
||||
const screenshots = new Set(attachments.filter(a => a.contentType.startsWith('image/')));
|
||||
const videos = attachments.filter(a => a.name === 'video');
|
||||
const traces = attachments.filter(a => a.name === 'trace');
|
||||
const htmls = attachments.filter(a => a.contentType.startsWith('text/html'));
|
||||
const otherAttachments = new Set<TestAttachment>(attachments);
|
||||
[...screenshots, ...videos, ...traces].forEach(a => otherAttachments.delete(a));
|
||||
[...screenshots, ...videos, ...traces, ...htmls].forEach(a => otherAttachments.delete(a));
|
||||
const diffs = groupImageDiffs(screenshots);
|
||||
return { screenshots: [...screenshots], videos, traces, otherAttachments, diffs };
|
||||
return { screenshots: [...screenshots], videos, traces, otherAttachments, diffs, htmls };
|
||||
}, [result]);
|
||||
|
||||
const videoRef = React.useRef<HTMLDivElement>(null);
|
||||
|
|
@ -135,7 +136,10 @@ export const TestResultView: React.FC<{
|
|||
</div>)}
|
||||
</AutoChip>}
|
||||
|
||||
{!!otherAttachments.size && <AutoChip header='Attachments'>
|
||||
{!!(otherAttachments.size + htmls.length) && <AutoChip header='Attachments'>
|
||||
{[...htmls].map((a, i) => (
|
||||
<AttachmentLink key={`html-link-${i}`} attachment={a} openInNewTab />)
|
||||
)}
|
||||
{[...otherAttachments].map((a, i) => <AttachmentLink key={`attachment-link-${i}`} attachment={a}></AttachmentLink>)}
|
||||
</AutoChip>}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -802,6 +802,32 @@ for (const useIntermediateMergeReport of [false] as const) {
|
|||
await expect(page.locator('.attachment-body')).toHaveText(['foo', '{"foo":1}', 'utf16 encoded']);
|
||||
});
|
||||
|
||||
test('should have link for opening HTML attachments in new tab', async ({ runInlineTest, page, showReport }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('passing', async ({ page }, testInfo) => {
|
||||
testInfo.attach('axe-report.html', {
|
||||
contentType: 'text/html',
|
||||
body: '<h1>Axe Report</h1>',
|
||||
});
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
await showReport();
|
||||
await page.getByText('passing', { exact: true }).click();
|
||||
|
||||
const [newTab] = await Promise.all([
|
||||
page.waitForEvent('popup'),
|
||||
page.getByText('axe-report.html', { exact: true }).click(),
|
||||
]);
|
||||
|
||||
await expect(newTab).toHaveURL(/^blob:/);
|
||||
await expect(newTab.getByText('Axe Report')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should use file-browser friendly extensions for buffer attachments based on contentType', async ({ runInlineTest, showReport, page }, testInfo) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.js': `
|
||||
|
|
|
|||
Loading…
Reference in a new issue