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 }) {