Skip to content

Commit 873f3a0

Browse files
authored
chore(trace): add context create event for test runner (#30697)
Adding metadata event to the test.trace to simplify time computation logic.
1 parent 7057f28 commit 873f3a0

File tree

6 files changed

+314
-12
lines changed

6 files changed

+314
-12
lines changed

packages/playwright-core/src/server/trace/recorder/tracing.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import type { ConsoleMessage } from '../../console';
4545
import { Dispatcher } from '../../dispatchers/dispatcher';
4646
import { serializeError } from '../../errors';
4747

48-
const version: trace.VERSION = 6;
48+
const version: trace.VERSION = 7;
4949

5050
export type TracerOptions = {
5151
name?: string;
@@ -100,10 +100,12 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
100100
this._contextCreatedEvent = {
101101
version,
102102
type: 'context-options',
103+
origin: 'library',
103104
browserName: '',
104105
options: {},
105106
platform: process.platform,
106107
wallTime: 0,
108+
monotonicTime: 0,
107109
sdkLanguage: context.attribution.playwright.options.sdkLanguage,
108110
testIdAttributeName
109111
};
@@ -177,7 +179,12 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
177179
this._allocateNewTraceFile(this._state);
178180

179181
this._fs.mkdir(path.dirname(this._state.traceFile));
180-
const event: trace.TraceEvent = { ...this._contextCreatedEvent, title: options.title, wallTime: Date.now() };
182+
const event: trace.TraceEvent = {
183+
...this._contextCreatedEvent,
184+
title: options.title,
185+
wallTime: Date.now(),
186+
monotonicTime: monotonicTime()
187+
};
181188
this._fs.appendFile(this._state.traceFile, JSON.stringify(event) + '\n');
182189

183190
this._context.instrumentation.addListener(this, this._context);

packages/playwright/src/worker/testTracing.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type { TestInfoImpl } from './testInfo';
2828

2929
export type Attachment = TestInfo['attachments'][0];
3030
export const testTraceEntryName = 'test.trace';
31+
const version: trace.VERSION = 7;
3132
let traceOrdinal = 0;
3233

3334
type TraceFixtureValue = PlaywrightWorkerOptions['trace'] | undefined;
@@ -41,11 +42,24 @@ export class TestTracing {
4142
private _temporaryTraceFiles: string[] = [];
4243
private _artifactsDir: string;
4344
private _tracesDir: string;
45+
private _contextCreatedEvent: trace.ContextCreatedTraceEvent;
4446

4547
constructor(testInfo: TestInfoImpl, artifactsDir: string) {
4648
this._testInfo = testInfo;
4749
this._artifactsDir = artifactsDir;
4850
this._tracesDir = path.join(this._artifactsDir, 'traces');
51+
this._contextCreatedEvent = {
52+
version,
53+
type: 'context-options',
54+
origin: 'testRunner',
55+
browserName: '',
56+
options: {},
57+
platform: process.platform,
58+
wallTime: Date.now(),
59+
monotonicTime: monotonicTime(),
60+
sdkLanguage: 'javascript',
61+
};
62+
this._appendTraceEvent(this._contextCreatedEvent);
4963
}
5064

5165
private _shouldCaptureTrace() {

packages/trace-viewer/src/entries.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type ContextEntry = {
2626
browserName: string;
2727
channel?: string;
2828
platform?: string;
29-
wallTime?: number;
29+
wallTime: number;
3030
sdkLanguage?: Language;
3131
testIdAttributeName?: string;
3232
title?: string;
@@ -58,6 +58,7 @@ export function createEmptyContext(): ContextEntry {
5858
origin: 'testRunner',
5959
traceUrl: '',
6060
startTime: Number.MAX_SAFE_INTEGER,
61+
wallTime: Number.MAX_SAFE_INTEGER,
6162
endTime: 0,
6263
browserName: '',
6364
options: {

packages/trace-viewer/src/traceModernizer.ts

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type * as trace from '@trace/trace';
1818
import type * as traceV3 from './versions/traceV3';
1919
import type * as traceV4 from './versions/traceV4';
2020
import type * as traceV5 from './versions/traceV5';
21+
import type * as traceV6 from './versions/traceV6';
2122
import type { ActionEntry, ContextEntry, PageEntry } from './entries';
2223
import type { SnapshotStorage } from './snapshotStorage';
2324

@@ -71,12 +72,13 @@ export class TraceModernizer {
7172
switch (event.type) {
7273
case 'context-options': {
7374
this._version = event.version;
74-
contextEntry.origin = 'library';
75+
contextEntry.origin = event.origin;
7576
contextEntry.browserName = event.browserName;
7677
contextEntry.channel = event.channel;
7778
contextEntry.title = event.title;
7879
contextEntry.platform = event.platform;
7980
contextEntry.wallTime = event.wallTime;
81+
contextEntry.startTime = event.monotonicTime;
8082
contextEntry.sdkLanguage = event.sdkLanguage;
8183
contextEntry.options = event.options;
8284
contextEntry.testIdAttributeName = event.testIdAttributeName;
@@ -145,11 +147,11 @@ export class TraceModernizer {
145147
break;
146148
}
147149
case 'resource-snapshot':
148-
this._snapshotStorage!.addResource(event.snapshot);
150+
this._snapshotStorage.addResource(event.snapshot);
149151
contextEntry.resources.push(event.snapshot);
150152
break;
151153
case 'frame-snapshot':
152-
this._snapshotStorage!.addFrameSnapshot(event.snapshot);
154+
this._snapshotStorage.addFrameSnapshot(event.snapshot);
153155
break;
154156
}
155157
// Make sure there is a page entry for each page, even without screencast frames,
@@ -170,12 +172,18 @@ export class TraceModernizer {
170172
}
171173
}
172174

175+
private _processedContextCreatedEvent() {
176+
return this._version !== undefined;
177+
}
178+
173179
private _modernize(event: any): trace.TraceEvent[] {
174-
if (this._version === undefined)
180+
// In trace 6->7 we also need to modernize context-options event.
181+
let version = this._version || event.version;
182+
if (version === undefined)
175183
return [event];
176-
const lastVersion: trace.VERSION = 6;
184+
const lastVersion: trace.VERSION = 7;
177185
let events = [event];
178-
for (let version = this._version; version < lastVersion; ++version)
186+
for (; version < lastVersion; ++version)
179187
events = (this as any)[`_modernize_${version}_to_${version + 1}`].call(this, events);
180188
return events;
181189
}
@@ -341,8 +349,8 @@ export class TraceModernizer {
341349
return event;
342350
}
343351

344-
_modernize_5_to_6(events: traceV5.TraceEvent[]): trace.TraceEvent[] {
345-
const result: trace.TraceEvent[] = [];
352+
_modernize_5_to_6(events: traceV5.TraceEvent[]): traceV6.TraceEvent[] {
353+
const result: traceV6.TraceEvent[] = [];
346354
for (const event of events) {
347355
result.push(event);
348356
if (event.type !== 'after' || !event.log.length)
@@ -358,4 +366,35 @@ export class TraceModernizer {
358366
}
359367
return result;
360368
}
369+
370+
_modernize_6_to_7(events: traceV6.TraceEvent[]): trace.TraceEvent[] {
371+
const result: trace.TraceEvent[] = [];
372+
if (!this._processedContextCreatedEvent() && events[0].type !== 'context-options') {
373+
const event: trace.ContextCreatedTraceEvent = {
374+
type: 'context-options',
375+
origin: 'testRunner',
376+
version: 7,
377+
browserName: '',
378+
options: {},
379+
platform: process.platform,
380+
wallTime: 0,
381+
monotonicTime: 0,
382+
sdkLanguage: 'javascript',
383+
};
384+
result.push(event);
385+
}
386+
for (const event of events) {
387+
if (event.type === 'context-options') {
388+
result.push({ ...event, monotonicTime: 0, origin: 'library' });
389+
continue;
390+
}
391+
// Take wall and monotonic time from the first event.
392+
if (!this._contextEntry.wallTime && event.type === 'before')
393+
this._contextEntry.wallTime = event.wallTime;
394+
if (!this._contextEntry.startTime && event.type === 'before')
395+
this._contextEntry.startTime = event.startTime;
396+
result.push(event);
397+
}
398+
return result;
399+
}
361400
}

0 commit comments

Comments
 (0)