From a62260a9f2a194f8fdea80266531aa41b2061fa5 Mon Sep 17 00:00:00 2001 From: Joe-Hendley <95080839+Joe-Hendley@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:45:16 +0100 Subject: [PATCH] feat(html report): linkify test annotations (#31521) --- .../html-reporter/src/testCaseView.spec.tsx | 39 +++++++++++++++++++ packages/html-reporter/src/testCaseView.tsx | 34 +++++++++++++--- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/packages/html-reporter/src/testCaseView.spec.tsx b/packages/html-reporter/src/testCaseView.spec.tsx index 28fe8247f5..c306843107 100644 --- a/packages/html-reporter/src/testCaseView.spec.tsx +++ b/packages/html-reporter/src/testCaseView.spec.tsx @@ -74,3 +74,42 @@ test('should render test case', async ({ mount }) => { await expect(component.getByText('test.spec.ts:42')).toBeVisible(); await expect(component.getByText('My test')).toBeVisible(); }); + +const linkRenderingTestCase: TestCase = { + testId: 'testid', + title: 'My test', + path: [], + projectName: 'chromium', + location: { file: 'test.spec.ts', line: 42, column: 0 }, + annotations: [ + { type: 'more info', description: 'read https://playwright.dev/docs/intro and https://playwright.dev/docs/api/class-playwright' }, + { type: 'related issues', description: 'https://github.com/microsoft/playwright/issues/23180, https://github.com/microsoft/playwright/issues/23181' }, + + ], + tags: [], + outcome: 'expected', + duration: 10, + ok: true, + results: [result] +}; + +test('should correctly render links in annotations', async ({ mount }) => { + const component = await mount(); + // const container = await(component.getByText('Annotations')); + + const firstLink = await component.getByText('https://playwright.dev/docs/intro').first(); + await expect(firstLink).toBeVisible(); + await expect(firstLink).toHaveAttribute('href', 'https://playwright.dev/docs/intro'); + + const secondLink = await component.getByText('https://playwright.dev/docs/api/class-playwright').first(); + await expect(secondLink).toBeVisible(); + await expect(secondLink).toHaveAttribute('href', 'https://playwright.dev/docs/api/class-playwright'); + + const thirdLink = await component.getByText('https://github.com/microsoft/playwright/issues/23180').first(); + await expect(thirdLink).toBeVisible(); + await expect(thirdLink).toHaveAttribute('href', 'https://github.com/microsoft/playwright/issues/23180'); + + const fourthLink = await component.getByText('https://github.com/microsoft/playwright/issues/23181').first(); + await expect(fourthLink).toBeVisible(); + await expect(fourthLink).toHaveAttribute('href', 'https://github.com/microsoft/playwright/issues/23181'); +}); \ No newline at end of file diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx index eecbdac9f5..66555598f2 100644 --- a/packages/html-reporter/src/testCaseView.tsx +++ b/packages/html-reporter/src/testCaseView.tsx @@ -65,11 +65,35 @@ export const TestCaseView: React.FC<{ }; function renderAnnotationDescription(description: string) { - try { - if (['http:', 'https:'].includes(new URL(description).protocol)) - return {description}; - } catch {} - return description; + const CONTROL_CODES = '\\u0000-\\u0020\\u007f-\\u009f'; + const WEB_LINK_REGEX = new RegExp('(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|www\\.)[^\\s' + CONTROL_CODES + '"]{2,}[^\\s' + CONTROL_CODES + '"\')}\\],:;.!?]', 'ug'); + + const result = []; + let currentIndex = 0; + let match; + + while ((match = WEB_LINK_REGEX.exec(description)) !== null) { + const stringBeforeMatch = description.substring(currentIndex, match.index); + if (stringBeforeMatch) + result.push(stringBeforeMatch); + + const value = match[0]; + result.push(renderLink(value)); + currentIndex = match.index + value.length; + } + const stringAfterMatches = description.substring(currentIndex); + if (stringAfterMatches) + result.push(stringAfterMatches); + + return result; +} + +function renderLink(text: string) { + let link = text; + if (link.startsWith('www.')) + link = 'https://' + link; + + return {text}; } function TestCaseAnnotationView({ annotation: { type, description } }: { annotation: TestCaseAnnotation }) {