diff --git a/new-docs/puppeteer.productlauncher.connect.md b/new-docs/puppeteer.productlauncher.connect.md
deleted file mode 100644
index 6837409e..00000000
--- a/new-docs/puppeteer.productlauncher.connect.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-[Home](./index.md) > [puppeteer](./puppeteer.md) > [ProductLauncher](./puppeteer.productlauncher.md) > [connect](./puppeteer.productlauncher.connect.md)
-
-## ProductLauncher.connect() method
-
-Signature:
-
-```typescript
-connect(object: any): any;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| object | any | |
-
-Returns:
-
-any
-
diff --git a/new-docs/puppeteer.productlauncher.md b/new-docs/puppeteer.productlauncher.md
index 4f3dc6fa..8f1595fc 100644
--- a/new-docs/puppeteer.productlauncher.md
+++ b/new-docs/puppeteer.productlauncher.md
@@ -17,13 +17,12 @@ export interface ProductLauncher
| Property | Type | Description |
| --- | --- | --- |
| [executablePath](./puppeteer.productlauncher.executablepath.md) | () => string | |
-| [product](./puppeteer.productlauncher.product.md) | string | |
+| [product](./puppeteer.productlauncher.product.md) | [Product](./puppeteer.product.md) | |
## Methods
| Method | Description |
| --- | --- |
-| [connect(object)](./puppeteer.productlauncher.connect.md) | |
| [defaultArgs(object)](./puppeteer.productlauncher.defaultargs.md) | |
| [launch(object)](./puppeteer.productlauncher.launch.md) | |
diff --git a/new-docs/puppeteer.productlauncher.product.md b/new-docs/puppeteer.productlauncher.product.md
index 6d906bad..a1d63d3c 100644
--- a/new-docs/puppeteer.productlauncher.product.md
+++ b/new-docs/puppeteer.productlauncher.product.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-product: string;
+product: Product;
```
diff --git a/new-docs/puppeteer.puppeteer.connect.md b/new-docs/puppeteer.puppeteer.connect.md
index 7e99b608..26512d0d 100644
--- a/new-docs/puppeteer.puppeteer.connect.md
+++ b/new-docs/puppeteer.puppeteer.connect.md
@@ -13,7 +13,7 @@ connect(options: BrowserOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
- product?: string;
+ product?: Product;
}): Promise;
```
@@ -21,7 +21,7 @@ connect(options: BrowserOptions & {
| Parameter | Type | Description |
| --- | --- | --- |
-| options | [BrowserOptions](./puppeteer.browseroptions.md) & { browserWSEndpoint?: string; browserURL?: string; transport?: ConnectionTransport; product?: string; } | Set of configurable options to set on the browser. |
+| options | [BrowserOptions](./puppeteer.browseroptions.md) & { browserWSEndpoint?: string; browserURL?: string; transport?: ConnectionTransport; product?: [Product](./puppeteer.product.md); } | Set of configurable options to set on the browser. |
Returns:
diff --git a/package.json b/package.json
index 6aa78977..5448ba19 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"devtools-protocol": "0.0.809251",
"extract-zip": "^2.0.0",
"https-proxy-agent": "^4.0.0",
+ "node-fetch": "^2.6.1",
"pkg-dir": "^4.2.0",
"progress": "^2.0.1",
"proxy-from-env": "^1.0.0",
diff --git a/src/api-docs-entry.ts b/src/api-docs-entry.ts
index 848a3436..c56819b2 100644
--- a/src/api-docs-entry.ts
+++ b/src/api-docs-entry.ts
@@ -41,9 +41,11 @@ export * from './common/FileChooser.js';
export * from './common/FrameManager.js';
export * from './common/Input.js';
export * from './common/Page.js';
+export * from './common/Product.js';
export * from './common/Puppeteer.js';
-export * from './node/LaunchOptions.js';
+export * from './common/BrowserConnector.js';
export * from './node/Launcher.js';
+export * from './node/LaunchOptions.js';
export * from './common/HTTPRequest.js';
export * from './common/HTTPResponse.js';
export * from './common/SecurityDetails.js';
diff --git a/src/common/BrowserConnector.ts b/src/common/BrowserConnector.ts
new file mode 100644
index 00000000..48ec8a9c
--- /dev/null
+++ b/src/common/BrowserConnector.ts
@@ -0,0 +1,109 @@
+/**
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ConnectionTransport } from './ConnectionTransport.js';
+import { Browser } from './Browser.js';
+import { assert } from './assert.js';
+import { debugError } from '../common/helper.js';
+import { Connection } from './Connection.js';
+import { WebSocketTransport } from './WebSocketTransport.js';
+import { getFetch } from './fetch.js';
+import { Viewport } from './PuppeteerViewport.js';
+
+/**
+ * Generic browser options that can be passed when launching any browser.
+ * @public
+ */
+export interface BrowserOptions {
+ ignoreHTTPSErrors?: boolean;
+ defaultViewport?: Viewport;
+ slowMo?: number;
+}
+
+/**
+ * Users should never call this directly; it's called when calling
+ * `puppeteer.connect`.
+ * @internal
+ */
+export const connectToBrowser = async (
+ options: BrowserOptions & {
+ browserWSEndpoint?: string;
+ browserURL?: string;
+ transport?: ConnectionTransport;
+ }
+) => {
+ const {
+ browserWSEndpoint,
+ browserURL,
+ ignoreHTTPSErrors = false,
+ defaultViewport = { width: 800, height: 600 },
+ transport,
+ slowMo = 0,
+ } = options;
+
+ assert(
+ Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
+ 1,
+ 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
+ );
+
+ let connection = null;
+ if (transport) {
+ connection = new Connection('', transport, slowMo);
+ } else if (browserWSEndpoint) {
+ const connectionTransport = await WebSocketTransport.create(
+ browserWSEndpoint
+ );
+ connection = new Connection(browserWSEndpoint, connectionTransport, slowMo);
+ } else if (browserURL) {
+ const connectionURL = await getWSEndpoint(browserURL);
+ const connectionTransport = await WebSocketTransport.create(connectionURL);
+ connection = new Connection(connectionURL, connectionTransport, slowMo);
+ }
+
+ const { browserContextIds } = await connection.send(
+ 'Target.getBrowserContexts'
+ );
+ return Browser.create(
+ connection,
+ browserContextIds,
+ ignoreHTTPSErrors,
+ defaultViewport,
+ null,
+ () => connection.send('Browser.close').catch(debugError)
+ );
+};
+
+async function getWSEndpoint(browserURL: string): Promise {
+ const endpointURL = new URL('/json/version', browserURL);
+
+ const fetch = await getFetch();
+ try {
+ const result = await fetch(endpointURL.toString(), {
+ method: 'GET',
+ });
+ if (!result.ok) {
+ throw new Error(`HTTP ${result.statusText}`);
+ }
+ const data = await result.json();
+ return data.webSocketDebuggerUrl;
+ } catch (error) {
+ error.message =
+ `Failed to fetch browser webSocket URL from ${endpointURL}: ` +
+ error.message;
+ throw error;
+ }
+}
diff --git a/src/common/Product.ts b/src/common/Product.ts
new file mode 100644
index 00000000..58a62fad
--- /dev/null
+++ b/src/common/Product.ts
@@ -0,0 +1,21 @@
+/**
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Supported products.
+ * @public
+ */
+export type Product = 'chrome' | 'firefox';
diff --git a/src/common/Puppeteer.ts b/src/common/Puppeteer.ts
index d324a09d..7dc50e3d 100644
--- a/src/common/Puppeteer.ts
+++ b/src/common/Puppeteer.ts
@@ -14,11 +14,7 @@
* limitations under the License.
*/
import Launcher from '../node/Launcher.js';
-import {
- LaunchOptions,
- ChromeArgOptions,
- BrowserOptions,
-} from '../node/LaunchOptions.js';
+import { LaunchOptions, ChromeArgOptions } from '../node/LaunchOptions.js';
import { ProductLauncher } from '../node/Launcher.js';
import {
BrowserFetcher,
@@ -36,6 +32,8 @@ import {
CustomQueryHandler,
} from './QueryHandler.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
+import { Product } from './Product.js';
+import { connectToBrowser, BrowserOptions } from './BrowserConnector.js';
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
@@ -141,11 +139,11 @@ export class Puppeteer {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
- product?: string;
+ product?: Product;
}
): Promise {
if (options.product) this._productName = options.product;
- return this._launcher.connect(options);
+ return connectToBrowser(options);
}
/**
diff --git a/src/common/fetch.ts b/src/common/fetch.ts
new file mode 100644
index 00000000..ae4b65c4
--- /dev/null
+++ b/src/common/fetch.ts
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { isNode } from '../environment.js';
+
+/* Use the global version if we're in the browser, else load the node-fetch module. */
+export const getFetch = async (): Promise => {
+ return isNode ? await import('node-fetch') : globalThis.fetch;
+};
diff --git a/src/node/BrowserFetcher.ts b/src/node/BrowserFetcher.ts
index f5ecdba4..4653cd23 100644
--- a/src/node/BrowserFetcher.ts
+++ b/src/node/BrowserFetcher.ts
@@ -22,6 +22,7 @@ import * as childProcess from 'child_process';
import * as https from 'https';
import * as http from 'http';
+import { Product } from '../common/Product.js';
import extractZip from 'extract-zip';
import { debug } from '../common/Debug.js';
import { promisify } from 'util';
@@ -65,11 +66,6 @@ const browserConfig = {
* @public
*/
export type Platform = 'linux' | 'mac' | 'win32' | 'win64';
-/**
- * Supported products.
- * @public
- */
-export type Product = 'chrome' | 'firefox';
function archiveName(
product: Product,
diff --git a/src/node/LaunchOptions.ts b/src/node/LaunchOptions.ts
index 0003ba87..0eb99b69 100644
--- a/src/node/LaunchOptions.ts
+++ b/src/node/LaunchOptions.ts
@@ -13,9 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import { Viewport } from '../common/PuppeteerViewport.js';
-
/**
* Launcher options that only apply to Chrome.
*
@@ -43,13 +40,3 @@ export interface LaunchOptions {
env?: Record;
pipe?: boolean;
}
-
-/**
- * Generic browser options that can be passed when launching any browser.
- * @public
- */
-export interface BrowserOptions {
- ignoreHTTPSErrors?: boolean;
- defaultViewport?: Viewport;
- slowMo?: number;
-}
diff --git a/src/node/Launcher.ts b/src/node/Launcher.ts
index 4f92a88c..49a111e0 100644
--- a/src/node/Launcher.ts
+++ b/src/node/Launcher.ts
@@ -15,29 +15,19 @@
*/
import * as os from 'os';
import * as path from 'path';
-import * as http from 'http';
-import * as https from 'https';
-import * as URL from 'url';
import * as fs from 'fs';
import { BrowserFetcher } from './BrowserFetcher.js';
-import { Connection } from '../common/Connection.js';
import { Browser } from '../common/Browser.js';
-import { assert } from '../common/assert.js';
-import { debugError } from '../common/helper.js';
-import { ConnectionTransport } from '../common/ConnectionTransport.js';
-import { WebSocketTransport } from '../common/WebSocketTransport.js';
import { BrowserRunner } from './BrowserRunner.js';
import { promisify } from 'util';
const mkdtempAsync = promisify(fs.mkdtemp);
const writeFileAsync = promisify(fs.writeFile);
-import {
- ChromeArgOptions,
- LaunchOptions,
- BrowserOptions,
-} from './LaunchOptions.js';
+import { ChromeArgOptions, LaunchOptions } from './LaunchOptions.js';
+import { BrowserOptions } from '../common/BrowserConnector.js';
+import { Product } from '../common/Product.js';
/**
* Describes a launcher - a class that is able to create and launch a browser instance.
@@ -45,10 +35,9 @@ import {
*/
export interface ProductLauncher {
launch(object);
- connect(object);
executablePath: () => string;
defaultArgs(object);
- product: string;
+ product: Product;
}
/**
@@ -215,66 +204,9 @@ class ChromeLauncher implements ProductLauncher {
return resolveExecutablePath(this).executablePath;
}
- get product(): string {
+ get product(): Product {
return 'chrome';
}
-
- async connect(
- options: BrowserOptions & {
- browserWSEndpoint?: string;
- browserURL?: string;
- transport?: ConnectionTransport;
- }
- ): Promise {
- const {
- browserWSEndpoint,
- browserURL,
- ignoreHTTPSErrors = false,
- defaultViewport = { width: 800, height: 600 },
- transport,
- slowMo = 0,
- } = options;
-
- assert(
- Number(!!browserWSEndpoint) +
- Number(!!browserURL) +
- Number(!!transport) ===
- 1,
- 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
- );
-
- let connection = null;
- if (transport) {
- connection = new Connection('', transport, slowMo);
- } else if (browserWSEndpoint) {
- const connectionTransport = await WebSocketTransport.create(
- browserWSEndpoint
- );
- connection = new Connection(
- browserWSEndpoint,
- connectionTransport,
- slowMo
- );
- } else if (browserURL) {
- const connectionURL = await getWSEndpoint(browserURL);
- const connectionTransport = await WebSocketTransport.create(
- connectionURL
- );
- connection = new Connection(connectionURL, connectionTransport, slowMo);
- }
-
- const { browserContextIds } = await connection.send(
- 'Target.getBrowserContexts'
- );
- return Browser.create(
- connection,
- browserContextIds,
- ignoreHTTPSErrors,
- defaultViewport,
- null,
- () => connection.send('Browser.close').catch(debugError)
- );
- }
}
/**
@@ -392,63 +324,6 @@ class FirefoxLauncher implements ProductLauncher {
}
}
- async connect(
- options: BrowserOptions & {
- browserWSEndpoint?: string;
- browserURL?: string;
- transport?: ConnectionTransport;
- }
- ): Promise {
- const {
- browserWSEndpoint,
- browserURL,
- ignoreHTTPSErrors = false,
- defaultViewport = { width: 800, height: 600 },
- transport,
- slowMo = 0,
- } = options;
-
- assert(
- Number(!!browserWSEndpoint) +
- Number(!!browserURL) +
- Number(!!transport) ===
- 1,
- 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
- );
-
- let connection = null;
- if (transport) {
- connection = new Connection('', transport, slowMo);
- } else if (browserWSEndpoint) {
- const connectionTransport = await WebSocketTransport.create(
- browserWSEndpoint
- );
- connection = new Connection(
- browserWSEndpoint,
- connectionTransport,
- slowMo
- );
- } else if (browserURL) {
- const connectionURL = await getWSEndpoint(browserURL);
- const connectionTransport = await WebSocketTransport.create(
- connectionURL
- );
- connection = new Connection(connectionURL, connectionTransport, slowMo);
- }
-
- const { browserContextIds } = await connection.send(
- 'Target.getBrowserContexts'
- );
- return Browser.create(
- connection,
- browserContextIds,
- ignoreHTTPSErrors,
- defaultViewport,
- null,
- () => connection.send('Browser.close').catch(debugError)
- );
- }
-
executablePath(): string {
return resolveExecutablePath(this).executablePath;
}
@@ -464,7 +339,7 @@ class FirefoxLauncher implements ProductLauncher {
}
}
- get product(): string {
+ get product(): Product {
return 'firefox';
}
@@ -705,42 +580,6 @@ class FirefoxLauncher implements ProductLauncher {
}
}
-function getWSEndpoint(browserURL: string): Promise {
- let resolve, reject;
- const promise = new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- });
-
- const endpointURL = URL.resolve(browserURL, '/json/version');
- const protocol = endpointURL.startsWith('https') ? https : http;
- const requestOptions = Object.assign(URL.parse(endpointURL), {
- method: 'GET',
- });
- const request = protocol.request(requestOptions, (res) => {
- let data = '';
- if (res.statusCode !== 200) {
- // Consume response data to free up memory.
- res.resume();
- reject(new Error('HTTP ' + res.statusCode));
- return;
- }
- res.setEncoding('utf8');
- res.on('data', (chunk) => (data += chunk));
- res.on('end', () => resolve(JSON.parse(data).webSocketDebuggerUrl));
- });
-
- request.on('error', reject);
- request.end();
-
- return promise.catch((error) => {
- error.message =
- `Failed to fetch browser webSocket url from ${endpointURL}: ` +
- error.message;
- throw error;
- });
-}
-
function resolveExecutablePath(
launcher: ChromeLauncher | FirefoxLauncher
): { executablePath: string; missingText?: string } {
diff --git a/test/chromiumonly.spec.ts b/test/chromiumonly.spec.ts
index 65d1c820..7b64a70f 100644
--- a/test/chromiumonly.spec.ts
+++ b/test/chromiumonly.spec.ts
@@ -84,7 +84,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
.connect({ browserURL })
.catch((error_) => (error = error_));
expect(error.message).toContain(
- 'Failed to fetch browser webSocket url from'
+ 'Failed to fetch browser webSocket URL from'
);
originalBrowser.close();
});
diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js
index f91205ea..d3e8fb87 100644
--- a/utils/doclint/check_public_api/index.js
+++ b/utils/doclint/check_public_api/index.js
@@ -803,6 +803,13 @@ function compareDocumentations(actual, expected) {
expectedName: 'Array