From 6b371f83f2ee9874cadea78a569005bb3b436e8d Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 1 Sep 2021 14:35:11 -0700 Subject: [PATCH] chore: few html report tweaks (#8631) --- src/web/htmlReport/htmlReport.css | 70 ++++++++++++++------ src/web/htmlReport/htmlReport.tsx | 106 +++++++++++++++++------------- 2 files changed, 110 insertions(+), 66 deletions(-) diff --git a/src/web/htmlReport/htmlReport.css b/src/web/htmlReport/htmlReport.css index bbd73b5d6c..a04531173a 100644 --- a/src/web/htmlReport/htmlReport.css +++ b/src/web/htmlReport/htmlReport.css @@ -14,7 +14,7 @@ limitations under the License. */ -.suite-tree { +.suite-tree-column { line-height: 18px; flex: auto; overflow: auto; @@ -31,28 +31,19 @@ min-height: 18px; } -.suite-tree .tree-item-title:not(.selected):hover { +.suite-tree-column .tree-item-title:not(.selected):hover { background-color: #e8e8e8; } -.suite-tree .tree-item-title.selected { +.suite-tree-column .tree-item-title.selected { background-color: #0060c0; color: white; } -.suite-tree .tree-item-title.selected * { +.suite-tree-column .tree-item-title.selected * { color: white !important; } - -.test-case { - flex: auto; -} - -.test-case .tab-content { - overflow: auto; -} - .error-message { white-space: pre; font-family: monospace; @@ -88,6 +79,8 @@ .test-result { flex: auto; display: flex; + flex-direction: column; + padding-right: 8px; } .test-overview-title { @@ -109,11 +102,6 @@ max-height: 500px; } -.test-result .tabbed-pane { - margin-top: 50px; - width: 550px; -} - .image-preview { position: relative; display: flex; @@ -137,15 +125,55 @@ margin-left: 24px; } -.steps-tree .tree-item-title:not(.selected):hover { +.test-result .tree-item-title:not(.selected):hover { background-color: #e8e8e8; } -.steps-tree .tree-item-title.selected { +.test-result .tree-item-title.selected { background-color: #0060c0; color: white; } -.steps-tree .tree-item-title.selected * { +.test-result .tree-item-title.selected * { color: white !important; } + +.suite-tree-column .tab-strip, +.test-case-column .tab-strip { + border: none; + box-shadow: none; + background-color: transparent; +} + +.suite-tree-column .tab-element, +.test-case-column .tab-element { + border: none; + text-transform: uppercase; + font-weight: bold; + font-size: 11px; + color: #aaa; +} + +.suite-tree-column .tab-element.selected, +.test-case-column .tab-element.selected { + color: #555; +} + +.test-case-title { + flex: none; + display: flex; + align-items: center; + padding: 10px; + font-size: 18px; + cursor: pointer; +} + +.test-case-location { + flex: none; + display: flex; + align-items: center; + padding: 0 10px 10px; + color: var(--blue); + text-decoration: underline; + cursor: pointer; +} diff --git a/src/web/htmlReport/htmlReport.tsx b/src/web/htmlReport/htmlReport.tsx index 576bb255b2..e780bade76 100644 --- a/src/web/htmlReport/htmlReport.tsx +++ b/src/web/htmlReport/htmlReport.tsx @@ -53,7 +53,7 @@ export const Report: React.FC = () => { return
-
+
{ (['Failing', 'All'] as Filter[]).map(item => { const selected = item === filter; @@ -145,54 +145,55 @@ const TestTreeItem: React.FC<{ }; const TestCaseView: React.FC<{ - test?: JsonTestCase, + test: JsonTestCase | undefined, }> = ({ test }) => { - const [selectedTab, setSelectedTab] = React.useState('0'); - return
- { !test &&
} - { test && ({ - id: String(index), - title:
{statusIcon(result.status)} {retryLabel(index)}
, - render: () => - })) || []} selectedTab={selectedTab} setSelectedTab={setSelectedTab} /> } -
; -}; - -const TestOverview: React.FC<{ - test: JsonTestCase, - result: JsonTestResult, -}> = ({ test, result }) => { - const [selectedStep, setSelectedStep] = React.useState(); - return
- + const [selectedResultIndex, setSelectedResultIndex] = React.useState(0); + const [selectedStep, setSelectedStep] = React.useState(undefined); + const result = test?.results[selectedResultIndex]; + return +
{!selectedStep && } {!!selectedStep && } -
- {renderLocation(test.location, true)} › {test?.title} ({msToString(result.duration)})
} - depth={0} - key='test' - onClick={() => setSelectedStep(undefined)}> - - {result.steps.map((step, i) => )} -
-
+
+
+ { test &&
setSelectedStep(undefined)}>{test?.title}
} + { test &&
setSelectedStep(undefined)}>{renderLocation(test.location, true)}
} + { test && ({ + id: String(index), + title:
{statusIcon(result.status)} {retryLabel(index)}
, + render: () => + })) || []} selectedTab={String(selectedResultIndex)} setSelectedTab={id => setSelectedResultIndex(+id)} />} +
+ ; +}; + +const TestResultView: React.FC<{ + test: JsonTestCase, + result: JsonTestResult, + selectedStep: JsonTestStep | undefined, + setSelectedStep: (step: JsonTestStep | undefined) => void; +}> = ({ test, result, selectedStep, setSelectedStep }) => { + return
+ {result.steps.map((step, i) => )}
; }; const TestResultDetails: React.FC<{ - test: JsonTestCase, - result: JsonTestResult, + test: JsonTestCase | undefined, + result: JsonTestResult | undefined, }> = ({ test, result }) => { const { screenshots, video, attachmentsMap } = React.useMemo(() => { const attachmentsMap = new Map(); - const screenshots = result.attachments.filter(a => a.name === 'screenshot'); - const video = result.attachments.filter(a => a.name === 'video'); - for (const a of result.attachments) + const attachments = result?.attachments || []; + const screenshots = attachments.filter(a => a.name === 'screenshot'); + const video = attachments.filter(a => a.name === 'video'); + for (const a of attachments) attachmentsMap.set(a.name, a); return { attachmentsMap, screenshots, video }; }, [ result ]); + if (!result) + return
; return
{result.failureSnippet &&
Test error
} {result.failureSnippet &&
} @@ -211,14 +212,14 @@ const TestResultDetails: React.FC<{ }; const TestStepDetails: React.FC<{ - test: JsonTestCase, - result: JsonTestResult, - step: JsonTestStep, + test: JsonTestCase | undefined, + result: JsonTestResult | undefined, + step: JsonTestStep | undefined, }> = ({ test, result, step }) => { const [source, setSource] = React.useState({ text: '', language: 'javascript' }); React.useEffect(() => { (async () => { - const frame = step.stack?.[0]; + const frame = step?.stack?.[0]; if (!frame || !frame.sha1) return; try { @@ -230,10 +231,25 @@ const TestStepDetails: React.FC<{ } })(); }, [step]); + const [selectedTab, setSelectedTab] = React.useState('log'); return
- {step.failureSnippet &&
Step error
} - {step.failureSnippet &&
} - +
+ }, + { + id: 'errors', + title: 'Errors', + render: () =>
+ }, + { + id: 'source', + title: 'Source', + render: () => + } + ]}>
; }; @@ -243,7 +259,7 @@ const StepTreeItem: React.FC<{ selectedStep?: JsonTestStep, setSelectedStep: (step: JsonTestStep | undefined) => void; }> = ({ step, depth, selectedStep, setSelectedStep }) => { - return + return {testStepStatusIcon(step)} {step.preview || step.title}
@@ -286,7 +302,7 @@ export const ImageDiff: React.FunctionComponent<{ export const AttachmentLink: React.FunctionComponent<{ attachment: JsonAttachment, }> = ({ attachment }) => { - return + return {attachment.sha1 && {attachment.name}} {attachment.body && {attachment.name}}