fix: end WebDriver BiDi session on disconnect (#11470)

Co-authored-by: Maksim Sadym <sadym@google.com>
This commit is contained in:
Maksim Sadym 2023-11-30 15:27:49 +01:00 committed by GitHub
parent 957a8293bb
commit a66d029607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 34 additions and 28 deletions

View File

@ -10,10 +10,10 @@ Disconnects Puppeteer from this [browser](./puppeteer.browser.md), but leaves th
```typescript ```typescript
class Browser { class Browser {
abstract disconnect(): void; abstract disconnect(): Promise<void>;
} }
``` ```
**Returns:** **Returns:**
void Promise&lt;void&gt;

View File

@ -46,7 +46,7 @@ const browser = await puppeteer.launch();
// Store the endpoint to be able to reconnect to the browser. // Store the endpoint to be able to reconnect to the browser.
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
// Disconnect puppeteer from the browser. // Disconnect puppeteer from the browser.
browser.disconnect(); await browser.disconnect();
// Use the endpoint to reestablish a connection // Use the endpoint to reestablish a connection
const browser2 = await puppeteer.connect({browserWSEndpoint}); const browser2 = await puppeteer.connect({browserWSEndpoint});

View File

@ -228,7 +228,7 @@ export interface BrowserEvents extends Record<EventType, unknown> {
* // Store the endpoint to be able to reconnect to the browser. * // Store the endpoint to be able to reconnect to the browser.
* const browserWSEndpoint = browser.wsEndpoint(); * const browserWSEndpoint = browser.wsEndpoint();
* // Disconnect puppeteer from the browser. * // Disconnect puppeteer from the browser.
* browser.disconnect(); * await browser.disconnect();
* *
* // Use the endpoint to reestablish a connection * // Use the endpoint to reestablish a connection
* const browser2 = await puppeteer.connect({browserWSEndpoint}); * const browser2 = await puppeteer.connect({browserWSEndpoint});
@ -414,7 +414,7 @@ export abstract class Browser extends EventEmitter<BrowserEvents> {
* Disconnects Puppeteer from this {@link Browser | browser}, but leaves the * Disconnects Puppeteer from this {@link Browser | browser}, but leaves the
* process running. * process running.
*/ */
abstract disconnect(): void; abstract disconnect(): Promise<void>;
/** /**
* Whether Puppeteer is connected to this {@link Browser | browser}. * Whether Puppeteer is connected to this {@link Browser | browser}.

View File

@ -49,6 +49,7 @@ export async function connectBidiOverCdp(
close(): void { close(): void {
bidiServer.close(); bidiServer.close();
cdpConnectionAdapter.close(); cdpConnectionAdapter.close();
cdp.dispose();
}, },
onmessage(_message: string): void { onmessage(_message: string): void {
// The method is overridden by the Connection. // The method is overridden by the Connection.

View File

@ -254,8 +254,8 @@ export class BidiBrowser extends Browser {
return; return;
} }
await this.#connection.send('browser.close', {}); await this.#connection.send('browser.close', {});
this.#connection.dispose();
await this.#closeCallback?.call(null); await this.#closeCallback?.call(null);
this.#connection.dispose();
} }
override get connected(): boolean { override get connected(): boolean {
@ -323,7 +323,13 @@ export class BidiBrowser extends Browser {
return this.#browserTarget; return this.#browserTarget;
} }
override disconnect(): void { override async disconnect(): Promise<void> {
this; try {
// Fail silently if the session cannot be ended.
await this.#connection.send('session.end', {});
} catch (e) {
debugError(e);
}
this.#connection.dispose();
} }
} }

View File

@ -111,6 +111,10 @@ export interface Commands {
returnType: Bidi.EmptyResult; returnType: Bidi.EmptyResult;
}; };
'session.end': {
params: Bidi.EmptyParams;
returnType: Bidi.EmptyResult;
};
'session.new': { 'session.new': {
params: Bidi.Session.NewParameters; params: Bidi.Session.NewParameters;
returnType: Bidi.Session.NewResult; returnType: Bidi.Session.NewResult;

View File

@ -410,13 +410,14 @@ export class CdpBrowser extends BrowserBase {
override async close(): Promise<void> { override async close(): Promise<void> {
await this.#closeCallback.call(null); await this.#closeCallback.call(null);
this.disconnect(); await this.disconnect();
} }
override disconnect(): void { override disconnect(): Promise<void> {
this.#targetManager.dispose(); this.#targetManager.dispose();
this.#connection.dispose(); this.#connection.dispose();
this._detach(); this._detach();
return Promise.resolve();
} }
override get connected(): boolean { override get connected(): boolean {

View File

@ -383,12 +383,6 @@
"parameters": ["chrome", "headless"], "parameters": ["chrome", "headless"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance", "testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],

View File

@ -70,7 +70,7 @@ describe('Browser specs', function () {
protocol: browser.protocol, protocol: browser.protocol,
}); });
expect(remoteBrowser.process()).toBe(null); expect(remoteBrowser.process()).toBe(null);
remoteBrowser.disconnect(); await remoteBrowser.disconnect();
}); });
}); });
@ -84,7 +84,7 @@ describe('Browser specs', function () {
protocol: browser.protocol, protocol: browser.protocol,
}); });
expect(newBrowser.isConnected()).toBe(true); expect(newBrowser.isConnected()).toBe(true);
newBrowser.disconnect(); await newBrowser.disconnect();
expect(newBrowser.isConnected()).toBe(false); expect(newBrowser.isConnected()).toBe(false);
}); });
}); });

View File

@ -230,7 +230,7 @@ describe('BrowserContext', function () {
}); });
const contexts = remoteBrowser.browserContexts(); const contexts = remoteBrowser.browserContexts();
expect(contexts).toHaveLength(2); expect(contexts).toHaveLength(2);
remoteBrowser.disconnect(); await remoteBrowser.disconnect();
await context.close(); await context.close();
}); });

View File

@ -38,7 +38,7 @@ describe('Chromium-Specific Launcher tests', function () {
return 7 * 8; return 7 * 8;
}) })
).toBe(56); ).toBe(56);
browser1.disconnect(); await browser1.disconnect();
const browser2 = await puppeteer.connect({ const browser2 = await puppeteer.connect({
browserURL: browserURL + '/', browserURL: browserURL + '/',
@ -49,7 +49,7 @@ describe('Chromium-Specific Launcher tests', function () {
return 8 * 7; return 8 * 7;
}) })
).toBe(56); ).toBe(56);
browser2.disconnect(); await browser2.disconnect();
} finally { } finally {
await close(); await close();
} }

View File

@ -52,7 +52,7 @@ describe('Launcher specs', function () {
return error_; return error_;
}); });
await server.waitForRequest('/one-style.css'); await server.waitForRequest('/one-style.css');
remote.disconnect(); await remote.disconnect();
const error = await navigationPromise; const error = await navigationPromise;
expect( expect(
[ [
@ -78,7 +78,7 @@ describe('Launcher specs', function () {
.catch(error_ => { .catch(error_ => {
return error_; return error_;
}); });
remote.disconnect(); await remote.disconnect();
const error = await watchdog; const error = await watchdog;
expect(error.message).toContain('Session closed.'); expect(error.message).toContain('Session closed.');
} finally { } finally {
@ -635,7 +635,7 @@ describe('Launcher specs', function () {
return 7 * 8; return 7 * 8;
}) })
).toBe(56); ).toBe(56);
otherBrowser.disconnect(); await otherBrowser.disconnect();
const secondPage = await browser.newPage(); const secondPage = await browser.newPage();
expect( expect(
@ -776,7 +776,7 @@ describe('Launcher specs', function () {
await page2.close(); await page2.close();
await page1.close(); await page1.close();
remoteBrowser.disconnect(); await remoteBrowser.disconnect();
await browser.close(); await browser.close();
} finally { } finally {
await close(); await close();
@ -788,7 +788,7 @@ describe('Launcher specs', function () {
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.PREFIX + '/frames/nested-frames.html'); await page.goto(server.PREFIX + '/frames/nested-frames.html');
browser.disconnect(); await browser.disconnect();
const remoteBrowser = await puppeteer.connect({ const remoteBrowser = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
@ -858,7 +858,7 @@ describe('Launcher specs', function () {
const browserWSEndpoint = browserOne.wsEndpoint(); const browserWSEndpoint = browserOne.wsEndpoint();
const pageOne = await browserOne.newPage(); const pageOne = await browserOne.newPage();
await pageOne.goto(server.EMPTY_PAGE); await pageOne.goto(server.EMPTY_PAGE);
browserOne.disconnect(); await browserOne.disconnect();
const browserTwo = await puppeteer.connect({ const browserTwo = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,

View File

@ -418,7 +418,7 @@ describe('OOPIF', function () {
return target.url().endsWith('dynamic-oopif.html'); return target.url().endsWith('dynamic-oopif.html');
}); });
await target.page(); await target.page();
browser1.disconnect(); await browser1.disconnect();
}); });
it('should support lazy OOP frames', async () => { it('should support lazy OOP frames', async () => {