diff --git a/packages/html-reporter/src/links.tsx b/packages/html-reporter/src/links.tsx index 4ddaf20a91..42b9f9b5b9 100644 --- a/packages/html-reporter/src/links.tsx +++ b/packages/html-reporter/src/links.tsx @@ -78,7 +78,7 @@ export const AttachmentLink: React.FunctionComponent<{ return {attachment.contentType === kMissingContentType ? icons.warning() : icons.attachment()} {attachment.path && {linkName || attachment.name}} - {attachment.body && {linkifyText(attachment.name)}} + {!attachment.path && {linkifyText(attachment.name)}} } loadChildren={attachment.body ? () => { return [
{linkifyText(attachment.body!)}
]; } : undefined} depth={0} style={{ lineHeight: '32px' }}>
; diff --git a/packages/html-reporter/src/testCaseView.spec.tsx b/packages/html-reporter/src/testCaseView.spec.tsx index d73407582d..624a93805f 100644 --- a/packages/html-reporter/src/testCaseView.spec.tsx +++ b/packages/html-reporter/src/testCaseView.spec.tsx @@ -132,6 +132,9 @@ const resultWithAttachment: TestResult = { name: 'first attachment', body: 'The body with https://playwright.dev/docs/intro link and https://github.com/microsoft/playwright/issues/31284.', contentType: 'text/plain' + }, { + name: 'attachment with inline link https://github.com/microsoft/playwright/issues/31284', + contentType: 'text/plain' }], status: 'passed', }; @@ -157,4 +160,11 @@ test('should correctly render links in attachments', async ({ mount }) => { await expect(body).toBeVisible(); await expect(body.locator('a').filter({ hasText: 'playwright.dev' })).toHaveAttribute('href', 'https://playwright.dev/docs/intro'); await expect(body.locator('a').filter({ hasText: 'github.com' })).toHaveAttribute('href', 'https://github.com/microsoft/playwright/issues/31284'); -}); \ No newline at end of file +}); + +test('should correctly render links in attachment name', async ({ mount }) => { + const component = await mount(); + const link = component.getByText('attachment with inline link').locator('a'); + await expect(link).toHaveAttribute('href', 'https://github.com/microsoft/playwright/issues/31284'); + await expect(link).toHaveText('https://github.com/microsoft/playwright/issues/31284'); +}); diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index e4575a8627..c9ce2f7bcd 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -319,7 +319,7 @@ export function formatFailure(config: FullConfig, test: TestCase, options: {inde if (includeAttachments) { for (let i = 0; i < result.attachments.length; ++i) { const attachment = result.attachments[i]; - const hasPrintableContent = attachment.contentType.startsWith('text/') && attachment.body; + const hasPrintableContent = attachment.contentType.startsWith('text/'); if (!attachment.path && !hasPrintableContent) continue; resultLines.push(''); diff --git a/packages/playwright/src/util.ts b/packages/playwright/src/util.ts index d6cabd07c6..a4ddce7a3b 100644 --- a/packages/playwright/src/util.ts +++ b/packages/playwright/src/util.ts @@ -256,6 +256,8 @@ export function resolveReporterOutputPath(defaultValue: string, configDir: strin } export async function normalizeAndSaveAttachment(outputPath: string, name: string, options: { path?: string, body?: string | Buffer, contentType?: string } = {}): Promise<{ name: string; path?: string | undefined; body?: Buffer | undefined; contentType: string; }> { + if (options.path === undefined && options.body === undefined) + return { name, contentType: 'text/plain' }; if ((options.path !== undefined ? 1 : 0) + (options.body !== undefined ? 1 : 0) !== 1) throw new Error(`Exactly one of "path" and "body" must be specified`); if (options.path !== undefined) { diff --git a/tests/playwright-test/reporter-attachment.spec.ts b/tests/playwright-test/reporter-attachment.spec.ts index fd938be437..50d6d1ee0c 100644 --- a/tests/playwright-test/reporter-attachment.spec.ts +++ b/tests/playwright-test/reporter-attachment.spec.ts @@ -99,8 +99,8 @@ test(`testInfo.attach errors`, async ({ runInlineTest }) => { const text = result.output.replace(/\\/g, '/'); expect(text).toMatch(/Error: ENOENT: no such file or directory, copyfile '.*foo.txt.*'/); expect(text).toContain(`Exactly one of "path" and "body" must be specified`); - expect(result.passed).toBe(0); - expect(result.failed).toBe(3); + expect(result.passed).toBe(1); + expect(result.failed).toBe(2); expect(result.exitCode).toBe(1); }); @@ -175,6 +175,21 @@ test(`testInfo.attach allow empty string body`, async ({ runInlineTest }) => { expect(result.output).toMatch(/^.*attachment #1: name \(text\/plain\).*\n.*\n.*──────/gm); }); +test(`testInfo.attach allow without options`, async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('success', async ({}, testInfo) => { + await testInfo.attach('Full name'); + expect(0).toBe(1); + }); + `, + }); + expect(result.exitCode).toBe(1); + expect(result.failed).toBe(1); + expect(result.output).toMatch(/^.*attachment #1: Full name \(text\/plain\).*\n.*──────/gm); +}); + test(`testInfo.attach allow empty buffer body`, async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.test.ts': `