From b85d6704917e65994ffc8eacd80dedbb19cc77d3 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Sat, 11 Mar 2023 11:43:33 -0800 Subject: [PATCH] chore(ui): show output on demand (#21592) --- packages/trace-viewer/src/ui/metadataView.tsx | 2 +- packages/trace-viewer/src/ui/watchMode.css | 2 +- packages/trace-viewer/src/ui/watchMode.tsx | 34 +++++++---- packages/trace-viewer/src/ui/workbench.tsx | 61 +++++++++++++------ packages/web/src/common.css | 3 +- .../web/src/components/codeMirrorWrapper.tsx | 2 +- tests/library/trace-viewer.spec.ts | 2 +- tests/playwright-test/reporter-html.spec.ts | 3 +- 8 files changed, 71 insertions(+), 38 deletions(-) diff --git a/packages/trace-viewer/src/ui/metadataView.tsx b/packages/trace-viewer/src/ui/metadataView.tsx index 52c6df4916..b5254ba78d 100644 --- a/packages/trace-viewer/src/ui/metadataView.tsx +++ b/packages/trace-viewer/src/ui/metadataView.tsx @@ -24,7 +24,7 @@ export const MetadataView: React.FunctionComponent<{ }> = ({ model }) => { if (!model) return <>; - return
+ return
Time
{!!model.wallTime &&
start time:{new Date(model.wallTime).toLocaleString()}
}
duration:{msToString(model.endTime - model.startTime)}
diff --git a/packages/trace-viewer/src/ui/watchMode.css b/packages/trace-viewer/src/ui/watchMode.css index 66eb8ce0e4..00093916b8 100644 --- a/packages/trace-viewer/src/ui/watchMode.css +++ b/packages/trace-viewer/src/ui/watchMode.css @@ -44,7 +44,7 @@ margin: 0; } -.watch-mode-sidebar .section-title { +.watch-mode .section-title { font-size: 11px; text-transform: uppercase; font-weight: bold; diff --git a/packages/trace-viewer/src/ui/watchMode.tsx b/packages/trace-viewer/src/ui/watchMode.tsx index e08fc8e433..89c1e473f0 100644 --- a/packages/trace-viewer/src/ui/watchMode.tsx +++ b/packages/trace-viewer/src/ui/watchMode.tsx @@ -62,6 +62,7 @@ export const WatchModeView: React.FC<{}> = ({ const [visibleTestIds, setVisibleTestIds] = React.useState([]); const [filterText, setFilterText] = React.useState(''); const [filterExpanded, setFilterExpanded] = React.useState(false); + const [isShowingOutput, setIsShowingOutput] = React.useState(false); const inputRef = React.useRef(null); React.useEffect(() => { @@ -125,9 +126,24 @@ export const WatchModeView: React.FC<{}> = ({ }; const result = selectedTest?.results[0]; - return
+ const isFinished = result && result.duration >= 0; + return
- {(result && result.duration >= 0) ? : } +
+
+ +
Output
+ xtermDataSource.clear()}> +
+ setIsShowingOutput(false)}> +
+ ; +
+
+ {isFinished && } + {!isFinished && } +
+
setSettingsVisible(false)}>Tests
@@ -137,6 +153,7 @@ export const WatchModeView: React.FC<{}> = ({ setIsWatchingFiles(!isWatchingFiles)}>
{ setSettingsVisible(!settingsVisible); }}> + { setIsShowingOutput(!isShowingOutput); }}>
{!settingsVisible && ; + return ; }; export const FinishedTraceView: React.FC<{ @@ -337,16 +354,7 @@ export const FinishedTraceView: React.FC<{ loadSingleTraceFile(attachment.path).then(setModel); }, [testResult]); - return ; -}; - -export const TraceView: React.FC<{ - model: MultiTraceModel | undefined, -}> = ({ model }) => { - const xterm = ; - return xtermDataSource.clear()}>, - ]} hideTimelineBars={true} hideStackFrames={true} />; + return ; }; declare global { diff --git a/packages/trace-viewer/src/ui/workbench.tsx b/packages/trace-viewer/src/ui/workbench.tsx index 2f50123aa9..daa224aeeb 100644 --- a/packages/trace-viewer/src/ui/workbench.tsx +++ b/packages/trace-viewer/src/ui/workbench.tsx @@ -33,42 +33,65 @@ import { MetadataView } from './metadataView'; export const Workbench: React.FunctionComponent<{ model?: MultiTraceModel, - output?: React.ReactElement, - rightToolbar?: React.ReactElement[], hideTimelineBars?: boolean, hideStackFrames?: boolean, -}> = ({ model, output, rightToolbar, hideTimelineBars, hideStackFrames }) => { + showSourcesFirst?: boolean, +}> = ({ model, hideTimelineBars, hideStackFrames, showSourcesFirst }) => { const [selectedAction, setSelectedAction] = React.useState(undefined); const [highlightedAction, setHighlightedAction] = React.useState(); const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState('actions'); - const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState(output ? 'output' : 'call'); + const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState(showSourcesFirst ? 'source' : 'call'); const activeAction = model ? highlightedAction || selectedAction : undefined; React.useEffect(() => { - if (selectedAction) + if (selectedAction && model?.actions.includes(selectedAction)) return; const failedAction = model?.actions.find(a => a.error); if (failedAction) setSelectedAction(failedAction); - // In the UI mode, selecting the first error should reveal source. - if (failedAction && output) - setSelectedPropertiesTab('source'); - }, [model, output, selectedAction, setSelectedAction, setSelectedPropertiesTab]); + else if (model?.actions.length) + setSelectedAction(model.actions[model.actions.length - 1]); + }, [model, selectedAction, setSelectedAction, setSelectedPropertiesTab]); const { errors, warnings } = activeAction ? modelUtil.stats(activeAction) : { errors: 0, warnings: 0 }; const consoleCount = errors + warnings; const networkCount = activeAction ? modelUtil.resourcesForAction(activeAction).length : 0; const sdkLanguage = model?.sdkLanguage || 'javascript'; - const tabs: TabbedPaneTabModel[] = [ - { id: 'call', title: 'Call', render: () => }, - { id: 'source', title: 'Source', count: 0, render: () => }, - { id: 'console', title: 'Console', count: consoleCount, render: () => }, - { id: 'network', title: 'Network', count: networkCount, render: () => }, - ]; + const callTab: TabbedPaneTabModel = { + id: 'call', + title: showSourcesFirst ? 'Log' : 'Call', + render: () => + }; + const sourceTab: TabbedPaneTabModel = { + id: 'source', + title: 'Source', + render: () => + }; + const consoleTab: TabbedPaneTabModel = { + id: 'console', + title: 'Console', + count: consoleCount, + render: () => + }; + const networkTab: TabbedPaneTabModel = { + id: 'network', + title: 'Network', + count: networkCount, + render: () => + }; - if (output) - tabs.unshift({ id: 'output', title: 'Output', component: output }); + const tabs: TabbedPaneTabModel[] = showSourcesFirst ? [ + sourceTab, + consoleTab, + networkTab, + callTab, + ] : [ + callTab, + consoleTab, + networkTab, + sourceTab, + ]; return
setSelectedAction(action)} hideTimelineBars={hideTimelineBars} /> - + - +
; }; diff --git a/packages/web/src/common.css b/packages/web/src/common.css index e1a640f2a4..01e443375b 100644 --- a/packages/web/src/common.css +++ b/packages/web/src/common.css @@ -72,7 +72,8 @@ body { min-height: 0; } -*[hidden] { +*[hidden], +.hidden { display: none !important; } diff --git a/packages/web/src/components/codeMirrorWrapper.tsx b/packages/web/src/components/codeMirrorWrapper.tsx index dae38cf131..38558f1bf3 100644 --- a/packages/web/src/components/codeMirrorWrapper.tsx +++ b/packages/web/src/components/codeMirrorWrapper.tsx @@ -146,7 +146,7 @@ export const CodeMirrorWrapper: React.FC = ({ } codemirrorRef.current!.widgets = widgets; - if (revealLine) + if (revealLine && codemirrorRef.current!.cm.lineCount() >= revealLine) codemirror.scrollIntoView({ line: revealLine - 1, ch: 0 }, 50); }, [codemirror, text, highlight, revealLine, focusOnChange, onChange]); diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index ff8b7123ee..a101ab7845 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -633,7 +633,7 @@ test('should follow redirects', async ({ page, runAndTrace, server, asset }) => test('should include metainfo', async ({ showTraceViewer, browserName }) => { const traceViewer = await showTraceViewer([traceFile]); await traceViewer.page.locator('text=Metadata').click(); - const callLine = traceViewer.page.locator('.call-line'); + const callLine = traceViewer.page.locator('.metadata-view .call-line'); await expect(callLine.getByText('start time')).toHaveText(/start time:[\d/,: ]+/); await expect(callLine.getByText('duration')).toHaveText(/duration:[\dms]+/); await expect(callLine.getByText('engine')).toHaveText(/engine:[\w]+/); diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 755c5f9ab1..6628a1a39e 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -37,6 +37,8 @@ const test = baseTest.extend<{ showReport: (reportFolder?: string) => Promise { await runInlineTest({ 'playwright.config.ts': ` @@ -473,7 +475,6 @@ test('should warn user when viewing via file:// protocol', async ({ runInlineTes await test.step('view via server', async () => { await showReport(); await page.locator('[title="View trace"]').click(); - await expect(page.locator('body')).toContainText('Action does not have snapshots', { useInnerText: true }); await expect(page.locator('dialog')).toBeHidden(); });