mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 07:35:33 +03:00
chore: make html report produce named attachments (#26421)
https://github.com/microsoft/playwright/issues/26326
This commit is contained in:
parent
d2165f3e2d
commit
4c4525c9e0
@ -68,13 +68,22 @@ export const AttachmentLink: React.FunctionComponent<{
|
||||
}> = ({ attachment, href, linkName }) => {
|
||||
return <TreeItem title={<span>
|
||||
{attachment.contentType === kMissingContentType ? icons.warning() : icons.attachment()}
|
||||
{attachment.path && <a href={href || attachment.path} target='_blank'>{linkName || attachment.name}</a>}
|
||||
{attachment.path && <a href={href || attachment.path} download={downloadFileNameForAttachment(attachment)}>{linkName || attachment.name}</a>}
|
||||
{attachment.body && <span>{attachment.name}</span>}
|
||||
</span>} loadChildren={attachment.body ? () => {
|
||||
return [<div className='attachment-body'>{attachment.body}</div>];
|
||||
} : undefined} depth={0} style={{ lineHeight: '32px' }}></TreeItem>;
|
||||
};
|
||||
|
||||
function downloadFileNameForAttachment(attachment: TestAttachment): string {
|
||||
if (attachment.name.includes('.') || !attachment.path)
|
||||
return attachment.name;
|
||||
const firstDotIndex = attachment.path.indexOf('.');
|
||||
if (firstDotIndex === -1)
|
||||
return attachment.name;
|
||||
return attachment.name + attachment.path.slice(firstDotIndex, attachment.path.length);
|
||||
}
|
||||
|
||||
export function generateTraceUrl(traces: TestAttachment[]) {
|
||||
return `trace/index.html?${traces.map((a, i) => `trace=${new URL(a.path!, window.location.href)}`).join('&')}`;
|
||||
}
|
||||
|
@ -577,13 +577,13 @@ test('preserve attachments', async ({ runInlineTest, mergeReports, showReport, p
|
||||
await showReport();
|
||||
|
||||
await page.getByText('first').click();
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
// Check file attachment.
|
||||
await page.getByRole('link', { name: 'file-attachment' }).click();
|
||||
const popup = await popupPromise;
|
||||
const download = await downloadPromise;
|
||||
// Check file attachment content.
|
||||
await expect(popup.locator('body')).toHaveText('hello!');
|
||||
await popup.close();
|
||||
expect(await readAllFromStreamAsString(await download.createReadStream())).toEqual('hello!');
|
||||
|
||||
await page.goBack();
|
||||
|
||||
await page.getByText('failing 1').click();
|
||||
@ -651,13 +651,13 @@ test('generate html with attachment urls', async ({ runInlineTest, mergeReports,
|
||||
await page.goto(`${server.PREFIX}/index.html`);
|
||||
await page.getByText('first').click();
|
||||
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
// Check file attachment.
|
||||
await page.getByRole('link', { name: 'file-attachment' }).click();
|
||||
const popup = await popupPromise;
|
||||
const download = await downloadPromise;
|
||||
// Check file attachment content.
|
||||
await expect(popup.locator('body')).toHaveText('hello!');
|
||||
await popup.close();
|
||||
expect(await readAllFromStreamAsString(await download.createReadStream())).toEqual('hello!');
|
||||
|
||||
await page.goBack();
|
||||
|
||||
// Check inline attachment.
|
||||
@ -720,11 +720,10 @@ test('resource names should not clash between runs', async ({ runInlineTest, sho
|
||||
await page.getByText('first').click();
|
||||
await expect(fileAttachment).toBeVisible();
|
||||
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await fileAttachment.click();
|
||||
const popup = await popupPromise;
|
||||
await expect(popup.locator('body')).toHaveText('hello!');
|
||||
await popup.close();
|
||||
const download = await downloadPromise;
|
||||
expect(await readAllFromStreamAsString(await download.createReadStream())).toEqual('hello!');
|
||||
await page.goBack();
|
||||
}
|
||||
|
||||
@ -733,11 +732,10 @@ test('resource names should not clash between runs', async ({ runInlineTest, sho
|
||||
await page.getByText('failing 2').click();
|
||||
await expect(fileAttachment).toBeVisible();
|
||||
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await fileAttachment.click();
|
||||
const popup = await popupPromise;
|
||||
await expect(popup.locator('body')).toHaveText('bye!');
|
||||
await popup.close();
|
||||
const download = await downloadPromise;
|
||||
expect(await readAllFromStreamAsString(await download.createReadStream())).toEqual('bye!');
|
||||
await page.goBack();
|
||||
}
|
||||
});
|
||||
@ -1371,4 +1369,12 @@ test('should merge blob reports with same name', async ({ runInlineTest, mergeRe
|
||||
await expect(page.locator('.subnav-item:has-text("Failed") .counter')).toHaveText('4');
|
||||
await expect(page.locator('.subnav-item:has-text("Flaky") .counter')).toHaveText('2');
|
||||
await expect(page.locator('.subnav-item:has-text("Skipped") .counter')).toHaveText('4');
|
||||
});
|
||||
});
|
||||
|
||||
function readAllFromStreamAsString(stream: NodeJS.ReadableStream): Promise<string> {
|
||||
return new Promise(resolve => {
|
||||
const chunks: Buffer[] = [];
|
||||
stream.on('data', chunk => chunks.push(chunk));
|
||||
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
||||
});
|
||||
}
|
||||
|
@ -684,7 +684,7 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
||||
await expect(page.locator('.attachment-body')).toHaveText(['foo', '{"foo":1}', 'utf16 encoded']);
|
||||
});
|
||||
|
||||
test('should use file-browser friendly extensions for buffer attachments based on contentType', async ({ runInlineTest }, testInfo) => {
|
||||
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': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
@ -700,6 +700,28 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
||||
`,
|
||||
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
await showReport();
|
||||
await page.getByRole('link', { name: 'passing' }).click();
|
||||
|
||||
const expectedAttachments = [
|
||||
['screenshot', 'screenshot.png', 'f6aa9785bc9c7b8fd40c3f6ede6f59112a939527.png'],
|
||||
['some-pdf', 'some-pdf.pdf', '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33.pdf'],
|
||||
['madeup-contentType', 'madeup-contentType.dat', '62cdb7020ff920e5aa642c3d4066950dd1f01f4d.dat'],
|
||||
['screenshot-that-already-has-an-extension-with-madeup.png', 'screenshot-that-already-has-an-extension-with-madeup.png', '86f7e437faa5a7fce15d1ddcb9eaeaea377667b8.png'],
|
||||
['screenshot-that-already-has-an-extension-with-correct-contentType.png', 'screenshot-that-already-has-an-extension-with-correct-contentType.png', '84a516841ba77a5b4648de2cd0dfcb30ea46dbb4.png'],
|
||||
['example.ext with spaces', 'example.ext with spaces', 'e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98.ext-with-spaces'],
|
||||
];
|
||||
|
||||
for (const [visibleAttachmentName, downloadFileName, sha1] of expectedAttachments) {
|
||||
await test.step(`should download ${visibleAttachmentName}`, async () => {
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await page.getByRole('link', { name: visibleAttachmentName, exact: true }).click();
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toBe(downloadFileName);
|
||||
expect(await readAllFromStream(await download.createReadStream())).toEqual(await fs.promises.readFile(path.join(testInfo.outputPath('playwright-report'), 'data', sha1)));
|
||||
});
|
||||
}
|
||||
|
||||
const files = await fs.promises.readdir(path.join(testInfo.outputPath('playwright-report'), 'data'));
|
||||
expect(new Set(files)).toEqual(new Set([
|
||||
'f6aa9785bc9c7b8fd40c3f6ede6f59112a939527.png', // screenshot
|
||||
@ -2025,4 +2047,12 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
||||
await expect(page.getByText('passes title')).toBeVisible();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function readAllFromStream(stream: NodeJS.ReadableStream): Promise<Buffer> {
|
||||
return new Promise(resolve => {
|
||||
const chunks: Buffer[] = [];
|
||||
stream.on('data', chunk => chunks.push(chunk));
|
||||
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user