Skip to content

Commit d367a2e

Browse files
chore(tests): log protocol messages when a test fails on the bots (#963)
Similarly to how we handle stdio, this captures all protocol messages and logs them when a test fails. Great for when debugging tests in parallel or for bot failures! Currently I made `DEBUGP=true` turn this on locally, and turned it on always for the CI. Open to suggestions for a better environment variable. I would turn it on by default always, like the stdio logging, but it adds an enormous amount of noise to our error messages.
1 parent 8abf35c commit d367a2e

File tree

8 files changed

+37
-15
lines changed

8 files changed

+37
-15
lines changed

src/browser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface Browser extends platform.EventEmitterType {
2424
newPage(options?: BrowserContextOptions): Promise<Page>;
2525
isConnected(): boolean;
2626
close(): Promise<void>;
27+
_setDebugFunction(debugFunction: (message: string) => void): void;
2728
}
2829

2930
export type ConnectOptions = {

src/chromium/crBrowser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,8 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
304304
isConnected(): boolean {
305305
return !this._connection._closed;
306306
}
307+
308+
_setDebugFunction(debugFunction: (message: string) => void) {
309+
this._connection._debugProtocol = debugFunction;
310+
}
307311
}

src/chromium/crConnection.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import { ConnectionTransport } from '../transport';
2020
import { assert } from '../helper';
2121
import { Protocol } from './protocol';
2222

23-
const debugProtocol = platform.debug('pw:protocol');
24-
2523
export const ConnectionEvents = {
2624
Disconnected: Symbol('ConnectionEvents.Disconnected')
2725
};
@@ -36,6 +34,7 @@ export class CRConnection extends platform.EventEmitter {
3634
private _sessions = new Map<string, CRSession>();
3735
readonly rootSession: CRSession;
3836
_closed = false;
37+
_debugProtocol: (message: string) => void;
3938

4039
constructor(transport: ConnectionTransport) {
4140
super();
@@ -44,6 +43,7 @@ export class CRConnection extends platform.EventEmitter {
4443
this._transport.onclose = this._onClose.bind(this);
4544
this.rootSession = new CRSession(this, 'browser', '');
4645
this._sessions.set('', this.rootSession);
46+
this._debugProtocol = platform.debug('pw:protocol');
4747
}
4848

4949
static fromSession(session: CRSession): CRConnection {
@@ -60,13 +60,13 @@ export class CRConnection extends platform.EventEmitter {
6060
if (sessionId)
6161
message.sessionId = sessionId;
6262
const data = JSON.stringify(message);
63-
debugProtocol('SEND ► ' + data);
63+
this._debugProtocol('SEND ► ' + data);
6464
this._transport.send(data);
6565
return id;
6666
}
6767

6868
async _onMessage(message: string) {
69-
debugProtocol('◀ RECV ' + message);
69+
this._debugProtocol('◀ RECV ' + message);
7070
const object = JSON.parse(message);
7171
if (object.id === kBrowserCloseMessageId)
7272
return;

src/firefox/ffBrowser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
242242
}, options);
243243
return context;
244244
}
245+
246+
_setDebugFunction(debugFunction: (message: string) => void) {
247+
this._connection._debugProtocol = debugFunction;
248+
}
245249
}
246250

247251
class Target {

src/firefox/ffConnection.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import * as platform from '../platform';
2020
import { ConnectionTransport } from '../transport';
2121
import { Protocol } from './protocol';
2222

23-
const debugProtocol = platform.debug('pw:protocol');
24-
2523
export const ConnectionEvents = {
2624
Disconnected: Symbol('Disconnected'),
2725
};
@@ -35,6 +33,7 @@ export class FFConnection extends platform.EventEmitter {
3533
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
3634
private _transport: ConnectionTransport;
3735
private _sessions: Map<string, FFSession>;
36+
_debugProtocol: (message: string) => void = platform.debug('pw:protocol');
3837
_closed: boolean;
3938

4039
on: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
@@ -86,12 +85,12 @@ export class FFConnection extends platform.EventEmitter {
8685

8786
_rawSend(message: any) {
8887
message = JSON.stringify(message);
89-
debugProtocol('SEND ► ' + message);
88+
this._debugProtocol('SEND ► ' + message);
9089
this._transport.send(message);
9190
}
9291

9392
async _onMessage(message: string) {
94-
debugProtocol('◀ RECV ' + message);
93+
this._debugProtocol('◀ RECV ' + message);
9594
const object = JSON.parse(message);
9695
if (object.id === kBrowserCloseMessageId)
9796
return;

src/webkit/wkBrowser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,8 @@ export class WKBrowser extends platform.EventEmitter implements Browser {
239239
}, options);
240240
return context;
241241
}
242+
243+
_setDebugFunction(debugFunction: (message: string) => void) {
244+
this._connection._debugFunction = debugFunction;
245+
}
242246
}

src/webkit/wkConnection.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import * as platform from '../platform';
2020
import { ConnectionTransport } from '../transport';
2121
import { Protocol } from './protocol';
2222

23-
const debugProtocol = platform.debug('pw:protocol');
24-
2523
// WKPlaywright uses this special id to issue Browser.close command which we
2624
// should ignore.
2725
export const kBrowserCloseMessageId = -9999;
@@ -36,6 +34,7 @@ export class WKConnection {
3634
private readonly _transport: ConnectionTransport;
3735
private _closed = false;
3836
private _onDisconnect: () => void;
37+
_debugFunction: (message: string) => void = platform.debug('pw:protocol');
3938

4039
readonly browserSession: WKSession;
4140

@@ -55,12 +54,12 @@ export class WKConnection {
5554

5655
rawSend(message: any) {
5756
message = JSON.stringify(message);
58-
debugProtocol('SEND ► ' + message);
57+
this._debugFunction('SEND ► ' + message);
5958
this._transport.send(message);
6059
}
6160

6261
private _dispatchMessage(message: string) {
63-
debugProtocol('◀ RECV ' + message);
62+
this._debugFunction('◀ RECV ' + message);
6463
const object = JSON.parse(message);
6564
if (object.id === kBrowserCloseMessageId)
6665
return;

test/playwright.spec.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,16 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
4242
const playwrightModule = require(playwrightPath);
4343
const playwright = playwrightModule[product.toLowerCase()];
4444

45-
const headless = (process.env.HEADLESS || 'true').trim().toLowerCase() === 'true';
46-
const slowMo = parseInt((process.env.SLOW_MO || '0').trim(), 10);
47-
45+
const headless = !!valueFromEnv('HEADLESS', true);
46+
const slowMo = valueFromEnv('SLOW_MO', 0);
47+
const CI = valueFromEnv('CI', false);
48+
const dumpProtocolOnFailure = CI || valueFromEnv('DEBUGP', true);
49+
50+
function valueFromEnv(name, defaultValue) {
51+
if (!(name in process.env))
52+
return defaultValue;
53+
return JSON.parse(process.env[name]);
54+
}
4855
const executablePath = {
4956
'Chromium': process.env.CRPATH,
5057
'Firefox': process.env.FFPATH,
@@ -108,6 +115,8 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
108115
beforeEach(async(state, test) => {
109116
const contexts = [];
110117
const onLine = (line) => test.output += line + '\n';
118+
if (dumpProtocolOnFailure)
119+
state.browser._setDebugFunction(onLine);
111120

112121
let rl;
113122
if (state.browserServer.process().stderr) {
@@ -123,6 +132,8 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
123132
rl.removeListener('line', onLine);
124133
rl.close();
125134
}
135+
if (dumpProtocolOnFailure)
136+
state.browser._setDebugFunction(() => void 0);
126137
};
127138

128139
state.newContext = async (options) => {

0 commit comments

Comments
 (0)