From 73b72309315cc97f973a1a2a496ad160e298e35f Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 5 Aug 2021 16:04:09 -0700 Subject: [PATCH] fix(trace viewer): render snapshots with correct viewport size (#8020) --- src/server/snapshot/snapshotterInjected.ts | 4 ++-- src/server/trace/recorder/tracing.ts | 2 +- src/server/trace/viewer/traceModel.ts | 18 ++++++++++++--- src/web/traceViewer/ui/callTab.tsx | 10 ++++---- src/web/traceViewer/ui/snapshotTab.tsx | 9 ++++++-- src/web/traceViewer/ui/workbench.tsx | 7 +++--- tests/trace-viewer/trace-viewer.spec.ts | 27 +++++++++++++++++++--- 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/server/snapshot/snapshotterInjected.ts b/src/server/snapshot/snapshotterInjected.ts index 2004c556f8..27db1ff823 100644 --- a/src/server/snapshot/snapshotterInjected.ts +++ b/src/server/snapshot/snapshotterInjected.ts @@ -443,8 +443,8 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { doctype: document.doctype ? document.doctype.name : undefined, resourceOverrides: [], viewport: { - width: Math.max(document.body ? document.body.offsetWidth : 0, document.documentElement ? document.documentElement.offsetWidth : 0), - height: Math.max(document.body ? document.body.offsetHeight : 0, document.documentElement ? document.documentElement.offsetHeight : 0), + width: window.innerWidth, + height: window.innerHeight, }, url: location.href, timestamp, diff --git a/src/server/trace/recorder/tracing.ts b/src/server/trace/recorder/tracing.ts index 60cd64e5eb..bd63f2374c 100644 --- a/src/server/trace/recorder/tracing.ts +++ b/src/server/trace/recorder/tracing.ts @@ -36,7 +36,7 @@ export type TracerOptions = { screenshots?: boolean; }; -export const VERSION = 1; +export const VERSION = 2; type RecordingState = { options: TracerOptions, diff --git a/src/server/trace/viewer/traceModel.ts b/src/server/trace/viewer/traceModel.ts index 46c9397a9d..c259fe5433 100644 --- a/src/server/trace/viewer/traceModel.ts +++ b/src/server/trace/viewer/traceModel.ts @@ -38,7 +38,8 @@ export class TraceModel { browserName: '', options: { sdkLanguage: '' }, pages: [], - resources: [] + resources: [], + snapshotSizes: {}, }; } @@ -98,6 +99,8 @@ export class TraceModel { break; case 'frame-snapshot': this._snapshotStorage.addFrameSnapshot(event.snapshot); + if (event.snapshot.snapshotName && event.snapshot.isMainFrame) + this.contextEntry.snapshotSizes[event.snapshot.snapshotName] = event.snapshot.viewport; break; } if (event.type === 'action' || event.type === 'event') { @@ -123,6 +126,14 @@ export class TraceModel { } return event; } + + _modernize_1_to_2(event: any): any { + if (event.type === 'frame-snapshot' && event.snapshot.isMainFrame) { + // Old versions had completely wrong viewport. + event.snapshot.viewport = this.contextEntry.options.viewport || { width: 1280, height: 720 }; + } + return event; + } } export type ContextEntry = { @@ -132,18 +143,19 @@ export type ContextEntry = { options: BrowserContextOptions; pages: PageEntry[]; resources: ResourceSnapshot[]; + snapshotSizes: { [snapshotName: string]: { width: number, height: number } }; }; export type PageEntry = { actions: trace.ActionTraceEvent[]; events: trace.ActionTraceEvent[]; - objects: { [ket: string]: any }; + objects: { [key: string]: any }; screencastFrames: { sha1: string, timestamp: number, width: number, height: number, - }[] + }[]; }; export class PersistentSnapshotStorage extends BaseSnapshotStorage { diff --git a/src/web/traceViewer/ui/callTab.tsx b/src/web/traceViewer/ui/callTab.tsx index 5f0500816a..fb0fb14a19 100644 --- a/src/web/traceViewer/ui/callTab.tsx +++ b/src/web/traceViewer/ui/callTab.tsx @@ -39,12 +39,12 @@ export const CallTab: React.FunctionComponent<{
{action.metadata.apiName}
{ !!paramKeys.length &&
Parameters
} { - !!paramKeys.length && paramKeys.map(name => renderLine(action.metadata, name, params[name])) + !!paramKeys.length && paramKeys.map((name, index) => renderLine(action.metadata, name, params[name], 'param-' + index)) } { !!action.metadata.result &&
Return value
} { - !!action.metadata.result && Object.keys(action.metadata.result).map(name => - renderLine(action.metadata, name, action.metadata.result[name]) + !!action.metadata.result && Object.keys(action.metadata.result).map((name, index) => + renderLine(action.metadata, name, action.metadata.result[name], 'result-' + index) ) }
Log
@@ -58,12 +58,12 @@ export const CallTab: React.FunctionComponent<{ ; }; -function renderLine(metadata: CallMetadata, name: string, value: any) { +function renderLine(metadata: CallMetadata, name: string, value: any, key: string) { const { title, type } = toString(metadata, name, value); let text = trimRight(title.replace(/\n/g, '↵'), 80); if (type === 'string') text = `"${text}"`; - return
{name}: {text}
; + return
{name}: {text}
; } function toString(metadata: CallMetadata, name: string, value: any): { title: string, type: string } { diff --git a/src/web/traceViewer/ui/snapshotTab.tsx b/src/web/traceViewer/ui/snapshotTab.tsx index 41943ed3f0..e911528a36 100644 --- a/src/web/traceViewer/ui/snapshotTab.tsx +++ b/src/web/traceViewer/ui/snapshotTab.tsx @@ -24,8 +24,9 @@ import { ActionTraceEvent } from '../../../server/trace/common/traceEvents'; export const SnapshotTab: React.FunctionComponent<{ action: ActionTraceEvent | undefined, - snapshotSize: Size, -}> = ({ action, snapshotSize }) => { + snapshotSizes: { [snapshotName: string]: Size }, + defaultSnapshotSize: Size, +}> = ({ action, snapshotSizes, defaultSnapshotSize }) => { const [measure, ref] = useMeasure(); const [snapshotIndex, setSnapshotIndex] = React.useState(0); @@ -61,6 +62,10 @@ export const SnapshotTab: React.FunctionComponent<{ } }, [action, snapshotIndex, iframeRef, snapshots]); + let snapshotSize = defaultSnapshotSize; + if (snapshots[snapshotIndex] && snapshots[snapshotIndex].snapshotName) + snapshotSize = snapshotSizes[snapshots[snapshotIndex].snapshotName] || defaultSnapshotSize; + const scale = Math.min(measure.width / snapshotSize.width, measure.height / snapshotSize.height); const scaledSize = { width: snapshotSize.width * scale, diff --git a/src/web/traceViewer/ui/workbench.tsx b/src/web/traceViewer/ui/workbench.tsx index 46b6293f8d..69b61b9ad1 100644 --- a/src/web/traceViewer/ui/workbench.tsx +++ b/src/web/traceViewer/ui/workbench.tsx @@ -54,7 +54,7 @@ export const Workbench: React.FunctionComponent<{ return actions; }, [context]); - const snapshotSize = context.options.viewport || { width: 1280, height: 720 }; + const defaultSnapshotSize = context.options.viewport || { width: 1280, height: 720 }; const boundaries = { minimum: context.startTime, maximum: context.endTime }; // Leave some nice free space on the right hand side. @@ -89,7 +89,7 @@ export const Workbench: React.FunctionComponent<{ - + }, { id: 'console', title: 'Console', count: consoleCount, render: () => }, @@ -124,5 +124,6 @@ const emptyContext: ContextEntry = { _debugName: '', }, pages: [], - resources: [] + resources: [], + snapshotSizes: {}, }; diff --git a/tests/trace-viewer/trace-viewer.spec.ts b/tests/trace-viewer/trace-viewer.spec.ts index b525713fd8..2615edfaaa 100644 --- a/tests/trace-viewer/trace-viewer.spec.ts +++ b/tests/trace-viewer/trace-viewer.spec.ts @@ -42,6 +42,9 @@ class TraceViewerPage { await this.page.click(`.action-title:has-text("${title}")`); } + async selectSnapshot(name: string) { + await this.page.click(`.snapshot-tab .tab-label:has-text("${name}")`); + } async callLines() { await this.page.waitForSelector('.call-line:visible'); @@ -74,6 +77,13 @@ class TraceViewerPage { await this.page.waitForSelector('.console-stack:visible'); return await this.page.$$eval('.console-stack:visible', ee => ee.map(e => e.textContent)); } + + async snapshotSize() { + return this.page.$eval('.snapshot-container', e => { + const style = window.getComputedStyle(e); + return { width: style.width, height: style.height }; + }); + } } const test = playwrightTest.extend<{ showTraceViewer: (trace: string) => Promise }>({ @@ -110,6 +120,7 @@ test.beforeAll(async ({ browser, browserName }, workerInfo) => { page.waitForNavigation(), page.waitForTimeout(200).then(() => page.goto('data:text/html,Hello world 2')) ]); + await page.setViewportSize({ width: 500, height: 600 }); await page.close(); traceFile = path.join(workerInfo.project.outputDir, browserName, 'trace.zip'); await context.tracing.stop({ path: traceFile }); @@ -129,6 +140,7 @@ test('should open simple trace viewer', async ({ showTraceViewer }) => { 'page.click\"Click\"', 'page.waitForNavigation', 'page.gotodata:text/html,Hello world 2', + 'page.setViewportSize', ]); }); @@ -166,14 +178,14 @@ test('should open console errors on click', async ({ showTraceViewer, browserNam test.fixme(browserName === 'firefox', 'Firefox generates stray console message for page error'); const traceViewer = await showTraceViewer(traceFile); expect(await traceViewer.actionIconsText('page.evaluate')).toEqual(['2', '1']); - expect(await traceViewer.page.isHidden('.console-tab')); + expect(await traceViewer.page.isHidden('.console-tab')).toBeTruthy(); await (await traceViewer.actionIcons('page.evaluate')).click(); - expect(await traceViewer.page.waitForSelector('.console-tab')); + expect(await traceViewer.page.waitForSelector('.console-tab')).toBeTruthy(); }); test('should show params and return value', async ({ showTraceViewer, browserName }) => { const traceViewer = await showTraceViewer(traceFile); - expect(await traceViewer.selectAction('page.evaluate')); + await traceViewer.selectAction('page.evaluate'); expect(await traceViewer.callLines()).toEqual([ 'page.evaluate', 'expression: "({↵ a↵ }) => {↵ console.log(\'Info\');↵ console.warn(\'Warning\');↵ con…"', @@ -182,3 +194,12 @@ test('should show params and return value', async ({ showTraceViewer, browserNam 'value: "return paramA"' ]); }); + +test('should have correct snapshot size', async ({ showTraceViewer }) => { + const traceViewer = await showTraceViewer(traceFile); + await traceViewer.selectAction('page.setViewport'); + await traceViewer.selectSnapshot('Before'); + expect(await traceViewer.snapshotSize()).toEqual({ width: '1280px', height: '720px' }); + await traceViewer.selectSnapshot('After'); + expect(await traceViewer.snapshotSize()).toEqual({ width: '500px', height: '600px' }); +});