diff --git a/src/test/reporters/html.ts b/src/test/reporters/html.ts index 91028169af..6040a9a2aa 100644 --- a/src/test/reporters/html.ts +++ b/src/test/reporters/html.ts @@ -22,7 +22,7 @@ import { formatError, formatResultFailure } from './base'; import { serializePatterns, toPosixPath } from './json'; export type JsonStats = { expected: number, unexpected: number, flaky: number, skipped: number }; -export type JsonLocation = Location; +export type JsonLocation = Location & { sha1?: string }; export type JsonStackFrame = { file: string, line: number, column: number, sha1?: string }; export type JsonConfig = Omit & { @@ -158,13 +158,14 @@ class HtmlReporter { fs.writeFileSync(path.join(this._reportFolder, 'report.json'), JSON.stringify(output)); } - private _relativeLocation(location: Location | undefined): Location { + private _relativeLocation(location: Location | undefined): JsonLocation { if (!location) return { file: '', line: 0, column: 0 }; return { file: toPosixPath(path.relative(this.config.rootDir, location.file)), line: location.line, column: location.column, + sha1: this._sourceProcessor.copySourceFile(location.file), }; } @@ -312,7 +313,7 @@ class SourceProcessor { return { stack: frames, preview }; } - private copySourceFile(file: string): string | undefined { + copySourceFile(file: string): string | undefined { let sha1: string | undefined; if (this.sha1Cache.has(file)) { sha1 = this.sha1Cache.get(file); diff --git a/src/web/htmlReport/htmlReport.css b/src/web/htmlReport/htmlReport.css index a04531173a..833108d297 100644 --- a/src/web/htmlReport/htmlReport.css +++ b/src/web/htmlReport/htmlReport.css @@ -52,7 +52,7 @@ padding: 5px; overflow: auto; margin: 20px 0; - flex: none; + flex: auto; } .status-icon { @@ -177,3 +177,7 @@ text-decoration: underline; cursor: pointer; } + +.test-details-column { + overflow-y: auto; +} diff --git a/src/web/htmlReport/htmlReport.tsx b/src/web/htmlReport/htmlReport.tsx index e780bade76..7754727150 100644 --- a/src/web/htmlReport/htmlReport.tsx +++ b/src/web/htmlReport/htmlReport.tsx @@ -183,6 +183,21 @@ const TestResultDetails: React.FC<{ test: JsonTestCase | undefined, result: JsonTestResult | undefined, }> = ({ test, result }) => { + const [selectedTab, setSelectedTab] = React.useState('errors'); + const [source, setSource] = React.useState({ text: '', language: 'javascript' }); + React.useEffect(() => { + (async () => { + if (!test || !test.location.sha1) + return; + try { + const response = await fetch('resources/' + test.location.sha1); + const text = await response.text(); + setSource({ text, language: 'javascript', highlight: [{ line: test.location.line, type: 'paused' }], revealLine: test.location.line }); + } catch (e) { + setSource({ text: '', language: 'javascript' }); + } + })(); + }, [test]); const { screenshots, video, attachmentsMap } = React.useMemo(() => { const attachmentsMap = new Map(); const attachments = result?.attachments || []; @@ -194,20 +209,40 @@ const TestResultDetails: React.FC<{ }, [ result ]); if (!result) return
; - return
- {result.failureSnippet &&
Test error
} - {result.failureSnippet &&
} - {attachmentsMap.has('expected') && attachmentsMap.has('actual') && } - {!!screenshots.length &&
Screenshots
} - {screenshots.map(a =>
)} - {!!video.length &&
Video
} - {video.map(a =>
- -
)} - {!!result.attachments &&
Attachments
} - {result.attachments.map(a => )} + return
+ { + return
+
+ {attachmentsMap.has('expected') && attachmentsMap.has('actual') && } +
; + } + }, + { + id: 'results', + title: 'Results', + render: () => { + return
+ {screenshots.map(a =>
)} + {video.map(a =>
+ +
)} + {!!result.attachments &&
Attachments
} + {result.attachments.map(a => )} +
; + } + }, + { + id: 'source', + title: 'Source', + render: () => + } + ]}>
; };