From f3a46f7405d54af0ead532b44f0bd7113846d018 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 23 Feb 2023 21:57:02 +0100 Subject: [PATCH] feat(html): render annotations as links if needed (#21165) Fixes https://github.com/microsoft/playwright/issues/20584 --- packages/html-reporter/src/testCaseView.tsx | 24 ++++++++++++++++----- packages/html-reporter/src/types.ts | 4 +++- tests/playwright-test/reporter-html.spec.ts | 24 +++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx index 089f15a49c..08f1523dc6 100644 --- a/packages/html-reporter/src/testCaseView.tsx +++ b/packages/html-reporter/src/testCaseView.tsx @@ -14,7 +14,7 @@ limitations under the License. */ -import type { TestCase } from './types'; +import type { TestCase, TestCaseAnnotation } from './types'; import * as React from 'react'; import { TabbedPane } from './tabbedPane'; import { AutoChip } from './chip'; @@ -38,10 +38,7 @@ export const TestCaseView: React.FC<{ {test &&
{test.location.file}:{test.location.line}
} {test && !!test.projectName && } {test && !!test.annotations.length && - {test.annotations.map(a =>
- {a.type} - {a.description && : {a.description}} -
)} + {test.annotations.map(annotation => )}
} {test && ({ @@ -52,6 +49,23 @@ export const TestCaseView: React.FC<{ ; }; +function renderAnnotationDescription(description: string) { + try { + if (['http:', 'https:'].includes(new URL(description).protocol)) + return {description}; + } catch {} + return description; +} + +function TestCaseAnnotationView({ annotation: { type, description } }: { annotation: TestCaseAnnotation }) { + return ( +
+ {type} + {description && : {renderAnnotationDescription(description)}} +
+ ); +} + function retryLabel(index: number) { if (!index) return 'Run'; diff --git a/packages/html-reporter/src/types.ts b/packages/html-reporter/src/types.ts index 5ecbb00086..d7bd68e412 100644 --- a/packages/html-reporter/src/types.ts +++ b/packages/html-reporter/src/types.ts @@ -52,13 +52,15 @@ export type TestFileSummary = { stats: Stats; }; +export type TestCaseAnnotation = { type: string, description?: string }; + export type TestCaseSummary = { testId: string, title: string; path: string[]; projectName: string; location: Location; - annotations: { type: string, description?: string }[]; + annotations: TestCaseAnnotation[]; outcome: 'skipped' | 'expected' | 'unexpected' | 'flaky'; duration: number; ok: boolean; diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 8b40898398..bf63c86d71 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -577,6 +577,30 @@ test('should render annotations', async ({ runInlineTest, page, showReport }) => await expect(page.locator('.test-case-annotation')).toHaveText('skip: I am not interested in this test'); }); +test('should render annotations as link if needed', async ({ runInlineTest, page, showReport, server }) => { + const result = await runInlineTest({ + 'playwright.config.js': ` + module.exports = { timeout: 1500 }; + `, + 'a.test.js': ` + import { test, expect } from '@playwright/test'; + test('pass test', async ({ page }) => { + test.info().annotations.push({ type: 'issue', description: '${server.EMPTY_PAGE}' }); + }); + `, + }, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + + await showReport(); + await page.getByText('pass test').click(); + await expect(page.locator('.test-case-annotation')).toHaveText(`issue: ${server.EMPTY_PAGE}`); + const popupPromise = page.waitForEvent('popup'); + await page.getByRole('link', { name: server.EMPTY_PAGE }).click(); + const popup = await popupPromise; + expect(popup.url()).toBe(server.EMPTY_PAGE); +}); + test('should render text attachments as text', async ({ runInlineTest, page, showReport }) => { const result = await runInlineTest({ 'a.test.js': `