diff --git a/src/server/snapshot/snapshotter.ts b/src/server/snapshot/snapshotter.ts index 2458554bd4..a83eb45c7d 100644 --- a/src/server/snapshot/snapshotter.ts +++ b/src/server/snapshot/snapshotter.ts @@ -199,7 +199,7 @@ export class Snapshotter { const resource: ResourceSnapshot = { pageId: response.frame()._page.guid, frameId: response.frame().guid, - resourceId: 'resource@' + createGuid(), + resourceId: response.guid, url, type: response.request().resourceType(), contentType, diff --git a/src/server/trace/common/traceEvents.ts b/src/server/trace/common/traceEvents.ts index 05bf5dc879..33ce1949aa 100644 --- a/src/server/trace/common/traceEvents.ts +++ b/src/server/trace/common/traceEvents.ts @@ -16,60 +16,40 @@ import { CallMetadata } from '../../instrumentation'; import { FrameSnapshot, ResourceSnapshot } from '../../snapshot/snapshotTypes'; +import { BrowserContextOptions } from '../../types'; export type ContextCreatedTraceEvent = { - timestamp: number, - type: 'context-metadata', + type: 'context-options', browserName: string, - deviceScaleFactor: number, - isMobile: boolean, - viewportSize?: { width: number, height: number }, - debugName?: string, -}; - -export type PageCreatedTraceEvent = { - timestamp: number, - type: 'page-created', - pageId: string, -}; - -export type PageDestroyedTraceEvent = { - timestamp: number, - type: 'page-destroyed', - pageId: string, + options: BrowserContextOptions }; export type ScreencastFrameTraceEvent = { - timestamp: number, type: 'screencast-frame', pageId: string, sha1: string, width: number, height: number, + timestamp: number, }; export type ActionTraceEvent = { - timestamp: number, type: 'action' | 'event', metadata: CallMetadata, }; export type ResourceSnapshotTraceEvent = { - timestamp: number, type: 'resource-snapshot', snapshot: ResourceSnapshot, }; export type FrameSnapshotTraceEvent = { - timestamp: number, type: 'frame-snapshot', snapshot: FrameSnapshot, }; export type TraceEvent = ContextCreatedTraceEvent | - PageCreatedTraceEvent | - PageDestroyedTraceEvent | ScreencastFrameTraceEvent | ActionTraceEvent | ResourceSnapshotTraceEvent | diff --git a/src/server/trace/recorder/traceSnapshotter.ts b/src/server/trace/recorder/traceSnapshotter.ts index b7d0a2accf..d0e723e248 100644 --- a/src/server/trace/recorder/traceSnapshotter.ts +++ b/src/server/trace/recorder/traceSnapshotter.ts @@ -24,7 +24,6 @@ import { FrameSnapshot, ResourceSnapshot } from '../../snapshot/snapshotTypes'; import { Snapshotter, SnapshotterBlob, SnapshotterDelegate } from '../../snapshot/snapshotter'; import { ElementHandle } from '../../dom'; import { TraceEvent } from '../common/traceEvents'; -import { monotonicTime } from '../../../utils/utils'; const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs)); @@ -66,18 +65,10 @@ export class TraceSnapshotter extends EventEmitter implements SnapshotterDelegat } onResourceSnapshot(snapshot: ResourceSnapshot): void { - this._appendTraceEvent({ - timestamp: monotonicTime(), - type: 'resource-snapshot', - snapshot, - }); + this._appendTraceEvent({ type: 'resource-snapshot', snapshot }); } onFrameSnapshot(snapshot: FrameSnapshot): void { - this._appendTraceEvent({ - timestamp: monotonicTime(), - type: 'frame-snapshot', - snapshot, - }); + this._appendTraceEvent({ type: 'frame-snapshot', snapshot }); } } diff --git a/src/server/trace/recorder/tracing.ts b/src/server/trace/recorder/tracing.ts index c501ae9b0d..4a8679ddff 100644 --- a/src/server/trace/recorder/tracing.ts +++ b/src/server/trace/recorder/tracing.ts @@ -68,13 +68,9 @@ export class Tracing implements InstrumentationListener { this._appendEventChain = mkdirIfNeeded(this._traceFile); const event: trace.ContextCreatedTraceEvent = { - timestamp: monotonicTime(), - type: 'context-metadata', + type: 'context-options', browserName: this._context._browser.options.name, - isMobile: !!this._context._options.isMobile, - deviceScaleFactor: this._context._options.deviceScaleFactor || 1, - viewportSize: this._context._options.viewport || undefined, - debugName: this._context._options._debugName, + options: this._context._options }; this._appendTraceEvent(event); for (const page of this._context.pages()) @@ -154,34 +150,18 @@ export class Tracing implements InstrumentationListener { if (!sdkObject.attribution.page) return; await this._captureSnapshot('after', sdkObject, metadata); - const event: trace.ActionTraceEvent = { - timestamp: metadata.startTime, - type: 'action', - metadata, - }; + const event: trace.ActionTraceEvent = { type: 'action', metadata }; this._appendTraceEvent(event); } onEvent(sdkObject: SdkObject, metadata: CallMetadata) { if (!sdkObject.attribution.page) return; - const event: trace.ActionTraceEvent = { - timestamp: metadata.startTime, - type: 'event', - metadata, - }; + const event: trace.ActionTraceEvent = { type: 'event', metadata }; this._appendTraceEvent(event); } private _onPage(screenshots: boolean | undefined, page: Page) { - const pageId = page.guid; - - const event: trace.PageCreatedTraceEvent = { - timestamp: monotonicTime(), - type: 'page-created', - pageId, - }; - this._appendTraceEvent(event); if (screenshots) page.setScreencastOptions({ width: 800, height: 600, quality: 90 }); @@ -201,14 +181,6 @@ export class Tracing implements InstrumentationListener { await fsWriteFileAsync(path.join(this._resourcesDir!, sha1), params.buffer).catch(() => {}); }); }), - helper.addEventListener(page, Page.Events.Close, () => { - const event: trace.PageDestroyedTraceEvent = { - timestamp: monotonicTime(), - type: 'page-destroyed', - pageId, - }; - this._appendTraceEvent(event); - }) ); } diff --git a/src/server/trace/viewer/traceModel.ts b/src/server/trace/viewer/traceModel.ts index 28179eee13..6535d094c3 100644 --- a/src/server/trace/viewer/traceModel.ts +++ b/src/server/trace/viewer/traceModel.ts @@ -19,16 +19,25 @@ import path from 'path'; import * as trace from '../common/traceEvents'; import { ContextResources, ResourceSnapshot } from '../../snapshot/snapshotTypes'; import { BaseSnapshotStorage, SnapshotStorage } from '../../snapshot/snapshotStorage'; +import { BrowserContextOptions } from '../../types'; export * as trace from '../common/traceEvents'; export class TraceModel { - contextEntry: ContextEntry | undefined; + contextEntry: ContextEntry; pageEntries = new Map(); contextResources = new Map(); private _snapshotStorage: PersistentSnapshotStorage; constructor(snapshotStorage: PersistentSnapshotStorage) { this._snapshotStorage = snapshotStorage; + this.contextEntry = { + startTime: Number.MAX_VALUE, + endTime: Number.MIN_VALUE, + browserName: '', + options: { sdkLanguage: '' }, + pages: [], + resources: [] + }; } appendEvents(events: trace.TraceEvent[], snapshotStorage: SnapshotStorage) { @@ -40,49 +49,41 @@ export class TraceModel { this.contextEntry!.resources = snapshotStorage.resources(); } + private _pageEntry(pageId: string): PageEntry { + let pageEntry = this.pageEntries.get(pageId); + if (!pageEntry) { + pageEntry = { + actions: [], + events: [], + screencastFrames: [], + }; + this.pageEntries.set(pageId, pageEntry); + this.contextEntry.pages.push(pageEntry); + } + return pageEntry; + } + appendEvent(event: trace.TraceEvent) { switch (event.type) { - case 'context-metadata': { - this.contextEntry = { - startTime: Number.MAX_VALUE, - endTime: Number.MIN_VALUE, - created: event, - pages: [], - resources: [] - }; - break; - } - case 'page-created': { - const pageEntry: PageEntry = { - created: event, - destroyed: undefined as any, - actions: [], - events: [], - screencastFrames: [], - }; - this.pageEntries.set(event.pageId, pageEntry); - this.contextEntry!.pages.push(pageEntry); - break; - } - case 'page-destroyed': { - this.pageEntries.get(event.pageId)!.destroyed = event; + case 'context-options': { + this.contextEntry.browserName = event.browserName; + this.contextEntry.options = event.options; break; } case 'screencast-frame': { - this.pageEntries.get(event.pageId)!.screencastFrames.push(event); + this._pageEntry(event.pageId).screencastFrames.push(event); break; } case 'action': { const metadata = event.metadata; - const pageEntry = this.pageEntries.get(metadata.pageId!)!; - pageEntry.actions.push(event); + if (metadata.pageId) + this._pageEntry(metadata.pageId).actions.push(event); break; } case 'event': { const metadata = event.metadata; - const pageEntry = this.pageEntries.get(metadata.pageId!); - if (pageEntry) - pageEntry.events.push(event); + if (metadata.pageId) + this._pageEntry(metadata.pageId).events.push(event); break; } case 'resource-snapshot': @@ -102,14 +103,13 @@ export class TraceModel { export type ContextEntry = { startTime: number; endTime: number; - created: trace.ContextCreatedTraceEvent; + browserName: string; + options: BrowserContextOptions; pages: PageEntry[]; resources: ResourceSnapshot[]; } export type PageEntry = { - created: trace.PageCreatedTraceEvent; - destroyed: trace.PageDestroyedTraceEvent; actions: trace.ActionTraceEvent[]; events: trace.ActionTraceEvent[]; screencastFrames: { diff --git a/src/web/traceViewer/ui/filmStrip.tsx b/src/web/traceViewer/ui/filmStrip.tsx index 5acc065b42..7725375544 100644 --- a/src/web/traceViewer/ui/filmStrip.tsx +++ b/src/web/traceViewer/ui/filmStrip.tsx @@ -43,7 +43,7 @@ export const FilmStrip: React.FunctionComponent<{ const previewTime = boundaries.minimum + (boundaries.maximum - boundaries.minimum) * previewPoint.x / measure.width; previewImage = screencastFrames[upperBound(screencastFrames, previewTime, timeComparator) - 1]; } - const previewSize = inscribe(context.created.viewportSize!, { width: 600, height: 600 }); + const previewSize = inscribe(context.options.viewport!, { width: 600, height: 600 }); return
{ context.pages.filter(p => p.screencastFrames.length).map((page, index) => a.timestamp - b.timestamp); const nextAction = selectedAction ? actions[actions.indexOf(selectedAction) + 1] : undefined; return { actions, nextAction }; }, [context, selectedAction]); - const snapshotSize = context.created.viewportSize || { width: 1280, height: 720 }; + const snapshotSize = context.options.viewport || { width: 1280, height: 720 }; const boundaries = { minimum: context.startTime, maximum: context.endTime }; return
@@ -103,14 +102,13 @@ const now = performance.now(); const emptyContext: ContextEntry = { startTime: now, endTime: now, - created: { - timestamp: now, - type: 'context-metadata', - browserName: '', + browserName: '', + options: { + sdkLanguage: '', deviceScaleFactor: 1, isMobile: false, - viewportSize: { width: 1280, height: 800 }, - debugName: '', + viewport: { width: 1280, height: 800 }, + _debugName: '', }, pages: [], resources: [] diff --git a/tests/tracing.spec.ts b/tests/tracing.spec.ts index 2eebf9aabb..9c3d1a418b 100644 --- a/tests/tracing.spec.ts +++ b/tests/tracing.spec.ts @@ -38,8 +38,7 @@ test('should collect trace', async ({ context, page, server, browserName }, test await (context as any).tracing.export(testInfo.outputPath('trace.zip')); const { events } = await parseTrace(testInfo.outputPath('trace.zip')); - expect(events[0].type).toBe('context-metadata'); - expect(events[1].type).toBe('page-created'); + expect(events[0].type).toBe('context-options'); expect(events.find(e => e.metadata?.apiName === 'page.goto')).toBeTruthy(); expect(events.find(e => e.metadata?.apiName === 'page.setContent')).toBeTruthy(); expect(events.find(e => e.metadata?.apiName === 'page.click')).toBeTruthy(); @@ -80,8 +79,7 @@ test('should collect two traces', async ({ context, page, server }, testInfo) => { const { events } = await parseTrace(testInfo.outputPath('trace1.zip')); - expect(events[0].type).toBe('context-metadata'); - expect(events[1].type).toBe('page-created'); + expect(events[0].type).toBe('context-options'); expect(events.find(e => e.metadata?.apiName === 'page.goto')).toBeTruthy(); expect(events.find(e => e.metadata?.apiName === 'page.setContent')).toBeTruthy(); expect(events.find(e => e.metadata?.apiName === 'page.click')).toBeTruthy(); @@ -91,8 +89,7 @@ test('should collect two traces', async ({ context, page, server }, testInfo) => { const { events } = await parseTrace(testInfo.outputPath('trace2.zip')); - expect(events[0].type).toBe('context-metadata'); - expect(events[1].type).toBe('page-created'); + expect(events[0].type).toBe('context-options'); expect(events.find(e => e.metadata?.apiName === 'page.goto')).toBeFalsy(); expect(events.find(e => e.metadata?.apiName === 'page.setContent')).toBeFalsy(); expect(events.find(e => e.metadata?.apiName === 'page.click')).toBeFalsy();