diff --git a/packages/html-reporter/index.html b/packages/html-reporter/index.html index 970a975b12..6a52233a36 100644 --- a/packages/html-reporter/index.html +++ b/packages/html-reporter/index.html @@ -21,7 +21,6 @@ Playwright Test Report | Summary -
diff --git a/packages/html-reporter/src/headerView.tsx b/packages/html-reporter/src/headerView.tsx index 925bc64721..fa341dd5c3 100644 --- a/packages/html-reporter/src/headerView.tsx +++ b/packages/html-reporter/src/headerView.tsx @@ -23,6 +23,7 @@ import * as icons from './icons'; import { Link, navigate } from './links'; import { statusIcon } from './statusIcon'; import { filterWithToken } from './filter'; +import { setDefaultFavIconAndTitle } from './uiUtils'; export const HeaderView: React.FC { const params = new URLSearchParams(window.location.hash.slice(1)); setFilterText(params.get('q') || ''); + setDefaultFavIconAndTitle(); }; window.addEventListener('popstate', popstateFn); diff --git a/packages/html-reporter/src/index.tsx b/packages/html-reporter/src/index.tsx index 683113f32a..062cab5d48 100644 --- a/packages/html-reporter/src/index.tsx +++ b/packages/html-reporter/src/index.tsx @@ -23,6 +23,7 @@ import * as ReactDOM from 'react-dom'; import './colors.css'; import type { LoadedReport } from './loadedReport'; import { ReportView } from './reportView'; +import { setDefaultFavIconAndTitle } from './uiUtils'; // @ts-ignore const zipjs = zipImport as typeof zip; @@ -34,6 +35,10 @@ const ReportLoader: React.FC = () => { const zipReport = new ZipReport(); zipReport.load().then(() => setReport(zipReport)); }, [report]); + + React.useEffect(() => { + setDefaultFavIconAndTitle(); + }, []); return ; }; diff --git a/packages/html-reporter/src/testCaseView.spec.tsx b/packages/html-reporter/src/testCaseView.spec.tsx index edfa6f7bc6..fdf99703fe 100644 --- a/packages/html-reporter/src/testCaseView.spec.tsx +++ b/packages/html-reporter/src/testCaseView.spec.tsx @@ -79,14 +79,14 @@ test('should render test case', async ({ mount }) => { test('should correctly set the page title and favicon', async ({ mount, page }) => { await mount(); - expect(await page.locator('link[rel="icon"]').getAttribute('href')).toEqual('../logo_expected.svg'); + expect(await page.locator('link[rel="icon"]').getAttribute('href')).toMatch(/\/assets\/logo_expected-[A-Za-z0-9]+\.svg/); expect(await page.title()).toEqual(`| ${testCase.title}`); }); test('should fallback to default title and favicon', async ({ mount, page }) => { await mount(); - expect(await page.locator('link[rel="icon"]').getAttribute('href')).toEqual('../logo_default.svg'); - expect(await page.title()).toEqual('Playwright Test Report'); + expect(await page.locator('link[rel="icon"]').getAttribute('href')).toMatch(/\/assets\/logo_default-[A-Za-z0-9]+\.svg/); + expect(await page.title()).toEqual('Playwright Test Report | Summary'); }); const linkRenderingTestCase: TestCase = { diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx index 81311edecc..a0a4477822 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, TestCaseAnnotation, TestCaseSummary } from './types'; +import type { TestCase, TestCaseAnnotation } from './types'; import * as React from 'react'; import { TabbedPane } from './tabbedPane'; import { AutoChip } from './chip'; @@ -24,7 +24,7 @@ import { statusIcon } from './statusIcon'; import './testCaseView.css'; import { TestResultView } from './testResultView'; import { hashStringToInt } from './labelUtils'; -import { msToString } from './uiUtils'; +import { msToString, setDefaultFavIconAndTitle, setFavIcon } from './uiUtils'; export const TestCaseView: React.FC<{ projectNames: string[], @@ -46,9 +46,9 @@ export const TestCaseView: React.FC<{ React.useEffect(() => { document.title = test?.title ? `| ${test.title}` : 'Playwright Test Report'; - test?.outcome ? setFavicon({ outcome: test.outcome }) : setFavicon('default'); + test?.outcome ? setFavIcon({ outcome: test.outcome }) : setDefaultFavIconAndTitle(); const resetFaviconOnBack = () => { - setFavicon('default'); + setDefaultFavIconAndTitle(); }; window.addEventListener('popstate', resetFaviconOnBack); @@ -144,13 +144,3 @@ const LabelsLinkView: React.FC | 'default') { - let link: HTMLLinkElement | null = document.querySelector("link[rel*='icon']"); - if (!link) { - link = document.createElement('link'); - link.rel = 'icon'; - document.getElementsByTagName('head')[0].appendChild(link); - } - const outcomeValue = outcome instanceof Object ? outcome.outcome : outcome; - link.href = `../logo_${outcomeValue}.svg`; -} \ No newline at end of file diff --git a/packages/html-reporter/src/uiUtils.ts b/packages/html-reporter/src/uiUtils.ts index 00022b4204..571b7e3e81 100644 --- a/packages/html-reporter/src/uiUtils.ts +++ b/packages/html-reporter/src/uiUtils.ts @@ -13,6 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. */ +import favIconExpected from '../logo_expected.svg'; +import favIconDefault from '../logo_default.svg'; +import favIconUnExpected from '../logo_unexpected.svg'; +import favIconSkipped from '../logo_skipped.svg'; +import favIconFlaky from '../logo_flaky.svg'; +import type { TestCaseSummary } from './types'; export function msToString(ms: number): string { if (!isFinite(ms)) @@ -39,3 +45,37 @@ export function msToString(ms: number): string { const days = hours / 24; return days.toFixed(1) + 'd'; } + +export function setFavIcon(outcome: Pick) { + const link: HTMLLinkElement | null = getLinkIconElement(); + const outcomeValue = outcome.outcome; + + if (outcomeValue === 'expected') { + link.href = favIconExpected; + } else if (outcomeValue === 'unexpected') { + link.href = favIconUnExpected; + } else if (outcomeValue === 'skipped') { + link.href = favIconSkipped; + } else if (outcomeValue === 'flaky') { + link.href = favIconFlaky; + } else { + link.href = favIconDefault; + document.title = 'Playwright Test Report | Summary'; + } +} + +export function setDefaultFavIconAndTitle() { + const link: HTMLLinkElement | null = getLinkIconElement(); + link.href = favIconDefault; + document.title = 'Playwright Test Report | Summary'; +} + +function getLinkIconElement() { + let link: HTMLLinkElement | null = document.querySelector("link[rel*='icon']"); + if (!link) { + link = document.createElement('link'); + link.rel = 'icon'; + document.getElementsByTagName('head')[0].appendChild(link); + } + return link; +} \ No newline at end of file