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='viewport' content='width=device-width, initial-scale=1.0'>
<title>Playwright Test Report | Summary</title>
<link rel="icon" href="/logo_default.svg">
</head>
<body>
<div id='root'></div>

View file

@ -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<React.PropsWithChildren<{
stats: Stats,
@ -33,6 +34,7 @@ export const HeaderView: React.FC<React.PropsWithChildren<{
const popstateFn = () => {
const params = new URLSearchParams(window.location.hash.slice(1));
setFilterText(params.get('q') || '');
setDefaultFavIconAndTitle();
};
window.addEventListener('popstate', popstateFn);

View file

@ -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 <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 }) => {
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}`);
});
test('should fallback to default title and favicon', async ({ mount, page }) => {
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.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 = {

View file

@ -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<React.PropsWithChildren<{
) : 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
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<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;
}