Skip to content

Commit b7d0c32

Browse files
fix(browser): wait for the pipe to disconnect in browser.close (#1652)
With WebKit, sometimes the process closes before the stdio is streams are closed. I explicitly wait for the browser disconnect event now when closing.
1 parent b89df07 commit b7d0c32

File tree

5 files changed

+24
-48
lines changed

5 files changed

+24
-48
lines changed

src/browser.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,27 @@ import { Page } from './page';
1919
import { EventEmitter } from 'events';
2020
import { Download } from './download';
2121
import { debugProtocol } from './transport';
22+
import type { BrowserServer } from './server/browserServer';
23+
import { Events } from './events';
2224

2325
export interface Browser extends EventEmitter {
2426
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
2527
contexts(): BrowserContext[];
2628
newPage(options?: BrowserContextOptions): Promise<Page>;
2729
isConnected(): boolean;
2830
close(): Promise<void>;
29-
_disconnect(): Promise<void>;
3031
}
3132

3233
export abstract class BrowserBase extends EventEmitter implements Browser {
3334
_downloadsPath: string = '';
3435
private _downloads = new Map<string, Download>();
3536
_debugProtocol = debugProtocol;
37+
_ownedServer: BrowserServer | null = null;
3638

3739
abstract newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
3840
abstract contexts(): BrowserContext[];
3941
abstract isConnected(): boolean;
40-
abstract close(): Promise<void>;
41-
abstract _disconnect(): Promise<void>;
42+
abstract _disconnect(): void;
4243

4344
async newPage(options?: BrowserContextOptions): Promise<Page> {
4445
const context = await this.newContext(options);
@@ -59,6 +60,17 @@ export abstract class BrowserBase extends EventEmitter implements Browser {
5960
download._reportFinished(error);
6061
this._downloads.delete(uuid);
6162
}
63+
64+
async close() {
65+
if (this._ownedServer) {
66+
await this._ownedServer.close();
67+
} else {
68+
await Promise.all(this.contexts().map(context => context.close()));
69+
this._disconnect();
70+
}
71+
if (this.isConnected())
72+
await new Promise(x => this.once(Events.Browser.Disconnected, x));
73+
}
6274
}
6375

6476
export type LaunchType = 'local' | 'server' | 'persistent';

src/chromium/crBrowser.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import { readProtocolStream } from './crProtocolHelper';
2929
import { Events } from './events';
3030
import { Protocol } from './protocol';
3131
import { CRExecutionContext } from './crExecutionContext';
32-
import { BrowserServer } from '../server/browserServer';
3332

3433
export class CRBrowser extends BrowserBase {
3534
readonly _connection: CRConnection;
@@ -46,7 +45,6 @@ export class CRBrowser extends BrowserBase {
4645
private _tracingRecording = false;
4746
private _tracingPath: string | null = '';
4847
private _tracingClient: CRSession | undefined;
49-
_ownedServer: BrowserServer | null = null;
5048

5149
static async connect(transport: ConnectionTransport, isPersistent: boolean, slowMo?: number): Promise<CRBrowser> {
5250
const connection = new CRConnection(SlowMoTransport.wrap(transport, slowMo));
@@ -180,18 +178,8 @@ export class CRBrowser extends BrowserBase {
180178
await this._session.send('Target.closeTarget', { targetId: crPage._targetId });
181179
}
182180

183-
async _disconnect() {
184-
const disconnected = new Promise(f => this._connection.once(ConnectionEvents.Disconnected, f));
185-
await Promise.all(this.contexts().map(context => context.close()));
181+
_disconnect() {
186182
this._connection.close();
187-
await disconnected;
188-
}
189-
190-
async close() {
191-
if (this._ownedServer)
192-
await this._ownedServer.close();
193-
else
194-
await this._disconnect();
195183
}
196184

197185
async newBrowserCDPSession(): Promise<CRSession> {

src/firefox/ffBrowser.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { ConnectionEvents, FFConnection } from './ffConnection';
2727
import { headersArray } from './ffNetworkManager';
2828
import { FFPage } from './ffPage';
2929
import { Protocol } from './protocol';
30-
import { BrowserServer } from '../server/browserServer';
3130

3231
export class FFBrowser extends BrowserBase {
3332
_connection: FFConnection;
@@ -37,7 +36,6 @@ export class FFBrowser extends BrowserBase {
3736
private _eventListeners: RegisteredListener[];
3837
readonly _firstPagePromise: Promise<void>;
3938
private _firstPageCallback = () => {};
40-
_ownedServer: BrowserServer | null = null;
4139

4240
static async connect(transport: ConnectionTransport, attachToDefaultContext: boolean, slowMo?: number): Promise<FFBrowser> {
4341
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo));
@@ -137,19 +135,9 @@ export class FFBrowser extends BrowserBase {
137135
});
138136
}
139137

140-
async _disconnect() {
141-
await Promise.all(this.contexts().map(context => context.close()));
138+
_disconnect() {
142139
helper.removeEventListeners(this._eventListeners);
143-
const disconnected = new Promise(f => this.once(Events.Browser.Disconnected, f));
144140
this._connection.close();
145-
await disconnected;
146-
}
147-
148-
async close() {
149-
if (this._ownedServer)
150-
await this._ownedServer.close();
151-
else
152-
await this._disconnect();
153141
}
154142
}
155143

src/server/webkit.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class WebKit implements BrowserType<WKBrowser> {
4848
async launch(options: LaunchOptions = {}): Promise<WKBrowser> {
4949
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
5050
const { browserServer, transport, downloadsPath } = await this._launchServer(options, 'local');
51-
const browser = await WKBrowser.connect(transport!, options.slowMo, false, () => browserServer.close());
51+
const browser = await WKBrowser.connect(transport!, options.slowMo, false);
5252
browser._ownedServer = browserServer;
5353
browser._downloadsPath = downloadsPath;
5454
return browser;
@@ -64,7 +64,8 @@ export class WebKit implements BrowserType<WKBrowser> {
6464
slowMo = 0,
6565
} = options;
6666
const { transport, browserServer } = await this._launchServer(options, 'persistent', userDataDir);
67-
const browser = await WKBrowser.connect(transport!, slowMo, true, () => browserServer.close());
67+
const browser = await WKBrowser.connect(transport!, slowMo, true);
68+
browser._ownedServer = browserServer;
6869
await helper.waitWithTimeout(browser._waitForFirstPageTarget(), 'first page', timeout);
6970
return browser._defaultContext;
7071
}

src/webkit/wkBrowser.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import * as types from '../types';
2626
import { Protocol } from './protocol';
2727
import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnection, WKSession } from './wkConnection';
2828
import { WKPage } from './wkPage';
29-
import { BrowserServer } from '../server/browserServer';
3029

3130
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15';
3231

@@ -43,18 +42,16 @@ export class WKBrowser extends BrowserBase {
4342

4443
private _firstPageCallback: () => void = () => {};
4544
private readonly _firstPagePromise: Promise<void>;
46-
_ownedServer: BrowserServer | null = null;
4745

48-
static async connect(transport: ConnectionTransport, slowMo: number = 0, attachToDefaultContext: boolean = false, closeOverride?: () => Promise<void>): Promise<WKBrowser> {
49-
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo), attachToDefaultContext, closeOverride);
46+
static async connect(transport: ConnectionTransport, slowMo: number = 0, attachToDefaultContext: boolean = false): Promise<WKBrowser> {
47+
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo), attachToDefaultContext);
5048
return browser;
5149
}
5250

53-
constructor(transport: ConnectionTransport, attachToDefaultContext: boolean, closeOverride?: () => Promise<void>) {
51+
constructor(transport: ConnectionTransport, attachToDefaultContext: boolean) {
5452
super();
5553
this._connection = new WKConnection(transport, this._onDisconnect.bind(this));
5654
this._attachToDefaultContext = attachToDefaultContext;
57-
this._closeOverride = closeOverride;
5855
this._browserSession = this._connection.browserSession;
5956

6057
this._defaultContext = new WKBrowserContext(this, undefined, validateBrowserContextOptions({}));
@@ -190,19 +187,9 @@ export class WKBrowser extends BrowserBase {
190187
return !this._connection.isClosed();
191188
}
192189

193-
async _disconnect() {
190+
_disconnect() {
194191
helper.removeEventListeners(this._eventListeners);
195-
const disconnected = new Promise(f => this.once(Events.Browser.Disconnected, f));
196-
await Promise.all(this.contexts().map(context => context.close()));
197192
this._connection.close();
198-
await disconnected;
199-
}
200-
201-
async close() {
202-
if (this._closeOverride)
203-
await this._closeOverride();
204-
else
205-
await this._disconnect();
206193
}
207194
}
208195

0 commit comments

Comments
 (0)