chore(html-reporter) rework setting favicon and page title

This commit is contained in:
Ryan Rosello 2024-07-09 21:53:59 +10:00
parent 863ae531fd
commit fefea60857
6 changed files with 54 additions and 18 deletions

View file

@ -21,7 +21,6 @@
<meta name='color-scheme' content='dark light'> <meta name='color-scheme' content='dark light'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>Playwright Test Report | Summary</title> <title>Playwright Test Report | Summary</title>
<link rel="icon" href="/logo_default.svg">
</head> </head>
<body> <body>
<div id='root'></div> <div id='root'></div>

View file

@ -23,6 +23,7 @@ import * as icons from './icons';
import { Link, navigate } from './links'; import { Link, navigate } from './links';
import { statusIcon } from './statusIcon'; import { statusIcon } from './statusIcon';
import { filterWithToken } from './filter'; import { filterWithToken } from './filter';
import { setDefaultFavIconAndTitle } from './uiUtils';
export const HeaderView: React.FC<React.PropsWithChildren<{ export const HeaderView: React.FC<React.PropsWithChildren<{
stats: Stats, stats: Stats,
@ -33,6 +34,7 @@ export const HeaderView: React.FC<React.PropsWithChildren<{
const popstateFn = () => { const popstateFn = () => {
const params = new URLSearchParams(window.location.hash.slice(1)); const params = new URLSearchParams(window.location.hash.slice(1));
setFilterText(params.get('q') || ''); setFilterText(params.get('q') || '');
setDefaultFavIconAndTitle();
}; };
window.addEventListener('popstate', popstateFn); window.addEventListener('popstate', popstateFn);

View file

@ -23,6 +23,7 @@ import * as ReactDOM from 'react-dom';
import './colors.css'; import './colors.css';
import type { LoadedReport } from './loadedReport'; import type { LoadedReport } from './loadedReport';
import { ReportView } from './reportView'; import { ReportView } from './reportView';
import { setDefaultFavIconAndTitle } from './uiUtils';
// @ts-ignore // @ts-ignore
const zipjs = zipImport as typeof zip; const zipjs = zipImport as typeof zip;
@ -34,6 +35,10 @@ const ReportLoader: React.FC = () => {
const zipReport = new ZipReport(); const zipReport = new ZipReport();
zipReport.load().then(() => setReport(zipReport)); zipReport.load().then(() => setReport(zipReport));
}, [report]); }, [report]);
React.useEffect(() => {
setDefaultFavIconAndTitle();
}, []);
return <ReportView report={report}></ReportView>; return <ReportView report={report}></ReportView>;
}; };

View file

@ -79,14 +79,14 @@ test('should render test case', async ({ mount }) => {
test('should correctly set the page title and favicon', async ({ mount, page }) => { test('should correctly set the page title and favicon', async ({ mount, page }) => {
await mount(<TestCaseView projectNames={['chromium', 'webkit']} test={testCase} run={0} anchor=''></TestCaseView>); await mount(<TestCaseView projectNames={['chromium', 'webkit']} test={testCase} run={0} anchor=''></TestCaseView>);
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}`); expect(await page.title()).toEqual(`| ${testCase.title}`);
}); });
test('should fallback to default title and favicon', async ({ mount, page }) => { test('should fallback to default title and favicon', async ({ mount, page }) => {
await mount(<TestCaseView projectNames={['chromium', 'webkit']} test={undefined} run={0} anchor=''></TestCaseView>); await mount(<TestCaseView projectNames={['chromium', 'webkit']} test={undefined} run={0} anchor=''></TestCaseView>);
expect(await page.locator('link[rel="icon"]').getAttribute('href')).toEqual('../logo_default.svg'); 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'); expect(await page.title()).toEqual('Playwright Test Report | Summary');
}); });
const linkRenderingTestCase: TestCase = { const linkRenderingTestCase: TestCase = {

View file

@ -14,7 +14,7 @@
limitations under the License. limitations under the License.
*/ */
import type { TestCase, TestCaseAnnotation, TestCaseSummary } from './types'; import type { TestCase, TestCaseAnnotation } from './types';
import * as React from 'react'; import * as React from 'react';
import { TabbedPane } from './tabbedPane'; import { TabbedPane } from './tabbedPane';
import { AutoChip } from './chip'; import { AutoChip } from './chip';
@ -24,7 +24,7 @@ import { statusIcon } from './statusIcon';
import './testCaseView.css'; import './testCaseView.css';
import { TestResultView } from './testResultView'; import { TestResultView } from './testResultView';
import { hashStringToInt } from './labelUtils'; import { hashStringToInt } from './labelUtils';
import { msToString } from './uiUtils'; import { msToString, setDefaultFavIconAndTitle, setFavIcon } from './uiUtils';
export const TestCaseView: React.FC<{ export const TestCaseView: React.FC<{
projectNames: string[], projectNames: string[],
@ -46,9 +46,9 @@ export const TestCaseView: React.FC<{
React.useEffect(() => { React.useEffect(() => {
document.title = test?.title ? `| ${test.title}` : 'Playwright Test Report'; 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 = () => { const resetFaviconOnBack = () => {
setFavicon('default'); setDefaultFavIconAndTitle();
}; };
window.addEventListener('popstate', resetFaviconOnBack); window.addEventListener('popstate', resetFaviconOnBack);
@ -144,13 +144,3 @@ const LabelsLinkView: React.FC<React.PropsWithChildren<{
) : null; ) : null;
}; };
function setFavicon(outcome: Pick<TestCaseSummary, 'outcome'> | '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`;
}

View file

@ -13,6 +13,12 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. 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 { export function msToString(ms: number): string {
if (!isFinite(ms)) if (!isFinite(ms))
@ -39,3 +45,37 @@ export function msToString(ms: number): string {
const days = hours / 24; const days = hours / 24;
return days.toFixed(1) + 'd'; return days.toFixed(1) + 'd';
} }
export function setFavIcon(outcome: Pick<TestCaseSummary, 'outcome'>) {
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;
}