From e655bb6ca22e559ae95f3342a5ad5e954ce4649f Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Tue, 13 Oct 2020 16:19:26 +0100 Subject: [PATCH] chore(agnostification): split up root Puppeteer class (#6504) The `Puppeteer` class had two concerns: * connect to an existing browser * launch a new browser The first of those concerns is needed in all environments, but the second is only needed in Node. https://github.com/puppeteer/puppeteer/pull/6484 landing enabled us to pull the `Puppeteer` class apart into two: 1. `Puppeteer` which hosts the behaviour for connecting to existing browsers. 2. `PuppeteerNode`, which extends `Puppeteer` and also adds the ability to launch a new browser. This is a non-breaking change, because Node users will still get an instance of a class with all the methods they expect, but it'll be a `PuppeteerNode` rather than `Puppeteer`. I don't expect this to cause people any issues. We also now have new files that are effectively the entry points for Puppeteer: * `node.ts`: the main entry point for Puppeteer on Node. * `web.ts`: the main entry point for Puppeteer on the web. * `node-puppeteer-core.ts`: for those using puppeteer-core (which only exists in Node, not on the web). --- cjs-entry-core.js | 2 +- cjs-entry.js | 2 +- new-docs/puppeteer.browser.md | 2 +- .../puppeteer.connectoptions.browserurl.md | 11 + ...peteer.connectoptions.browserwsendpoint.md | 11 + new-docs/puppeteer.connectoptions.md | 22 ++ new-docs/puppeteer.connectoptions.product.md | 11 + .../puppeteer.connectoptions.transport.md | 11 + new-docs/puppeteer.md | 6 +- .../puppeteer.puppeteer._changedproduct.md | 11 + .../puppeteer.puppeteer._ispuppeteercore.md | 11 + new-docs/puppeteer.puppeteer.connect.md | 9 +- new-docs/puppeteer.puppeteer.md | 29 +-- new-docs/puppeteer.puppeteernode.connect.md | 29 +++ ...eer.puppeteernode.createbrowserfetcher.md} | 4 +- ...=> puppeteer.puppeteernode.defaultargs.md} | 4 +- ...puppeteer.puppeteernode.executablepath.md} | 4 +- ...h.md => puppeteer.puppeteernode.launch.md} | 8 +- new-docs/puppeteer.puppeteernode.md | 59 +++++ ....md => puppeteer.puppeteernode.product.md} | 4 +- new-docs/puppeteer.timeouterror.md | 2 +- src/api-docs-entry.ts | 6 +- src/common/Browser.ts | 2 +- src/common/Errors.ts | 2 +- src/common/Puppeteer.ts | 210 ++-------------- src/initialize-node.ts | 18 +- src/initialize-web.ts | 14 +- src/{index.ts => node-puppeteer-core.ts} | 10 +- src/{index-core.ts => node.ts} | 10 +- src/node/Puppeteer.ts | 230 ++++++++++++++++++ src/node/install.ts | 8 +- src/web.ts | 24 ++ test/coverage-utils.js | 1 + test/launcher.spec.ts | 1 + test/mocha-utils.ts | 6 +- utils/doclint/check_public_api/index.js | 36 ++- 36 files changed, 549 insertions(+), 281 deletions(-) create mode 100644 new-docs/puppeteer.connectoptions.browserurl.md create mode 100644 new-docs/puppeteer.connectoptions.browserwsendpoint.md create mode 100644 new-docs/puppeteer.connectoptions.md create mode 100644 new-docs/puppeteer.connectoptions.product.md create mode 100644 new-docs/puppeteer.connectoptions.transport.md create mode 100644 new-docs/puppeteer.puppeteer._changedproduct.md create mode 100644 new-docs/puppeteer.puppeteer._ispuppeteercore.md create mode 100644 new-docs/puppeteer.puppeteernode.connect.md rename new-docs/{puppeteer.puppeteer.createbrowserfetcher.md => puppeteer.puppeteernode.createbrowserfetcher.md} (75%) rename new-docs/{puppeteer.puppeteer.defaultargs.md => puppeteer.puppeteernode.defaultargs.md} (76%) rename new-docs/{puppeteer.puppeteer.executablepath.md => puppeteer.puppeteernode.executablepath.md} (77%) rename new-docs/{puppeteer.puppeteer.launch.md => puppeteer.puppeteernode.launch.md} (82%) create mode 100644 new-docs/puppeteer.puppeteernode.md rename new-docs/{puppeteer.puppeteer.product.md => puppeteer.puppeteernode.product.md} (77%) rename src/{index.ts => node-puppeteer-core.ts} (79%) rename src/{index-core.ts => node.ts} (76%) create mode 100644 src/node/Puppeteer.ts create mode 100644 src/web.ts diff --git a/cjs-entry-core.js b/cjs-entry-core.js index 70e9b88040f..446726fafa3 100644 --- a/cjs-entry-core.js +++ b/cjs-entry-core.js @@ -25,5 +25,5 @@ * This means that we can publish to CJS and ESM whilst maintaining the expected * import behaviour for CJS and ESM users. */ -const puppeteerExport = require('./lib/cjs/puppeteer/index-core'); +const puppeteerExport = require('./lib/cjs/puppeteer/node-puppeteer-core'); module.exports = puppeteerExport.default; diff --git a/cjs-entry.js b/cjs-entry.js index 1bcec7d85af..d1840a9bea1 100644 --- a/cjs-entry.js +++ b/cjs-entry.js @@ -25,5 +25,5 @@ * This means that we can publish to CJS and ESM whilst maintaining the expected * import behaviour for CJS and ESM users. */ -const puppeteerExport = require('./lib/cjs/puppeteer/index'); +const puppeteerExport = require('./lib/cjs/puppeteer/node'); module.exports = puppeteerExport.default; diff --git a/new-docs/puppeteer.browser.md b/new-docs/puppeteer.browser.md index 7e93c935d10..5b590876f87 100644 --- a/new-docs/puppeteer.browser.md +++ b/new-docs/puppeteer.browser.md @@ -4,7 +4,7 @@ ## Browser class -A Browser is created when Puppeteer connects to a Chromium instance, either through [Puppeteer.launch()](./puppeteer.puppeteer.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). +A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). Signature: diff --git a/new-docs/puppeteer.connectoptions.browserurl.md b/new-docs/puppeteer.connectoptions.browserurl.md new file mode 100644 index 00000000000..968317d64e7 --- /dev/null +++ b/new-docs/puppeteer.connectoptions.browserurl.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [ConnectOptions](./puppeteer.connectoptions.md) > [browserURL](./puppeteer.connectoptions.browserurl.md) + +## ConnectOptions.browserURL property + +Signature: + +```typescript +browserURL?: string; +``` diff --git a/new-docs/puppeteer.connectoptions.browserwsendpoint.md b/new-docs/puppeteer.connectoptions.browserwsendpoint.md new file mode 100644 index 00000000000..72abbfb1929 --- /dev/null +++ b/new-docs/puppeteer.connectoptions.browserwsendpoint.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [ConnectOptions](./puppeteer.connectoptions.md) > [browserWSEndpoint](./puppeteer.connectoptions.browserwsendpoint.md) + +## ConnectOptions.browserWSEndpoint property + +Signature: + +```typescript +browserWSEndpoint?: string; +``` diff --git a/new-docs/puppeteer.connectoptions.md b/new-docs/puppeteer.connectoptions.md new file mode 100644 index 00000000000..9377a965a88 --- /dev/null +++ b/new-docs/puppeteer.connectoptions.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [ConnectOptions](./puppeteer.connectoptions.md) + +## ConnectOptions interface + +Signature: + +```typescript +export interface ConnectOptions extends BrowserOptions +``` +Extends: [BrowserOptions](./puppeteer.browseroptions.md) + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [browserURL](./puppeteer.connectoptions.browserurl.md) | string | | +| [browserWSEndpoint](./puppeteer.connectoptions.browserwsendpoint.md) | string | | +| [product](./puppeteer.connectoptions.product.md) | [Product](./puppeteer.product.md) | | +| [transport](./puppeteer.connectoptions.transport.md) | ConnectionTransport | | + diff --git a/new-docs/puppeteer.connectoptions.product.md b/new-docs/puppeteer.connectoptions.product.md new file mode 100644 index 00000000000..50b7d20fef2 --- /dev/null +++ b/new-docs/puppeteer.connectoptions.product.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [ConnectOptions](./puppeteer.connectoptions.md) > [product](./puppeteer.connectoptions.product.md) + +## ConnectOptions.product property + +Signature: + +```typescript +product?: Product; +``` diff --git a/new-docs/puppeteer.connectoptions.transport.md b/new-docs/puppeteer.connectoptions.transport.md new file mode 100644 index 00000000000..3481976928e --- /dev/null +++ b/new-docs/puppeteer.connectoptions.transport.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [ConnectOptions](./puppeteer.connectoptions.md) > [transport](./puppeteer.connectoptions.transport.md) + +## ConnectOptions.transport property + +Signature: + +```typescript +transport?: ConnectionTransport; +``` diff --git a/new-docs/puppeteer.md b/new-docs/puppeteer.md index 114f66a0816..00d6f10e2dd 100644 --- a/new-docs/puppeteer.md +++ b/new-docs/puppeteer.md @@ -9,7 +9,7 @@ | Class | Description | | --- | --- | | [Accessibility](./puppeteer.accessibility.md) | The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or [switches](https://en.wikipedia.org/wiki/Switch_access). | -| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [Puppeteer.launch()](./puppeteer.puppeteer.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). | +| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). | | [BrowserContext](./puppeteer.browsercontext.md) | BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has a single BrowserContext used by default. The method [Browser.newPage](./puppeteer.browser.newpage.md) creates a page in the default browser context. | | [BrowserFetcher](./puppeteer.browserfetcher.md) | BrowserFetcher can download and manage different versions of Chromium and Firefox. | | [CDPSession](./puppeteer.cdpsession.md) | The CDPSession instances are used to talk raw Chrome Devtools Protocol. | @@ -27,7 +27,8 @@ | [Keyboard](./puppeteer.keyboard.md) | Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.type()](./puppeteer.keyboard.type.md), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page. | | [Mouse](./puppeteer.mouse.md) | The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. | | [Page](./puppeteer.page.md) | Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. | -| [Puppeteer](./puppeteer.puppeteer.md) | The main Puppeteer class. Provides the [launch](./puppeteer.puppeteer.launch.md) method to launch a browser.When you require or import the Puppeteer npm package you get back an instance of this class. | +| [Puppeteer](./puppeteer.puppeteer.md) | The main Puppeteer class.IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require puppeteer. That class extends Puppeteer, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md). | +| [PuppeteerNode](./puppeteer.puppeteernode.md) | Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.If you're using Puppeteer in a Node environment, this is the class you'll get when you run require('puppeteer') (or the equivalent ES import). | | [SecurityDetails](./puppeteer.securitydetails.md) | The SecurityDetails class represents the security details of a response that was received over a secure connection. | | [Target](./puppeteer.target.md) | | | [TimeoutError](./puppeteer.timeouterror.md) | TimeoutError is emitted whenever certain operations are terminated due to timeout. | @@ -54,6 +55,7 @@ | [BrowserOptions](./puppeteer.browseroptions.md) | Generic browser options that can be passed when launching any browser. | | [ChromeArgOptions](./puppeteer.chromeargoptions.md) | Launcher options that only apply to Chrome. | | [ClickOptions](./puppeteer.clickoptions.md) | | +| [ConnectOptions](./puppeteer.connectoptions.md) | | | [ConsoleMessageLocation](./puppeteer.consolemessagelocation.md) | | | [ContinueRequestOverrides](./puppeteer.continuerequestoverrides.md) | | | [CoverageEntry](./puppeteer.coverageentry.md) | The CoverageEntry class represents one entry of the coverage report. | diff --git a/new-docs/puppeteer.puppeteer._changedproduct.md b/new-docs/puppeteer.puppeteer._changedproduct.md new file mode 100644 index 00000000000..6649c662465 --- /dev/null +++ b/new-docs/puppeteer.puppeteer._changedproduct.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [\_changedProduct](./puppeteer.puppeteer._changedproduct.md) + +## Puppeteer.\_changedProduct property + +Signature: + +```typescript +protected _changedProduct: boolean; +``` diff --git a/new-docs/puppeteer.puppeteer._ispuppeteercore.md b/new-docs/puppeteer.puppeteer._ispuppeteercore.md new file mode 100644 index 00000000000..ad294d17959 --- /dev/null +++ b/new-docs/puppeteer.puppeteer._ispuppeteercore.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [\_isPuppeteerCore](./puppeteer.puppeteer._ispuppeteercore.md) + +## Puppeteer.\_isPuppeteerCore property + +Signature: + +```typescript +protected _isPuppeteerCore: boolean; +``` diff --git a/new-docs/puppeteer.puppeteer.connect.md b/new-docs/puppeteer.puppeteer.connect.md index 26512d0d305..788e746ebea 100644 --- a/new-docs/puppeteer.puppeteer.connect.md +++ b/new-docs/puppeteer.puppeteer.connect.md @@ -9,19 +9,14 @@ This method attaches Puppeteer to an existing browser instance. Signature: ```typescript -connect(options: BrowserOptions & { - browserWSEndpoint?: string; - browserURL?: string; - transport?: ConnectionTransport; - product?: Product; - }): Promise; +connect(options: ConnectOptions): Promise; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| 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. | +| options | [ConnectOptions](./puppeteer.connectoptions.md) | Set of configurable options to set on the browser. | Returns: diff --git a/new-docs/puppeteer.puppeteer.md b/new-docs/puppeteer.puppeteer.md index 41259a6d9e3..33d7ee21f88 100644 --- a/new-docs/puppeteer.puppeteer.md +++ b/new-docs/puppeteer.puppeteer.md @@ -4,9 +4,9 @@ ## Puppeteer class -The main Puppeteer class. Provides the [launch](./puppeteer.puppeteer.launch.md) method to launch a browser. +The main Puppeteer class. -When you `require` or `import` the Puppeteer npm package you get back an instance of this class. +IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require `puppeteer`. That class extends `Puppeteer`, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md). Signature: @@ -18,31 +18,14 @@ export declare class Puppeteer The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `Puppeteer` class. -## Example - -The following is a typical example of using Puppeteer to drive automation: - -```js -const puppeteer = require('puppeteer'); - -(async () => { - const browser = await puppeteer.launch(); - const page = await browser.newPage(); - await page.goto('https://www.google.com'); - // other actions... - await browser.close(); -})(); - -``` -Once you have created a `page` you have access to a large API to interact with the page, navigate, or find certain elements in that page. The [\`page\` documentation](./puppeteer.page.md) lists all the available methods. - ## Properties | Property | Modifiers | Type | Description | | --- | --- | --- | --- | +| [\_changedProduct](./puppeteer.puppeteer._changedproduct.md) | | boolean | | +| [\_isPuppeteerCore](./puppeteer.puppeteer._ispuppeteercore.md) | | boolean | | | [devices](./puppeteer.puppeteer.devices.md) | | [DevicesMap](./puppeteer.devicesmap.md) | | | [errors](./puppeteer.puppeteer.errors.md) | | [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | -| [product](./puppeteer.puppeteer.product.md) | | string | The name of the browser that is under automation ("chrome" or "firefox") | ## Methods @@ -53,8 +36,4 @@ Once you have created a `page` you have access to a large API to interact with t | [\_\_experimental\_registerCustomQueryHandler(name, queryHandler)](./puppeteer.puppeteer.__experimental_registercustomqueryhandler.md) | | Registers a [custom query handler](./puppeteer.customqueryhandler.md). After registration, the handler can be used everywhere where a selector is expected by prepending the selection string with <name>/. The name is only allowed to consist of lower- and upper case latin letters. | | [\_\_experimental\_unregisterCustomQueryHandler(name)](./puppeteer.puppeteer.__experimental_unregistercustomqueryhandler.md) | | | | [connect(options)](./puppeteer.puppeteer.connect.md) | | This method attaches Puppeteer to an existing browser instance. | -| [createBrowserFetcher(options)](./puppeteer.puppeteer.createbrowserfetcher.md) | | | -| [defaultArgs(options)](./puppeteer.puppeteer.defaultargs.md) | | | -| [executablePath()](./puppeteer.puppeteer.executablepath.md) | | | -| [launch(options)](./puppeteer.puppeteer.launch.md) | | Launches puppeteer and launches a browser instance with given arguments and options when specified. | diff --git a/new-docs/puppeteer.puppeteernode.connect.md b/new-docs/puppeteer.puppeteernode.connect.md new file mode 100644 index 00000000000..c7a89901ebb --- /dev/null +++ b/new-docs/puppeteer.puppeteernode.connect.md @@ -0,0 +1,29 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [connect](./puppeteer.puppeteernode.connect.md) + +## PuppeteerNode.connect() method + +This method attaches Puppeteer to an existing browser instance. + +Signature: + +```typescript +connect(options: ConnectOptions): Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| options | [ConnectOptions](./puppeteer.connectoptions.md) | Set of configurable options to set on the browser. | + +Returns: + +Promise<[Browser](./puppeteer.browser.md)> + +Promise which resolves to browser instance. + +## Remarks + + diff --git a/new-docs/puppeteer.puppeteer.createbrowserfetcher.md b/new-docs/puppeteer.puppeteernode.createbrowserfetcher.md similarity index 75% rename from new-docs/puppeteer.puppeteer.createbrowserfetcher.md rename to new-docs/puppeteer.puppeteernode.createbrowserfetcher.md index 0aecc97bec7..778cd0140fa 100644 --- a/new-docs/puppeteer.puppeteer.createbrowserfetcher.md +++ b/new-docs/puppeteer.puppeteernode.createbrowserfetcher.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [createBrowserFetcher](./puppeteer.puppeteer.createbrowserfetcher.md) +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [createBrowserFetcher](./puppeteer.puppeteernode.createbrowserfetcher.md) -## Puppeteer.createBrowserFetcher() method +## PuppeteerNode.createBrowserFetcher() method Signature: diff --git a/new-docs/puppeteer.puppeteer.defaultargs.md b/new-docs/puppeteer.puppeteernode.defaultargs.md similarity index 76% rename from new-docs/puppeteer.puppeteer.defaultargs.md rename to new-docs/puppeteer.puppeteernode.defaultargs.md index 007d602a25c..8164d215ca8 100644 --- a/new-docs/puppeteer.puppeteer.defaultargs.md +++ b/new-docs/puppeteer.puppeteernode.defaultargs.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [defaultArgs](./puppeteer.puppeteer.defaultargs.md) +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [defaultArgs](./puppeteer.puppeteernode.defaultargs.md) -## Puppeteer.defaultArgs() method +## PuppeteerNode.defaultArgs() method Signature: diff --git a/new-docs/puppeteer.puppeteer.executablepath.md b/new-docs/puppeteer.puppeteernode.executablepath.md similarity index 77% rename from new-docs/puppeteer.puppeteer.executablepath.md rename to new-docs/puppeteer.puppeteernode.executablepath.md index 970f70a81d0..ebe62405bd6 100644 --- a/new-docs/puppeteer.puppeteer.executablepath.md +++ b/new-docs/puppeteer.puppeteernode.executablepath.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [executablePath](./puppeteer.puppeteer.executablepath.md) +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [executablePath](./puppeteer.puppeteernode.executablepath.md) -## Puppeteer.executablePath() method +## PuppeteerNode.executablePath() method Signature: diff --git a/new-docs/puppeteer.puppeteer.launch.md b/new-docs/puppeteer.puppeteernode.launch.md similarity index 82% rename from new-docs/puppeteer.puppeteer.launch.md rename to new-docs/puppeteer.puppeteernode.launch.md index a1cd153537a..3250b78cfa2 100644 --- a/new-docs/puppeteer.puppeteer.launch.md +++ b/new-docs/puppeteer.puppeteernode.launch.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [launch](./puppeteer.puppeteer.launch.md) +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [launch](./puppeteer.puppeteernode.launch.md) -## Puppeteer.launch() method +## PuppeteerNode.launch() method Launches puppeteer and launches a browser instance with given arguments and options when specified. @@ -10,7 +10,7 @@ Launches puppeteer and launches a browser instance with given arguments and opti ```typescript launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & { - product?: string; + product?: Product; extraPrefsFirefox?: Record; }): Promise; ``` @@ -19,7 +19,7 @@ launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & { | Parameter | Type | Description | | --- | --- | --- | -| options | [LaunchOptions](./puppeteer.launchoptions.md) & [ChromeArgOptions](./puppeteer.chromeargoptions.md) & [BrowserOptions](./puppeteer.browseroptions.md) & { product?: string; extraPrefsFirefox?: Record<string, unknown>; } | Set of configurable options to set on the browser. | +| options | [LaunchOptions](./puppeteer.launchoptions.md) & [ChromeArgOptions](./puppeteer.chromeargoptions.md) & [BrowserOptions](./puppeteer.browseroptions.md) & { product?: [Product](./puppeteer.product.md); extraPrefsFirefox?: Record<string, unknown>; } | Set of configurable options to set on the browser. | Returns: diff --git a/new-docs/puppeteer.puppeteernode.md b/new-docs/puppeteer.puppeteernode.md new file mode 100644 index 00000000000..99124faabf6 --- /dev/null +++ b/new-docs/puppeteer.puppeteernode.md @@ -0,0 +1,59 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) + +## PuppeteerNode class + +Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers. + +If you're using Puppeteer in a Node environment, this is the class you'll get when you run `require('puppeteer')` (or the equivalent ES `import`). + +Signature: + +```typescript +export declare class PuppeteerNode extends Puppeteer +``` +Extends: [Puppeteer](./puppeteer.puppeteer.md) + +## Remarks + +The most common method to use is [launch](./puppeteer.puppeteernode.launch.md), which is used to launch and connect to a new browser instance. + +See [the main Puppeteer class](./puppeteer.puppeteer.md) for methods common to all environments, such as [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). + +The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `PuppeteerNode` class. + +## Example + +The following is a typical example of using Puppeteer to drive automation: + +```js +const puppeteer = require('puppeteer'); + +(async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto('https://www.google.com'); + // other actions... + await browser.close(); +})(); + +``` +Once you have created a `page` you have access to a large API to interact with the page, navigate, or find certain elements in that page. The [\`page\` documentation](./puppeteer.page.md) lists all the available methods. + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [product](./puppeteer.puppeteernode.product.md) | | string | The name of the browser that is under automation ("chrome" or "firefox") | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [connect(options)](./puppeteer.puppeteernode.connect.md) | | This method attaches Puppeteer to an existing browser instance. | +| [createBrowserFetcher(options)](./puppeteer.puppeteernode.createbrowserfetcher.md) | | | +| [defaultArgs(options)](./puppeteer.puppeteernode.defaultargs.md) | | | +| [executablePath()](./puppeteer.puppeteernode.executablepath.md) | | | +| [launch(options)](./puppeteer.puppeteernode.launch.md) | | Launches puppeteer and launches a browser instance with given arguments and options when specified. | + diff --git a/new-docs/puppeteer.puppeteer.product.md b/new-docs/puppeteer.puppeteernode.product.md similarity index 77% rename from new-docs/puppeteer.puppeteer.product.md rename to new-docs/puppeteer.puppeteernode.product.md index e65098896c0..d324c85e955 100644 --- a/new-docs/puppeteer.puppeteer.product.md +++ b/new-docs/puppeteer.puppeteernode.product.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [puppeteer](./puppeteer.md) > [Puppeteer](./puppeteer.puppeteer.md) > [product](./puppeteer.puppeteer.product.md) +[Home](./index.md) > [puppeteer](./puppeteer.md) > [PuppeteerNode](./puppeteer.puppeteernode.md) > [product](./puppeteer.puppeteernode.product.md) -## Puppeteer.product property +## PuppeteerNode.product property The name of the browser that is under automation (`"chrome"` or `"firefox"`) diff --git a/new-docs/puppeteer.timeouterror.md b/new-docs/puppeteer.timeouterror.md index 10ceabbef54..40c751677f8 100644 --- a/new-docs/puppeteer.timeouterror.md +++ b/new-docs/puppeteer.timeouterror.md @@ -15,5 +15,5 @@ export declare class TimeoutError extends CustomError ## Remarks -Example operations are [page.waitForSelector](./puppeteer.page.waitforselector.md) or [puppeteer.launch](./puppeteer.puppeteer.launch.md). +Example operations are [page.waitForSelector](./puppeteer.page.waitforselector.md) or [puppeteer.launch](./puppeteer.puppeteernode.launch.md). diff --git a/src/api-docs-entry.ts b/src/api-docs-entry.ts index c56819b2798..d033a3ed7c3 100644 --- a/src/api-docs-entry.ts +++ b/src/api-docs-entry.ts @@ -19,8 +19,9 @@ * for. It is used by API Extractor to determine what parts of the system to * document. * - * We also have src/api.ts. This is used in `index.js` and by the legacy DocLint - * system. src/api-docs-entry.ts is ONLY used by API Extractor. + * The legacy DocLint system and the unit test coverage system use the list of + * modules defined in coverage-utils.js. src/api-docs-entry.ts is ONLY used by + * API Extractor. * * Once we have migrated to API Extractor and removed DocLint we can remove the * duplication and use this file. @@ -28,6 +29,7 @@ export * from './common/Accessibility.js'; export * from './common/Browser.js'; export * from './node/BrowserFetcher.js'; +export * from './node/Puppeteer.js'; export * from './common/Connection.js'; export * from './common/ConsoleMessage.js'; export * from './common/Coverage.js'; diff --git a/src/common/Browser.ts b/src/common/Browser.ts index 28852369c3d..e3b6a241194 100644 --- a/src/common/Browser.ts +++ b/src/common/Browser.ts @@ -87,7 +87,7 @@ export const enum BrowserEmittedEvents { /** * A Browser is created when Puppeteer connects to a Chromium instance, either through - * {@link Puppeteer.launch} or {@link Puppeteer.connect}. + * {@link PuppeteerNode.launch} or {@link Puppeteer.connect}. * * @remarks * diff --git a/src/common/Errors.ts b/src/common/Errors.ts index 6b0bb79c7b8..2ba151495d5 100644 --- a/src/common/Errors.ts +++ b/src/common/Errors.ts @@ -28,7 +28,7 @@ class CustomError extends Error { * @remarks * * Example operations are {@link Page.waitForSelector | page.waitForSelector} - * or {@link Puppeteer.launch | puppeteer.launch}. + * or {@link PuppeteerNode.launch | puppeteer.launch}. * * @public */ diff --git a/src/common/Puppeteer.ts b/src/common/Puppeteer.ts index 5ab356ed3a3..87cb272e0ba 100644 --- a/src/common/Puppeteer.ts +++ b/src/common/Puppeteer.ts @@ -13,13 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import Launcher from '../node/Launcher.js'; -import { LaunchOptions, ChromeArgOptions } from '../node/LaunchOptions.js'; -import { ProductLauncher } from '../node/Launcher.js'; -import { - BrowserFetcher, - BrowserFetcherOptions, -} from '../node/BrowserFetcher.js'; import { puppeteerErrors, PuppeteerErrors } from './Errors.js'; import { ConnectionTransport } from './ConnectionTransport.js'; import { devicesMap, DevicesMap } from './DeviceDescriptors.js'; @@ -31,102 +24,42 @@ import { clearCustomQueryHandlers, 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} - * method to launch a browser. - * - * When you `require` or `import` the Puppeteer npm package you get back an - * instance of this class. - * - * @remarks - * - * @example - * The following is a typical example of using Puppeteer to drive automation: - * ```js - * const puppeteer = require('puppeteer'); - * - * (async () => { - * const browser = await puppeteer.launch(); - * const page = await browser.newPage(); - * await page.goto('https://www.google.com'); - * // other actions... - * await browser.close(); - * })(); - * ``` - * - * Once you have created a `page` you have access to a large API to interact - * with the page, navigate, or find certain elements in that page. - * The {@link Page | `page` documentation} lists all the available methods. + * Settings that are common to the Puppeteer class, regardless of enviroment. + * @internal + */ +export interface CommonPuppeteerSettings { + isPuppeteerCore: boolean; +} + +export interface ConnectOptions extends BrowserOptions { + browserWSEndpoint?: string; + browserURL?: string; + transport?: ConnectionTransport; + product?: Product; +} + +/** + * The main Puppeteer class. * + * IMPORTANT: if you are using Puppeteer in a Node environment, you will get an + * instance of {@link PuppeteerNode} when you import or require `puppeteer`. + * That class extends `Puppeteer`, so has all the methods documented below as + * well as all that are defined on {@link PuppeteerNode}. * @public */ export class Puppeteer { - // Will be undefined in a browser environment - private _projectRoot?: string; - private _isPuppeteerCore: boolean; - private _changedProduct = false; - private __productName: string; - private _lazyLauncher: ProductLauncher; - /** - * @internal - */ - _preferredRevision: string; + protected _isPuppeteerCore: boolean; + protected _changedProduct = false; /** * @internal */ - constructor( - projectRoot: string, - preferredRevision: string, - isPuppeteerCore: boolean, - productName: string - ) { - this._projectRoot = projectRoot; - this._preferredRevision = preferredRevision; - this._isPuppeteerCore = isPuppeteerCore; - // track changes to Launcher configuration via options or environment variables - this.__productName = productName; - } - - /** - * Launches puppeteer and launches a browser instance with given arguments - * and options when specified. - * - * @remarks - * - * @example - * You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments: - * ```js - * const browser = await puppeteer.launch({ - * ignoreDefaultArgs: ['--mute-audio'] - * }); - * ``` - * - * **NOTE** Puppeteer can also be used to control the Chrome browser, - * but it works best with the version of Chromium it is bundled with. - * There is no guarantee it will work with any other version. - * Use `executablePath` option with extreme caution. - * If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested. - * In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome. - * See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users. - * - * @param options - Set of configurable options to set on the browser. - * @returns Promise which resolves to browser instance. - */ - launch( - options: LaunchOptions & - ChromeArgOptions & - BrowserOptions & { - product?: string; - extraPrefsFirefox?: Record; - } = {} - ): Promise { - if (options.product) this._productName = options.product; - return this._launcher.launch(options); + constructor(settings: CommonPuppeteerSettings) { + this._isPuppeteerCore = settings.isPuppeteerCore; } /** @@ -137,85 +70,10 @@ export class Puppeteer { * @param options - Set of configurable options to set on the browser. * @returns Promise which resolves to browser instance. */ - connect( - options: BrowserOptions & { - browserWSEndpoint?: string; - browserURL?: string; - transport?: ConnectionTransport; - product?: Product; - } - ): Promise { - if (options.product) this._productName = options.product; + connect(options: ConnectOptions): Promise { return connectToBrowser(options); } - /** - * @internal - */ - get _productName(): string { - return this.__productName; - } - - // don't need any TSDoc here - because the getter is internal the setter is too. - set _productName(name: string) { - if (this.__productName !== name) this._changedProduct = true; - this.__productName = name; - } - - /** - * @remarks - * - * **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH` - * and `PUPPETEER_CHROMIUM_REVISION` environment variables. - * - * @returns A path where Puppeteer expects to find the bundled browser. - * The browser binary might not be there if the download was skipped with - * the `PUPPETEER_SKIP_DOWNLOAD` environment variable. - */ - executablePath(): string { - return this._launcher.executablePath(); - } - - /** - * @internal - */ - get _launcher(): ProductLauncher { - if ( - !this._lazyLauncher || - this._lazyLauncher.product !== this._productName || - this._changedProduct - ) { - switch (this._productName) { - case 'firefox': - this._preferredRevision = PUPPETEER_REVISIONS.firefox; - break; - case 'chrome': - default: - this._preferredRevision = PUPPETEER_REVISIONS.chromium; - } - this._changedProduct = false; - this._lazyLauncher = Launcher( - this._projectRoot, - this._preferredRevision, - this._isPuppeteerCore, - this._productName - ); - } - return this._lazyLauncher; - } - - /** - * The name of the browser that is under automation (`"chrome"` or `"firefox"`) - * - * @remarks - * The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product` - * option in `puppeteer.launch([options])` and defaults to `chrome`. - * Firefox support is experimental. - */ - get product(): string { - return this._launcher.product; - } - /** * @remarks * A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}. @@ -267,24 +125,6 @@ export class Puppeteer { return puppeteerErrors; } - /** - * - * @param options - Set of configurable options to set on the browser. - * @returns The default flags that Chromium will be launched with. - */ - defaultArgs(options: ChromeArgOptions = {}): string[] { - return this._launcher.defaultArgs(options); - } - - /** - * @param options - Set of configurable options to specify the settings - * of the BrowserFetcher. - * @returns A new BrowserFetcher instance. - */ - createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher { - return new BrowserFetcher(this._projectRoot, options); - } - /** * Registers a {@link CustomQueryHandler | custom query handler}. After * registration, the handler can be used everywhere where a selector is diff --git a/src/initialize-node.ts b/src/initialize-node.ts index 0ef0094f531..e5336654034 100644 --- a/src/initialize-node.ts +++ b/src/initialize-node.ts @@ -14,28 +14,30 @@ * limitations under the License. */ -import { Puppeteer } from './common/Puppeteer.js'; +import { PuppeteerNode } from './node/Puppeteer.js'; import { PUPPETEER_REVISIONS } from './revisions.js'; import pkgDir from 'pkg-dir'; +import { Product } from './common/Product.js'; -export const initializePuppeteerNode = (packageName: string): Puppeteer => { +export const initializePuppeteerNode = (packageName: string): PuppeteerNode => { const puppeteerRootDirectory = pkgDir.sync(__dirname); let preferredRevision = PUPPETEER_REVISIONS.chromium; const isPuppeteerCore = packageName === 'puppeteer-core'; // puppeteer-core ignores environment variables - const product = isPuppeteerCore + const productName = isPuppeteerCore ? undefined : process.env.PUPPETEER_PRODUCT || process.env.npm_config_puppeteer_product || process.env.npm_package_config_puppeteer_product; - if (!isPuppeteerCore && product === 'firefox') + + if (!isPuppeteerCore && productName === 'firefox') preferredRevision = PUPPETEER_REVISIONS.firefox; - return new Puppeteer( - puppeteerRootDirectory, + return new PuppeteerNode({ + projectRoot: puppeteerRootDirectory, preferredRevision, isPuppeteerCore, - product - ); + productName: productName as Product, + }); }; diff --git a/src/initialize-web.ts b/src/initialize-web.ts index 342f899698f..4ec42ce3fec 100644 --- a/src/initialize-web.ts +++ b/src/initialize-web.ts @@ -18,17 +18,7 @@ import { Puppeteer } from './common/Puppeteer.js'; export const initializePuppeteerWeb = (packageName: string): Puppeteer => { const isPuppeteerCore = packageName === 'puppeteer-core'; - - // puppeteer-core ignores environment variables - return new Puppeteer( - // Product root directory is undefined as we're not concerned about - // downloading and installing browsers in the web environment. - undefined, - // Preferred revision is undefined as we use the browser we are running in. - undefined, + return new Puppeteer({ isPuppeteerCore, - // Preferred product is undefined as we use the browser we are - // running in. - undefined - ); + }); }; diff --git a/src/index.ts b/src/node-puppeteer-core.ts similarity index 79% rename from src/index.ts rename to src/node-puppeteer-core.ts index 8857d0bae97..976dfd5715c 100644 --- a/src/index.ts +++ b/src/node-puppeteer-core.ts @@ -16,10 +16,10 @@ import { initializePuppeteerNode } from './initialize-node.js'; import { isNode } from './environment.js'; -import { initializePuppeteerWeb } from './initialize-web.js'; -const initializeFunc = isNode - ? initializePuppeteerNode - : initializePuppeteerWeb; -const puppeteer = initializeFunc('puppeteer'); +if (!isNode) { + throw new Error('Cannot run puppeteer-core outside of Node.js'); +} + +const puppeteer = initializePuppeteerNode('puppeteer-core'); export default puppeteer; diff --git a/src/index-core.ts b/src/node.ts similarity index 76% rename from src/index-core.ts rename to src/node.ts index 2bd07b930b9..714f8c2b948 100644 --- a/src/index-core.ts +++ b/src/node.ts @@ -16,10 +16,8 @@ import { initializePuppeteerNode } from './initialize-node.js'; import { isNode } from './environment.js'; -import { initializePuppeteerWeb } from './initialize-web.js'; -const initializeFunc = isNode - ? initializePuppeteerNode - : initializePuppeteerWeb; -const puppeteer = initializeFunc('puppeteer-core'); -export default puppeteer; +if (!isNode) { + throw new Error('Trying to run Puppeteer-Node in a web environment.'); +} +export default initializePuppeteerNode('puppeteer'); diff --git a/src/node/Puppeteer.ts b/src/node/Puppeteer.ts new file mode 100644 index 00000000000..924d2fa96e9 --- /dev/null +++ b/src/node/Puppeteer.ts @@ -0,0 +1,230 @@ +/** + * 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 { + Puppeteer, + CommonPuppeteerSettings, + ConnectOptions, +} from '../common/Puppeteer.js'; +import { BrowserFetcher, BrowserFetcherOptions } from './BrowserFetcher.js'; +import { LaunchOptions, ChromeArgOptions } from './LaunchOptions.js'; +import { BrowserOptions } from '../common/BrowserConnector.js'; +import { Browser } from '../common/Browser.js'; +import Launcher, { ProductLauncher } from './Launcher.js'; +import { PUPPETEER_REVISIONS } from '../revisions.js'; +import { Product } from '../common/Product.js'; + +/** + * Extends the main {@link Puppeteer} class with Node specific behaviour for fetching and + * downloading browsers. + * + * If you're using Puppeteer in a Node environment, this is the class you'll get + * when you run `require('puppeteer')` (or the equivalent ES `import`). + * + * @remarks + * + * The most common method to use is {@link PuppeteerNode.launch | launch}, which + * is used to launch and connect to a new browser instance. + * + * See {@link Puppeteer | the main Puppeteer class} for methods common to all + * environments, such as {@link Puppeteer.connect}. + * + * @example + * The following is a typical example of using Puppeteer to drive automation: + * ```js + * const puppeteer = require('puppeteer'); + * + * (async () => { + * const browser = await puppeteer.launch(); + * const page = await browser.newPage(); + * await page.goto('https://www.google.com'); + * // other actions... + * await browser.close(); + * })(); + * ``` + * + * Once you have created a `page` you have access to a large API to interact + * with the page, navigate, or find certain elements in that page. + * The {@link Page | `page` documentation} lists all the available methods. + * + * @public + */ +export class PuppeteerNode extends Puppeteer { + private _lazyLauncher: ProductLauncher; + private _projectRoot: string; + private __productName?: Product; + /** + * @internal + */ + _preferredRevision: string; + + /** + * @internal + */ + constructor( + settings: { + projectRoot: string; + preferredRevision: string; + productName?: Product; + } & CommonPuppeteerSettings + ) { + const { + projectRoot, + preferredRevision, + productName, + ...commonSettings + } = settings; + super(commonSettings); + this._projectRoot = projectRoot; + this.__productName = productName; + this._preferredRevision = preferredRevision; + } + + /** + * This method attaches Puppeteer to an existing browser instance. + * + * @remarks + * + * @param options - Set of configurable options to set on the browser. + * @returns Promise which resolves to browser instance. + */ + connect(options: ConnectOptions): Promise { + if (options.product) this._productName = options.product; + return super.connect(options); + } + + /** + * @internal + */ + get _productName(): Product { + return this.__productName; + } + + // don't need any TSDoc here - because the getter is internal the setter is too. + set _productName(name: Product) { + if (this.__productName !== name) this._changedProduct = true; + this.__productName = name; + } + + /** + * Launches puppeteer and launches a browser instance with given arguments + * and options when specified. + * + * @remarks + * + * @example + * You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments: + * ```js + * const browser = await puppeteer.launch({ + * ignoreDefaultArgs: ['--mute-audio'] + * }); + * ``` + * + * **NOTE** Puppeteer can also be used to control the Chrome browser, + * but it works best with the version of Chromium it is bundled with. + * There is no guarantee it will work with any other version. + * Use `executablePath` option with extreme caution. + * If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested. + * In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome. + * See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users. + * + * @param options - Set of configurable options to set on the browser. + * @returns Promise which resolves to browser instance. + */ + launch( + options: LaunchOptions & + ChromeArgOptions & + BrowserOptions & { + product?: Product; + extraPrefsFirefox?: Record; + } = {} + ): Promise { + if (options.product) this._productName = options.product; + return this._launcher.launch(options); + } + + /** + * @remarks + * + * **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH` + * and `PUPPETEER_CHROMIUM_REVISION` environment variables. + * + * @returns A path where Puppeteer expects to find the bundled browser. + * The browser binary might not be there if the download was skipped with + * the `PUPPETEER_SKIP_DOWNLOAD` environment variable. + */ + executablePath(): string { + return this._launcher.executablePath(); + } + + /** + * @internal + */ + get _launcher(): ProductLauncher { + if ( + !this._lazyLauncher || + this._lazyLauncher.product !== this._productName || + this._changedProduct + ) { + switch (this._productName) { + case 'firefox': + this._preferredRevision = PUPPETEER_REVISIONS.firefox; + break; + case 'chrome': + default: + this._preferredRevision = PUPPETEER_REVISIONS.chromium; + } + this._changedProduct = false; + this._lazyLauncher = Launcher( + this._projectRoot, + this._preferredRevision, + this._isPuppeteerCore, + this._productName + ); + } + return this._lazyLauncher; + } + + /** + * The name of the browser that is under automation (`"chrome"` or `"firefox"`) + * + * @remarks + * The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product` + * option in `puppeteer.launch([options])` and defaults to `chrome`. + * Firefox support is experimental. + */ + get product(): string { + return this._launcher.product; + } + + /** + * + * @param options - Set of configurable options to set on the browser. + * @returns The default flags that Chromium will be launched with. + */ + defaultArgs(options: ChromeArgOptions = {}): string[] { + return this._launcher.defaultArgs(options); + } + + /** + * @param options - Set of configurable options to specify the settings + * of the BrowserFetcher. + * @returns A new BrowserFetcher instance. + */ + createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher { + return new BrowserFetcher(this._projectRoot, options); + } +} diff --git a/src/node/install.ts b/src/node/install.ts index ca46f00e2e8..41f2834d80d 100644 --- a/src/node/install.ts +++ b/src/node/install.ts @@ -17,8 +17,9 @@ import os from 'os'; import https from 'https'; import ProgressBar from 'progress'; -import puppeteer from '../index.js'; +import puppeteer from '../node.js'; import { PUPPETEER_REVISIONS } from '../revisions.js'; +import { PuppeteerNode } from './Puppeteer.js'; const supportedProducts = { chrome: 'Chromium', @@ -39,7 +40,7 @@ export async function downloadBrowser() { process.env.PUPPETEER_DOWNLOAD_PATH || process.env.npm_config_puppeteer_download_path || process.env.npm_package_config_puppeteer_download_path; - const browserFetcher = puppeteer.createBrowserFetcher({ + const browserFetcher = (puppeteer as PuppeteerNode).createBrowserFetcher({ product, host: downloadHost, path: downloadPath, @@ -55,7 +56,8 @@ export async function downloadBrowser() { PUPPETEER_REVISIONS.chromium ); } else if (product === 'firefox') { - puppeteer._preferredRevision = PUPPETEER_REVISIONS.firefox; + (puppeteer as PuppeteerNode)._preferredRevision = + PUPPETEER_REVISIONS.firefox; return getFirefoxNightlyVersion().catch((error) => { console.error(error); process.exit(1); diff --git a/src/web.ts b/src/web.ts new file mode 100644 index 00000000000..a48a5cf14d6 --- /dev/null +++ b/src/web.ts @@ -0,0 +1,24 @@ +/** + * 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 { initializePuppeteerWeb } from './initialize-web.js'; +import { isNode } from './environment.js'; + +if (isNode) { + throw new Error('Trying to run Puppeteer-Web in a Node environment'); +} + +export default initializePuppeteerWeb('puppeteer'); diff --git a/test/coverage-utils.js b/test/coverage-utils.js index add0238a0e8..c23e507f9de 100644 --- a/test/coverage-utils.js +++ b/test/coverage-utils.js @@ -57,6 +57,7 @@ const MODULES_TO_CHECK_FOR_COVERAGE = { Mouse: '../lib/cjs/puppeteer/common/Input', Page: '../lib/cjs/puppeteer/common/Page', Puppeteer: '../lib/cjs/puppeteer/common/Puppeteer', + PuppeteerNode: '../lib/cjs/puppeteer/node/Puppeteer', HTTPRequest: '../lib/cjs/puppeteer/common/HTTPRequest', HTTPResponse: '../lib/cjs/puppeteer/common/HTTPResponse', SecurityDetails: '../lib/cjs/puppeteer/common/SecurityDetails', diff --git a/test/launcher.spec.ts b/test/launcher.spec.ts index cb402c7ea9b..b2254a53cf8 100644 --- a/test/launcher.spec.ts +++ b/test/launcher.spec.ts @@ -459,6 +459,7 @@ describe('Launcher specs', function () { it('falls back to launching chrome if there is an unknown product but logs a warning', async () => { const { puppeteer } = getTestState(); const consoleStub = sinon.stub(console, 'warn'); + // @ts-expect-error purposeful bad input const browser = await puppeteer.launch({ product: 'SO_NOT_A_PRODUCT' }); const userAgent = await browser.userAgent(); await browser.close(); diff --git a/test/mocha-utils.ts b/test/mocha-utils.ts index 479d7720592..d13c82701c8 100644 --- a/test/mocha-utils.ts +++ b/test/mocha-utils.ts @@ -19,13 +19,13 @@ import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; import sinon from 'sinon'; -import puppeteer from '../lib/cjs/puppeteer/index.js'; +import puppeteer from '../lib/cjs/puppeteer/node.js'; import { Browser, BrowserContext, } from '../lib/cjs/puppeteer/common/Browser.js'; import { Page } from '../lib/cjs/puppeteer/common/Page.js'; -import { Puppeteer } from '../lib/cjs/puppeteer/common/Puppeteer.js'; +import { PuppeteerNode } from '../lib/cjs/puppeteer/node/Puppeteer.js'; import utils from './utils.js'; import rimraf from 'rimraf'; @@ -126,7 +126,7 @@ interface PuppeteerTestState { browser: Browser; context: BrowserContext; page: Page; - puppeteer: Puppeteer; + puppeteer: PuppeteerNode; defaultBrowserOptions: { [x: string]: any; }; diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index d3e8fb876ba..84d5ca0f2a9 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -206,10 +206,25 @@ function compareDocumentations(actual, expected) { const expectedClasses = Array.from(expected.classes.keys()).sort(); const classesDiff = diff(actualClasses, expectedClasses); + /* These have been moved onto PuppeteerNode but we want to document them under + * Puppeteer. See https://github.com/puppeteer/puppeteer/pull/6504 for details. + */ + const expectedPuppeteerClassMissingMethods = new Set([ + 'createBrowserFetcher', + 'defaultArgs', + 'executablePath', + 'launch', + ]); + for (const className of classesDiff.extra) errors.push(`Non-existing class found: ${className}`); - for (const className of classesDiff.missing) + + for (const className of classesDiff.missing) { + if (className === 'PuppeteerNode') { + continue; + } errors.push(`Class not found: ${className}`); + } for (const className of classesDiff.equal) { const actualClass = actual.classes.get(className); @@ -219,6 +234,12 @@ function compareDocumentations(actual, expected) { const methodDiff = diff(actualMethods, expectedMethods); for (const methodName of methodDiff.extra) { + if ( + expectedPuppeteerClassMissingMethods.has(methodName) && + actualClass.name === 'Puppeteer' + ) { + continue; + } errors.push(`Non-existing method found: ${className}.${methodName}()`); } @@ -282,8 +303,12 @@ function compareDocumentations(actual, expected) { expectedClass.properties.keys() ).sort(); const propertyDiff = diff(actualProperties, expectedProperties); - for (const propertyName of propertyDiff.extra) + for (const propertyName of propertyDiff.extra) { + if (className === 'Puppeteer' && propertyName === 'product') { + continue; + } errors.push(`Non-existing property found: ${className}.${propertyName}`); + } for (const propertyName of propertyDiff.missing) errors.push(`Property not found: ${className}.${propertyName}`); @@ -804,10 +829,10 @@ function compareDocumentations(actual, expected) { }, ], [ - 'Method Puppeteer.connect() options.product', + 'Method Puppeteer.connect() options', { - actualName: 'string', - expectedName: 'Product', + actualName: 'Object', + expectedName: 'ConnectOptions', }, ], ]); @@ -854,6 +879,7 @@ function compareDocumentations(actual, expected) { const skipPropertyChecksOnMethods = new Set([ 'Method Page.deleteCookie() ...cookies', 'Method Page.setCookie() ...cookies', + 'Method Puppeteer.connect() options', ]); if (skipPropertyChecksOnMethods.has(source)) return;