Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/playwright-core/src/server/har/harTracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,9 @@ export class HarTracer {
oldestWallTimeMs = wallTimeMs;
if (wallTimeMs > newestWallTimeMs)
newestWallTimeMs = wallTimeMs;
if (oldestWallTimeMs === newestWallTimeMs)
return;

// On coarse clocks all frames may share a single timestamp, in which case
// the duration is reported as zero rather than left unknown.
harEntry.time = newestWallTimeMs - oldestWallTimeMs;
};

Expand Down
19 changes: 11 additions & 8 deletions tests/library/har-websocket.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ function responseHeadersSize(headers: { name: string, value: string }[]): number
return result;
}

// Browser-reported message times are derived from a wall-clock baseline plus
// monotonic timestamps in the browser process, so they can drift by a few
// milliseconds relative to Date.now() in the test process.
const clockSkewMs = 100;

function messageSize(message: string | number[]): number {
// The payload is short enough that they only need the minimum frame header size.
if (message.length <= 125)
Expand Down Expand Up @@ -119,8 +124,8 @@ it('should include websocket handshake headers and status', async ({ contextFact
expect(wsEntry.response.headersSize).toBe(responseHeadersSize(wsEntry.response.headers));

const wallTimeMs = new Date(wsEntry.startedDateTime).getTime();
expect(wallTimeMs).toBeGreaterThanOrEqual(beforeMs);
expect(wallTimeMs).toBeLessThanOrEqual(afterMs);
expect(wallTimeMs).toBeGreaterThanOrEqual(beforeMs - clockSkewMs);
expect(wallTimeMs).toBeLessThanOrEqual(afterMs + clockSkewMs);

const requestHeaderNames = wsEntry.request.headers.map(h => h.name.toLowerCase());
expect(requestHeaderNames).toContain('upgrade');
Expand All @@ -142,7 +147,6 @@ async function testWebSocketMessages(contextFactory, server, testInfo, content,
const outgoingText = ['y'.repeat(125), 'y'.repeat(126), 'y'.repeat(2 ** 16)];
const outgoingBinary = [(new Array(125)).fill(0x02), (new Array(126)).fill(0x02), (new Array(2 ** 16)).fill(0x02)];
const incomingCount = incomingText.length + incomingBinary.length;
const outgoingCount = outgoingText.length + outgoingBinary.length;
const delayMs = 100;

server.onceWebSocketConnection(async ws => {
Expand Down Expand Up @@ -219,13 +223,12 @@ async function testWebSocketMessages(contextFactory, server, testInfo, content,
// message times cannot be compared against the host wall clock.
if (channel !== 'webkit-wsl') {
for (const m of messages) {
expect(m.time).toBeGreaterThanOrEqual(beforeMs - 1);
expect(m.time).toBeLessThanOrEqual(afterMs + 1);
expect(m.time).toBeGreaterThanOrEqual(beforeMs - clockSkewMs);
expect(m.time).toBeLessThanOrEqual(afterMs + clockSkewMs);
}
}
expect(messages[0].time).toBeLessThanOrEqual(messages[1].time);
expect(wsEntry.time).toBeGreaterThanOrEqual(messages[messages.length - 1].time - messages[0].time);
expect(wsEntry.time).toBeGreaterThanOrEqual(delayMs * (incomingCount + outgoingCount));
}

it('should embed websocket messages', async ({ contextFactory, server, channel }, testInfo) => {
Expand Down Expand Up @@ -297,8 +300,8 @@ it('should attach websocket messages for a still open websocket after stopping',
// message times cannot be compared against the host wall clock.
if (channel !== 'webkit-wsl') {
for (const m of messages) {
expect(m.time).toBeGreaterThanOrEqual(beforeMs - 1);
expect(m.time).toBeLessThanOrEqual(afterMs + 1);
expect(m.time).toBeGreaterThanOrEqual(beforeMs - clockSkewMs);
expect(m.time).toBeLessThanOrEqual(afterMs + clockSkewMs);
}
}
expect(messages[0].time).toBeLessThanOrEqual(messages[1].time);
Expand Down
Loading