put metadata into context
This commit is contained in:
parent
9d4361b511
commit
13f542c915
|
|
@ -23,15 +23,28 @@ import type { Metadata } from '@playwright/test';
|
||||||
import type { GitCommitInfo } from '@testIsomorphic/types';
|
import type { GitCommitInfo } from '@testIsomorphic/types';
|
||||||
import { CopyToClipboardContainer } from './copyToClipboard';
|
import { CopyToClipboardContainer } from './copyToClipboard';
|
||||||
import { linkifyText } from '@web/renderUtils';
|
import { linkifyText } from '@web/renderUtils';
|
||||||
import { GitCommitInfoContext } from './reportView';
|
|
||||||
|
|
||||||
type MetadataEntries = [string, unknown][];
|
type MetadataEntries = [string, unknown][];
|
||||||
|
|
||||||
export function filterMetadata(metadata: Metadata): { gitCommitInfo?: GitCommitInfo, metadataEntries: MetadataEntries } {
|
export const MetadataContext = React.createContext<MetadataEntries>([]);
|
||||||
return {
|
|
||||||
gitCommitInfo: metadata['git.commit.info'],
|
export function MetadataProvider({ metadata}: React.PropsWithChildren<{ metadata: Metadata }>) {
|
||||||
metadataEntries: Object.entries(metadata).filter(([key]) => key !== 'actualWorkers') // TODO: do not plumb actualWorkers through metadata.
|
const entries = React.useMemo(() => {
|
||||||
};
|
// TODO: do not plumb actualWorkers through metadata.
|
||||||
|
|
||||||
|
return Object.entries(metadata).filter(([key]) => key !== 'actualWorkers')
|
||||||
|
}, [metadata]);
|
||||||
|
|
||||||
|
return <MetadataContext.Provider value={entries} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMetadata() {
|
||||||
|
return React.useContext(MetadataContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGitCommitInfo() {
|
||||||
|
const metadataEntries = useMetadata();
|
||||||
|
return metadataEntries.find(([key]) => key === 'git.commit.info')?.[1] as GitCommitInfo | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ErrorBoundary extends React.Component<React.PropsWithChildren<{}>, { error: Error | null, errorInfo: React.ErrorInfo | null }> {
|
class ErrorBoundary extends React.Component<React.PropsWithChildren<{}>, { error: Error | null, errorInfo: React.ErrorInfo | null }> {
|
||||||
|
|
@ -60,12 +73,13 @@ class ErrorBoundary extends React.Component<React.PropsWithChildren<{}>, { error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MetadataView: React.FC<{ metadataEntries: MetadataEntries }> = ({ metadataEntries }) => {
|
export const MetadataView = () => {
|
||||||
return <ErrorBoundary><InnerMetadataView metadataEntries={metadataEntries}/></ErrorBoundary>;
|
return <ErrorBoundary><InnerMetadataView/></ErrorBoundary>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InnerMetadataView: React.FC<{ metadataEntries: MetadataEntries }> = ({ metadataEntries }) => {
|
const InnerMetadataView = () => {
|
||||||
const gitCommitInfo = React.useContext(GitCommitInfoContext);
|
const metadataEntries = useMetadata();
|
||||||
|
const gitCommitInfo = useGitCommitInfo();
|
||||||
const entries = metadataEntries.filter(([key]) => key !== 'git.commit.info');
|
const entries = metadataEntries.filter(([key]) => key !== 'git.commit.info');
|
||||||
if (!gitCommitInfo && !entries.length)
|
if (!gitCommitInfo && !entries.length)
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { FilteredStats, TestCase, TestCaseSummary, TestFile, TestFileSummary } from './types';
|
import type { FilteredStats, HTMLReport, TestCase, TestCaseSummary, TestFile, TestFileSummary } from './types';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import './colors.css';
|
import './colors.css';
|
||||||
import './common.css';
|
import './common.css';
|
||||||
|
|
@ -26,10 +26,7 @@ import './reportView.css';
|
||||||
import { TestCaseView } from './testCaseView';
|
import { TestCaseView } from './testCaseView';
|
||||||
import { TestFilesHeader, TestFilesView } from './testFilesView';
|
import { TestFilesHeader, TestFilesView } from './testFilesView';
|
||||||
import './theme.css';
|
import './theme.css';
|
||||||
import { filterMetadata } from './metadataView';
|
import { MetadataProvider } from './metadataView';
|
||||||
import type { GitCommitInfo } from '@testIsomorphic/types';
|
|
||||||
|
|
||||||
export const GitCommitInfoContext = React.createContext<GitCommitInfo | undefined>(undefined);
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
@ -54,8 +51,6 @@ export const ReportView: React.FC<{
|
||||||
const [filterText, setFilterText] = React.useState(searchParams.get('q') || '');
|
const [filterText, setFilterText] = React.useState(searchParams.get('q') || '');
|
||||||
const [metadataVisible, setMetadataVisible] = React.useState(false);
|
const [metadataVisible, setMetadataVisible] = React.useState(false);
|
||||||
|
|
||||||
const gitCommitInfo = React.useMemo(() => filterMetadata(report?.json().metadata || {}).gitCommitInfo, [report]);
|
|
||||||
|
|
||||||
const testIdToFileIdMap = React.useMemo(() => {
|
const testIdToFileIdMap = React.useMemo(() => {
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
for (const file of report?.json().files || []) {
|
for (const file of report?.json().files || []) {
|
||||||
|
|
@ -78,7 +73,7 @@ export const ReportView: React.FC<{
|
||||||
return result;
|
return result;
|
||||||
}, [report, filter]);
|
}, [report, filter]);
|
||||||
|
|
||||||
return <GitCommitInfoContext.Provider value={gitCommitInfo}><div className='htmlreport vbox px-4 pb-4'>
|
return <MetadataProvider metadata={report?.json().metadata ?? {}}><div className='htmlreport vbox px-4 pb-4'>
|
||||||
<main>
|
<main>
|
||||||
{report?.json() && <HeaderView stats={report.json().stats} filterText={filterText} setFilterText={setFilterText}></HeaderView>}
|
{report?.json() && <HeaderView stats={report.json().stats} filterText={filterText} setFilterText={setFilterText}></HeaderView>}
|
||||||
<Route predicate={testFilesRoutePredicate}>
|
<Route predicate={testFilesRoutePredicate}>
|
||||||
|
|
@ -94,7 +89,7 @@ export const ReportView: React.FC<{
|
||||||
{!!report && <TestCaseViewLoader report={report} tests={filteredTests.tests} testIdToFileIdMap={testIdToFileIdMap} />}
|
{!!report && <TestCaseViewLoader report={report} tests={filteredTests.tests} testIdToFileIdMap={testIdToFileIdMap} />}
|
||||||
</Route>
|
</Route>
|
||||||
</main>
|
</main>
|
||||||
</div></GitCommitInfoContext.Provider>;
|
</div></MetadataProvider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TestCaseViewLoader: React.FC<{
|
const TestCaseViewLoader: React.FC<{
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ import './testErrorView.css';
|
||||||
import * as icons from './icons';
|
import * as icons from './icons';
|
||||||
import type { ImageDiff } from '@web/shared/imageDiffView';
|
import type { ImageDiff } from '@web/shared/imageDiffView';
|
||||||
import { ImageDiffView } from '@web/shared/imageDiffView';
|
import { ImageDiffView } from '@web/shared/imageDiffView';
|
||||||
import { GitCommitInfoContext } from './reportView';
|
|
||||||
import { TestResult } from './types';
|
import { TestResult } from './types';
|
||||||
import { CopyToClipboard } from './copyToClipboard';
|
import { CopyToClipboard } from './copyToClipboard';
|
||||||
import { fixTestPrompt } from '@web/components/prompts';
|
import { fixTestPrompt } from '@web/components/prompts';
|
||||||
|
import { useGitCommitInfo } from './metadataView';
|
||||||
|
|
||||||
export const TestErrorView: React.FC<{ error: string; testId?: string; result?: TestResult }> = ({ error, testId, result }) => {
|
export const TestErrorView: React.FC<{ error: string; testId?: string; result?: TestResult }> = ({ error, testId, result }) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -49,7 +49,7 @@ const PromptButton: React.FC<{
|
||||||
error: string;
|
error: string;
|
||||||
result?: TestResult;
|
result?: TestResult;
|
||||||
}> = ({ error, result }) => {
|
}> = ({ error, result }) => {
|
||||||
const gitCommitInfo = React.useContext(GitCommitInfoContext);
|
const gitCommitInfo = useGitCommitInfo();
|
||||||
const prompt = React.useMemo(() => fixTestPrompt(
|
const prompt = React.useMemo(() => fixTestPrompt(
|
||||||
error,
|
error,
|
||||||
gitCommitInfo?.['pull.diff'] ?? gitCommitInfo?.['revision.diff'],
|
gitCommitInfo?.['pull.diff'] ?? gitCommitInfo?.['revision.diff'],
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { msToString } from './utils';
|
||||||
import { AutoChip } from './chip';
|
import { AutoChip } from './chip';
|
||||||
import { TestErrorView } from './testErrorView';
|
import { TestErrorView } from './testErrorView';
|
||||||
import * as icons from './icons';
|
import * as icons from './icons';
|
||||||
import { filterMetadata, MetadataView } from './metadataView';
|
import { MetadataView, useMetadata } from './metadataView';
|
||||||
|
|
||||||
export const TestFilesView: React.FC<{
|
export const TestFilesView: React.FC<{
|
||||||
tests: TestFileSummary[],
|
tests: TestFileSummary[],
|
||||||
|
|
@ -69,7 +69,7 @@ export const TestFilesHeader: React.FC<{
|
||||||
}> = ({ report, filteredStats, metadataVisible, toggleMetadataVisible }) => {
|
}> = ({ report, filteredStats, metadataVisible, toggleMetadataVisible }) => {
|
||||||
if (!report)
|
if (!report)
|
||||||
return;
|
return;
|
||||||
const { metadataEntries } = filterMetadata(report.metadata || {});
|
const metadataEntries = useMetadata();
|
||||||
return <>
|
return <>
|
||||||
<div className='mx-1' style={{ display: 'flex', marginTop: 10 }}>
|
<div className='mx-1' style={{ display: 'flex', marginTop: 10 }}>
|
||||||
{metadataEntries.length > 0 && <div className='metadata-toggle' role='button' onClick={toggleMetadataVisible} title={metadataVisible ? 'Hide metadata' : 'Show metadata'}>
|
{metadataEntries.length > 0 && <div className='metadata-toggle' role='button' onClick={toggleMetadataVisible} title={metadataVisible ? 'Hide metadata' : 'Show metadata'}>
|
||||||
|
|
@ -81,7 +81,7 @@ export const TestFilesHeader: React.FC<{
|
||||||
<div data-testid='overall-time' style={{ color: 'var(--color-fg-subtle)', marginRight: '10px' }}>{report ? new Date(report.startTime).toLocaleString() : ''}</div>
|
<div data-testid='overall-time' style={{ color: 'var(--color-fg-subtle)', marginRight: '10px' }}>{report ? new Date(report.startTime).toLocaleString() : ''}</div>
|
||||||
<div data-testid='overall-duration' style={{ color: 'var(--color-fg-subtle)' }}>Total time: {msToString(report.duration ?? 0)}</div>
|
<div data-testid='overall-duration' style={{ color: 'var(--color-fg-subtle)' }}>Total time: {msToString(report.duration ?? 0)}</div>
|
||||||
</div>
|
</div>
|
||||||
{metadataVisible && <MetadataView metadataEntries={metadataEntries}/>}
|
{metadataVisible && <MetadataView/>}
|
||||||
{!!report.errors.length && <AutoChip header='Errors' dataTestId='report-errors'>
|
{!!report.errors.length && <AutoChip header='Errors' dataTestId='report-errors'>
|
||||||
{report.errors.map((error, index) => <TestErrorView key={'test-report-error-message-' + index} error={error}></TestErrorView>)}
|
{report.errors.map((error, index) => <TestErrorView key={'test-report-error-message-' + index} error={error}></TestErrorView>)}
|
||||||
</AutoChip>}
|
</AutoChip>}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue