feat: detect Firefox in connect() automatically (#8718)

This PR implements automatic detection of the Firefox product when the `.connect()` method is used. This partially undoes the breaking change in https://github.com/puppeteer/puppeteer/pull/8520 but it's also a breaking change on its own since we don't accept an explicit product name anymore (it does not look like it was used anyway).
This commit is contained in:
Alex Rudenko 2022-08-02 10:50:05 +02:00 committed by Randolf J
parent fae4fa5915
commit 2abd772c9c
8 changed files with 17 additions and 54 deletions

View File

@ -18,5 +18,4 @@ export interface ConnectOptions extends BrowserConnectOptions
| --------------------------------------------------------------------- | --------- | --------------------------------------------------------- | ----------------- | | --------------------------------------------------------------------- | --------- | --------------------------------------------------------- | ----------------- |
| [browserURL?](./puppeteer.connectoptions.browserurl.md) | | string | <i>(Optional)</i> | | [browserURL?](./puppeteer.connectoptions.browserurl.md) | | string | <i>(Optional)</i> |
| [browserWSEndpoint?](./puppeteer.connectoptions.browserwsendpoint.md) | | string | <i>(Optional)</i> | | [browserWSEndpoint?](./puppeteer.connectoptions.browserwsendpoint.md) | | string | <i>(Optional)</i> |
| [product?](./puppeteer.connectoptions.product.md) | | [Product](./puppeteer.product.md) | <i>(Optional)</i> |
| [transport?](./puppeteer.connectoptions.transport.md) | | [ConnectionTransport](./puppeteer.connectiontransport.md) | <i>(Optional)</i> | | [transport?](./puppeteer.connectoptions.transport.md) | | [ConnectionTransport](./puppeteer.connectiontransport.md) | <i>(Optional)</i> |

View File

@ -1,13 +0,0 @@
---
sidebar_label: ConnectOptions.product
---
# ConnectOptions.product property
**Signature:**
```typescript
interface ConnectOptions {
product?: Product;
}
```

View File

@ -26,7 +26,6 @@ import {Connection} from './Connection.js';
import {ConnectionTransport} from './ConnectionTransport.js'; import {ConnectionTransport} from './ConnectionTransport.js';
import {getFetch} from './fetch.js'; import {getFetch} from './fetch.js';
import {Viewport} from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
import {Product} from './Product.js';
/** /**
* Generic browser options that can be passed when launching any browser or when * Generic browser options that can be passed when launching any browser or when
* connecting to an existing browser instance. * connecting to an existing browser instance.
@ -75,7 +74,6 @@ export async function _connectToBrowser(
browserWSEndpoint?: string; browserWSEndpoint?: string;
browserURL?: string; browserURL?: string;
transport?: ConnectionTransport; transport?: ConnectionTransport;
product?: Product;
} }
): Promise<Browser> { ): Promise<Browser> {
const { const {
@ -87,7 +85,6 @@ export async function _connectToBrowser(
slowMo = 0, slowMo = 0,
targetFilter, targetFilter,
_isPageTarget: isPageTarget, _isPageTarget: isPageTarget,
product,
} = options; } = options;
assert( assert(
@ -111,6 +108,11 @@ export async function _connectToBrowser(
await WebSocketClass.create(connectionURL); await WebSocketClass.create(connectionURL);
connection = new Connection(connectionURL, connectionTransport, slowMo); connection = new Connection(connectionURL, connectionTransport, slowMo);
} }
const version = await connection.send('Browser.getVersion');
const product = version.product.toLowerCase().includes('firefox')
? 'firefox'
: 'chrome';
const {browserContextIds} = await connection.send( const {browserContextIds} = await connection.send(
'Target.getBrowserContexts' 'Target.getBrowserContexts'

View File

@ -19,7 +19,6 @@ import {ConnectionTransport} from './ConnectionTransport.js';
import {devices} from './DeviceDescriptors.js'; import {devices} from './DeviceDescriptors.js';
import {errors} from './Errors.js'; import {errors} from './Errors.js';
import {networkConditions} from './NetworkConditions.js'; import {networkConditions} from './NetworkConditions.js';
import {Product} from './Product.js';
import { import {
clearCustomQueryHandlers, clearCustomQueryHandlers,
CustomQueryHandler, CustomQueryHandler,
@ -43,7 +42,6 @@ export interface ConnectOptions extends BrowserConnectOptions {
browserWSEndpoint?: string; browserWSEndpoint?: string;
browserURL?: string; browserURL?: string;
transport?: ConnectionTransport; transport?: ConnectionTransport;
product?: Product;
} }
/** /**

View File

@ -110,9 +110,6 @@ export class PuppeteerNode extends Puppeteer {
* @returns Promise which resolves to browser instance. * @returns Promise which resolves to browser instance.
*/ */
override connect(options: ConnectOptions): Promise<Browser> { override connect(options: ConnectOptions): Promise<Browser> {
if (options.product) {
this._productName = options.product;
}
return super.connect(options); return super.connect(options);
} }

View File

@ -63,12 +63,11 @@ describe('Browser specs', function () {
expect(process!.pid).toBeGreaterThan(0); expect(process!.pid).toBeGreaterThan(0);
}); });
it('should not return child_process for remote browser', async () => { it('should not return child_process for remote browser', async () => {
const {browser, puppeteer, isFirefox} = getTestState(); const {browser, puppeteer} = getTestState();
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
const remoteBrowser = await puppeteer.connect({ const remoteBrowser = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
}); });
expect(remoteBrowser.process()).toBe(null); expect(remoteBrowser.process()).toBe(null);
remoteBrowser.disconnect(); remoteBrowser.disconnect();
@ -77,12 +76,11 @@ describe('Browser specs', function () {
describe('Browser.isConnected', () => { describe('Browser.isConnected', () => {
it('should set the browser connected state', async () => { it('should set the browser connected state', async () => {
const {browser, puppeteer, isFirefox} = getTestState(); const {browser, puppeteer} = getTestState();
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
const newBrowser = await puppeteer.connect({ const newBrowser = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
}); });
expect(newBrowser.isConnected()).toBe(true); expect(newBrowser.isConnected()).toBe(true);
newBrowser.disconnect(); newBrowser.disconnect();

View File

@ -68,8 +68,7 @@ describe('Fixtures', function () {
expect(dumpioData).toContain('DevTools listening on ws://'); expect(dumpioData).toContain('DevTools listening on ws://');
}); });
it('should close the browser when the node process closes', async () => { it('should close the browser when the node process closes', async () => {
const {defaultBrowserOptions, puppeteerPath, puppeteer, isFirefox} = const {defaultBrowserOptions, puppeteerPath, puppeteer} = getTestState();
getTestState();
const {spawn, execSync} = await import('child_process'); const {spawn, execSync} = await import('child_process');
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
@ -94,7 +93,6 @@ describe('Fixtures', function () {
}); });
const browser = await puppeteer.connect({ const browser = await puppeteer.connect({
browserWSEndpoint: await wsEndPointPromise, browserWSEndpoint: await wsEndPointPromise,
product: isFirefox ? 'firefox' : 'chrome',
}); });
const promises = [ const promises = [
new Promise(resolve => { new Promise(resolve => {

View File

@ -139,13 +139,11 @@ describe('Launcher specs', function () {
describe('Browser.disconnect', function () { describe('Browser.disconnect', function () {
it('should reject navigation when browser closes', async () => { it('should reject navigation when browser closes', async () => {
const {server, puppeteer, defaultBrowserOptions, isFirefox} = const {server, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
server.setRoute('/one-style.css', () => {}); server.setRoute('/one-style.css', () => {});
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const remote = await puppeteer.connect({ const remote = await puppeteer.connect({
browserWSEndpoint: browser.wsEndpoint(), browserWSEndpoint: browser.wsEndpoint(),
product: isFirefox ? 'firefox' : 'chrome',
}); });
const page = await remote.newPage(); const page = await remote.newPage();
const navigationPromise = page const navigationPromise = page
@ -165,14 +163,12 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
}); });
it('should reject waitForSelector when browser closes', async () => { it('should reject waitForSelector when browser closes', async () => {
const {server, puppeteer, defaultBrowserOptions, isFirefox} = const {server, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const remote = await puppeteer.connect({ const remote = await puppeteer.connect({
browserWSEndpoint: browser.wsEndpoint(), browserWSEndpoint: browser.wsEndpoint(),
product: isFirefox ? 'firefox' : 'chrome',
}); });
const page = await remote.newPage(); const page = await remote.newPage();
const watchdog = page const watchdog = page
@ -188,13 +184,11 @@ describe('Launcher specs', function () {
}); });
describe('Browser.close', function () { describe('Browser.close', function () {
it('should terminate network waiters', async () => { it('should terminate network waiters', async () => {
const {server, puppeteer, defaultBrowserOptions, isFirefox} = const {server, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const remote = await puppeteer.connect({ const remote = await puppeteer.connect({
browserWSEndpoint: browser.wsEndpoint(), browserWSEndpoint: browser.wsEndpoint(),
product: isFirefox ? 'firefox' : 'chrome',
}); });
const newPage = await remote.newPage(); const newPage = await remote.newPage();
const results = await Promise.all([ const results = await Promise.all([
@ -671,12 +665,11 @@ describe('Launcher specs', function () {
describe('Puppeteer.connect', function () { describe('Puppeteer.connect', function () {
it('should be able to connect multiple times to the same browser', async () => { it('should be able to connect multiple times to the same browser', async () => {
const {puppeteer, defaultBrowserOptions, isFirefox} = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const otherBrowser = await puppeteer.connect({ const otherBrowser = await puppeteer.connect({
browserWSEndpoint: originalBrowser.wsEndpoint(), browserWSEndpoint: originalBrowser.wsEndpoint(),
product: isFirefox ? 'firefox' : 'chrome',
}); });
const page = await otherBrowser.newPage(); const page = await otherBrowser.newPage();
expect( expect(
@ -695,12 +688,11 @@ describe('Launcher specs', function () {
await originalBrowser.close(); await originalBrowser.close();
}); });
it('should be able to close remote browser', async () => { it('should be able to close remote browser', async () => {
const {defaultBrowserOptions, puppeteer, isFirefox} = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const remoteBrowser = await puppeteer.connect({ const remoteBrowser = await puppeteer.connect({
browserWSEndpoint: originalBrowser.wsEndpoint(), browserWSEndpoint: originalBrowser.wsEndpoint(),
product: isFirefox ? 'firefox' : 'chrome',
}); });
await Promise.all([ await Promise.all([
utils.waitEvent(originalBrowser, 'disconnected'), utils.waitEvent(originalBrowser, 'disconnected'),
@ -708,8 +700,7 @@ describe('Launcher specs', function () {
]); ]);
}); });
it('should support ignoreHTTPSErrors option', async () => { it('should support ignoreHTTPSErrors option', async () => {
const {httpsServer, puppeteer, defaultBrowserOptions, isFirefox} = const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -717,7 +708,6 @@ describe('Launcher specs', function () {
const browser = await puppeteer.connect({ const browser = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
product: isFirefox ? 'firefox' : 'chrome',
}); });
const page = await browser.newPage(); const page = await browser.newPage();
let error!: Error; let error!: Error;
@ -739,8 +729,7 @@ describe('Launcher specs', function () {
}); });
// @see https://github.com/puppeteer/puppeteer/issues/4197 // @see https://github.com/puppeteer/puppeteer/issues/4197
itFailsFirefox('should support targetFilter option', async () => { itFailsFirefox('should support targetFilter option', async () => {
const {server, puppeteer, defaultBrowserOptions, isFirefox} = const {server, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -753,7 +742,6 @@ describe('Launcher specs', function () {
const browser = await puppeteer.connect({ const browser = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
targetFilter: (targetInfo: Protocol.Target.TargetInfo) => { targetFilter: (targetInfo: Protocol.Target.TargetInfo) => {
return !targetInfo.url?.includes('should-be-ignored'); return !targetInfo.url?.includes('should-be-ignored');
}, },
@ -837,8 +825,7 @@ describe('Launcher specs', function () {
} }
); );
it('should be able to reconnect', async () => { it('should be able to reconnect', async () => {
const {puppeteer, server, defaultBrowserOptions, isFirefox} = const {puppeteer, server, defaultBrowserOptions} = getTestState();
getTestState();
const browserOne = await puppeteer.launch(defaultBrowserOptions); const browserOne = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = browserOne.wsEndpoint(); const browserWSEndpoint = browserOne.wsEndpoint();
const pageOne = await browserOne.newPage(); const pageOne = await browserOne.newPage();
@ -847,7 +834,6 @@ describe('Launcher specs', function () {
const browserTwo = await puppeteer.connect({ const browserTwo = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
}); });
const pages = await browserTwo.pages(); const pages = await browserTwo.pages();
const pageTwo = pages.find(page => { const pageTwo = pages.find(page => {
@ -991,16 +977,14 @@ describe('Launcher specs', function () {
itFailsFirefox( itFailsFirefox(
'should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', 'should be emitted when: browser gets closed, disconnected or underlying websocket gets closed',
async () => { async () => {
const {puppeteer, defaultBrowserOptions, isFirefox} = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
const remoteBrowser1 = await puppeteer.connect({ const remoteBrowser1 = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
}); });
const remoteBrowser2 = await puppeteer.connect({ const remoteBrowser2 = await puppeteer.connect({
browserWSEndpoint, browserWSEndpoint,
product: isFirefox ? 'firefox' : 'chrome',
}); });
let disconnectedOriginal = 0; let disconnectedOriginal = 0;