mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore(html-report): render metainfo as a chip (#13166)
This commit is contained in:
parent
a9989852d5
commit
81e7c0a77c
100
packages/html-reporter/src/metadataView.tsx
Normal file
100
packages/html-reporter/src/metadataView.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import './colors.css';
|
||||
import './common.css';
|
||||
import * as icons from './icons';
|
||||
import { Metadata } from './index';
|
||||
import { AutoChip } from './chip';
|
||||
import './reportView.css';
|
||||
import './theme.css';
|
||||
|
||||
export const MetadataView: React.FC<Metadata> = metadata => {
|
||||
return (
|
||||
<AutoChip header={
|
||||
<span>
|
||||
{metadata['revision.id'] && <span style={{ float: 'right', fontFamily: 'var(--monospace-font)' }}>
|
||||
{metadata['revision.id'].slice(0, 7)}
|
||||
</span>}
|
||||
{metadata['revision.subject'] && metadata['revision.subject'] || 'no subject>'}
|
||||
{!metadata['revision.subject'] && 'Commit metainfo'}
|
||||
</span>} initialExpanded={false}>
|
||||
{metadata['revision.subject'] &&
|
||||
<MetadatViewItem
|
||||
testId='revision.subject'
|
||||
content={<span>{metadata['revision.subject']}</span>}
|
||||
/>
|
||||
}
|
||||
{metadata['revision.id'] &&
|
||||
<MetadatViewItem
|
||||
testId='revision.id'
|
||||
content={<span style={{ fontFamily: 'var(--monospace-font)' }}>{metadata['revision.id']}</span>}
|
||||
href={metadata['revision.link']}
|
||||
icon='commit'
|
||||
/>
|
||||
}
|
||||
{(metadata['revision.author'] || metadata['revision.email']) &&
|
||||
<MetadatViewItem
|
||||
content={(
|
||||
metadata['revision.author'] && metadata['revision.email']
|
||||
? <>{metadata['revision.author']} {metadata['revision.email']}</>
|
||||
: (metadata['revision.author'] || metadata['revision.email'])
|
||||
)!}
|
||||
icon='person'
|
||||
/>
|
||||
}
|
||||
{metadata['revision.timestamp'] &&
|
||||
<MetadatViewItem
|
||||
testId='revision.timestamp'
|
||||
content={
|
||||
<>
|
||||
{Intl.DateTimeFormat(undefined, { dateStyle: 'full' }).format(metadata['revision.timestamp'])}
|
||||
{Intl.DateTimeFormat(undefined, { timeStyle: 'long' }).format(metadata['revision.timestamp'])}
|
||||
</>
|
||||
}
|
||||
icon='calendar'
|
||||
/>
|
||||
}
|
||||
{metadata['ci.link'] &&
|
||||
<MetadatViewItem
|
||||
content='CI/CD Logs'
|
||||
href={metadata['ci.link']}
|
||||
icon='externalLink'
|
||||
/>
|
||||
}
|
||||
{metadata['generatedAt'] &&
|
||||
<MetadatViewItem
|
||||
content={<span style={{ color: 'var(--color-fg-subtle)' }}>
|
||||
Report generated on {Intl.DateTimeFormat(undefined, { dateStyle: 'full', timeStyle: 'long' }).format(metadata['generatedAt'])}
|
||||
</span>}></MetadatViewItem>
|
||||
}
|
||||
</AutoChip>
|
||||
);
|
||||
};
|
||||
|
||||
const MetadatViewItem: React.FC<{ content: JSX.Element | string; icon?: keyof typeof icons, href?: string, testId?: string }> = ({ content, icon, href, testId }) => {
|
||||
return (
|
||||
<div className='my-1 hbox' data-test-id={testId} >
|
||||
<div className='mr-2'>
|
||||
{icons[icon || 'blank']()}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
{href ? <a href={href} target='_blank' rel='noopener noreferrer'>{content}</a> : content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -24,6 +24,7 @@ html, body {
|
||||
|
||||
body {
|
||||
overflow: auto;
|
||||
max-width: 1024px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
@ -32,58 +33,8 @@ body {
|
||||
border-top: 1px solid var(--color-border-default);
|
||||
}
|
||||
|
||||
.htmlreport {
|
||||
gap: 24px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.htmlreport header {
|
||||
width: 300px;
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.htmlreport main {
|
||||
max-width: 1024px;
|
||||
width: 100%;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.metadata-view a {
|
||||
color: var(--color-accent-fg);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.metadata-view a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.metadata-view h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.report {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 900px) {
|
||||
.htmlreport {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.htmlreport header {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.htmlreport main {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,10 @@ import { HeaderView } from './headerView';
|
||||
import { Route } from './links';
|
||||
import { LoadedReport } from './loadedReport';
|
||||
import './reportView.css';
|
||||
import { MetadataView } from './metadataView';
|
||||
import { TestCaseView } from './testCaseView';
|
||||
import { TestFilesView } from './testFilesView';
|
||||
import './theme.css';
|
||||
import * as icons from './icons';
|
||||
import { Metadata } from './index';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -45,10 +44,9 @@ export const ReportView: React.FC<{
|
||||
const filter = React.useMemo(() => Filter.parse(filterText), [filterText]);
|
||||
|
||||
return <div className='htmlreport vbox px-4 pb-4'>
|
||||
|
||||
{report?.json().metadata && <MetadataView {...report?.json().metadata!} />}
|
||||
<main>
|
||||
{report?.json() && <HeaderView stats={report.json().stats} filterText={filterText} setFilterText={setFilterText}></HeaderView>}
|
||||
{report?.json().metadata && <MetadataView {...report?.json().metadata!} />}
|
||||
<Route params=''>
|
||||
<TestFilesView report={report?.json()} filter={filter} expandedFiles={expandedFiles} setExpandedFiles={setExpandedFiles}></TestFilesView>
|
||||
</Route>
|
||||
@ -62,68 +60,6 @@ export const ReportView: React.FC<{
|
||||
</div>;
|
||||
};
|
||||
|
||||
const MetadataView: React.FC<Metadata> = metadata => {
|
||||
return (
|
||||
<header className='metadata-view pt-3'>
|
||||
<h1>{metadata['revision.subject'] || 'Playwright Test Report'}</h1>
|
||||
{metadata['revision.id'] &&
|
||||
<MetadatViewItem
|
||||
testId='revision.id'
|
||||
content={<span style={{ fontFamily: 'monospace' }}>{metadata['revision.id'].slice(0, 7)}</span>}
|
||||
href={metadata['revision.link']}
|
||||
icon='commit'
|
||||
/>
|
||||
}
|
||||
{(metadata['revision.author'] || metadata['revision.email']) &&
|
||||
<MetadatViewItem
|
||||
content={(
|
||||
metadata['revision.author'] && metadata['revision.email']
|
||||
? <>{metadata['revision.author']}<br/>{metadata['revision.email']}</>
|
||||
: (metadata['revision.author'] || metadata['revision.email'])
|
||||
)!}
|
||||
icon='person'
|
||||
/>
|
||||
}
|
||||
{metadata['revision.timestamp'] &&
|
||||
<MetadatViewItem
|
||||
testId='revision.timestamp'
|
||||
content={
|
||||
<>
|
||||
{Intl.DateTimeFormat(undefined, { dateStyle: 'full' }).format(metadata['revision.timestamp'])}
|
||||
<br />
|
||||
{Intl.DateTimeFormat(undefined, { timeStyle: 'long' }).format(metadata['revision.timestamp'])}
|
||||
</>
|
||||
}
|
||||
icon='calendar'
|
||||
/>
|
||||
}
|
||||
{metadata['ci.link'] &&
|
||||
<MetadatViewItem
|
||||
content='CI/CD Logs'
|
||||
href={metadata['ci.link']}
|
||||
icon='externalLink'
|
||||
/>
|
||||
}
|
||||
{metadata['generatedAt'] &&
|
||||
<p style={{ fontStyle: 'italic', color: 'var(--color-fg-subtle)' }}>Report generated on {Intl.DateTimeFormat(undefined, { dateStyle: 'full', timeStyle: 'long' }).format(metadata['generatedAt'])}</p>
|
||||
}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
const MetadatViewItem: React.FC<{ content: JSX.Element | string; icon: keyof typeof icons, href?: string, testId?: string }> = ({ content, icon, href, testId }) => {
|
||||
return (
|
||||
<div className='mt-2 hbox' data-test-id={testId} >
|
||||
<div className='mr-2'>
|
||||
{icons[icon]()}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
{href ? <a href={href} target='_blank' rel='noopener noreferrer'>{content}</a> : content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TestCaseViewLoader: React.FC<{
|
||||
report: LoadedReport,
|
||||
}> = ({ report }) => {
|
||||
|
@ -703,13 +703,13 @@ test('should include metadata', async ({ runInlineTest, showReport, page }) => {
|
||||
await showReport();
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
const metadata = page.locator('.metadata-view');
|
||||
await expect.soft(metadata.locator('data-test-id=revision.id')).toContainText(/^[a-f\d]{7}$/i);
|
||||
await expect.soft(metadata.locator('data-test-id=revision.id >> a')).toHaveAttribute('href', 'https://playwright.dev/microsoft/playwright-example-for-test/commit/example-sha');
|
||||
await expect.soft(metadata.locator('data-test-id=revision.timestamp')).toContainText(/AM|PM/);
|
||||
await expect.soft(metadata).toContainText('awesome commit message');
|
||||
await expect.soft(metadata).toContainText('William');
|
||||
await expect.soft(metadata).toContainText('shakespeare@example.local');
|
||||
await expect.soft(metadata.locator('text=CI/CD Logs')).toHaveAttribute('href', 'https://playwright.dev/microsoft/playwright-example-for-test/actions/runs/example-run-id');
|
||||
await expect.soft(metadata.locator('text=Report generated on')).toContainText(/AM|PM/);
|
||||
await page.click('text=awesome commit message');
|
||||
await expect.soft(page.locator('data-test-id=revision.id')).toContainText(/^[a-f\d]+$/i);
|
||||
await expect.soft(page.locator('data-test-id=revision.id >> a')).toHaveAttribute('href', 'https://playwright.dev/microsoft/playwright-example-for-test/commit/example-sha');
|
||||
await expect.soft(page.locator('data-test-id=revision.timestamp')).toContainText(/AM|PM/);
|
||||
await expect.soft(page.locator('text=awesome commit message')).toHaveCount(2);
|
||||
await expect.soft(page.locator('text=William')).toBeVisible();
|
||||
await expect.soft(page.locator('text=shakespeare@example.local')).toBeVisible();
|
||||
await expect.soft(page.locator('text=CI/CD Logs')).toHaveAttribute('href', 'https://playwright.dev/microsoft/playwright-example-for-test/actions/runs/example-run-id');
|
||||
await expect.soft(page.locator('text=Report generated on')).toContainText(/AM|PM/);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user