feat: use configuration files (#9140)

This PR adds configurations files to `puppeteer`'s methods for
configuration. Under the hood, `puppeteer` relies on
https://www.npmjs.com/package/cosmiconfig which resolves several formats
of configuration:

- a `puppeteer` property in package.json
- a `.puppeteerrc` file in JSON or YAML format
- a `.puppeteerrc.json`, `.puppeteerrc.yaml`, `.puppeteerrc.yml`,
`.puppeteerrc.js`, or `.puppeteerrc.cjs` file
- a `puppeteer.config.js` or `puppeteer.config.cjs` CommonJS module
exporting an object

Documentation will be added later.

Fixed: #9128
This commit is contained in:
jrandolf 2022-10-21 15:09:21 +02:00 committed by GitHub
parent efcbc97c60
commit ec201744f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 925 additions and 706 deletions

View File

@ -30,6 +30,7 @@ sidebar_label: API
| [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. | | [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. | | [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) | <p>Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium.</p><p>:::note</p><p>One Browser instance might have multiple Page instances.</p><p>:::</p> | | [Page](./puppeteer.page.md) | <p>Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium.</p><p>:::note</p><p>One Browser instance might have multiple Page instances.</p><p>:::</p> |
| [ProductLauncher](./puppeteer.productlauncher.md) | Describes a launcher - a class that is able to create and launch a browser instance. |
| [ProtocolError](./puppeteer.protocolerror.md) | ProtocolError is emitted whenever there is an error from the protocol. | | [ProtocolError](./puppeteer.protocolerror.md) | ProtocolError is emitted whenever there is an error from the protocol. |
| [Puppeteer](./puppeteer.puppeteer.md) | <p>The main Puppeteer class.</p><p>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 <code>puppeteer</code>. That class extends <code>Puppeteer</code>, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md).</p> | | [Puppeteer](./puppeteer.puppeteer.md) | <p>The main Puppeteer class.</p><p>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 <code>puppeteer</code>. That class extends <code>Puppeteer</code>, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md).</p> |
| [PuppeteerNode](./puppeteer.puppeteernode.md) | <p>Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.</p><p>If you're using Puppeteer in a Node environment, this is the class you'll get when you run <code>require('puppeteer')</code> (or the equivalent ES <code>import</code>).</p> | | [PuppeteerNode](./puppeteer.puppeteernode.md) | <p>Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.</p><p>If you're using Puppeteer in a Node environment, this is the class you'll get when you run <code>require('puppeteer')</code> (or the equivalent ES <code>import</code>).</p> |
@ -72,6 +73,7 @@ sidebar_label: API
| [CDPSessionOnMessageObject](./puppeteer.cdpsessiononmessageobject.md) | | | [CDPSessionOnMessageObject](./puppeteer.cdpsessiononmessageobject.md) | |
| [ClickOptions](./puppeteer.clickoptions.md) | | | [ClickOptions](./puppeteer.clickoptions.md) | |
| [CommonEventEmitter](./puppeteer.commoneventemitter.md) | | | [CommonEventEmitter](./puppeteer.commoneventemitter.md) | |
| [Configuration](./puppeteer.configuration.md) | |
| [ConnectionCallback](./puppeteer.connectioncallback.md) | | | [ConnectionCallback](./puppeteer.connectioncallback.md) | |
| [ConnectionTransport](./puppeteer.connectiontransport.md) | | | [ConnectionTransport](./puppeteer.connectiontransport.md) | |
| [ConnectOptions](./puppeteer.connectoptions.md) | | | [ConnectOptions](./puppeteer.connectoptions.md) | |
@ -102,7 +104,6 @@ sidebar_label: API
| [PDFOptions](./puppeteer.pdfoptions.md) | Valid options to configure PDF generation via [Page.pdf()](./puppeteer.page.pdf.md). | | [PDFOptions](./puppeteer.pdfoptions.md) | Valid options to configure PDF generation via [Page.pdf()](./puppeteer.page.pdf.md). |
| [Point](./puppeteer.point.md) | | | [Point](./puppeteer.point.md) | |
| [PressOptions](./puppeteer.pressoptions.md) | | | [PressOptions](./puppeteer.pressoptions.md) | |
| [ProductLauncher](./puppeteer.productlauncher.md) | Describes a launcher - a class that is able to create and launch a browser instance. |
| [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | | [PuppeteerErrors](./puppeteer.puppeteererrors.md) | |
| [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | | | [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | |
| [RemoteAddress](./puppeteer.remoteaddress.md) | | | [RemoteAddress](./puppeteer.remoteaddress.md) | |

View File

@ -10,12 +10,12 @@ Constructs a browser fetcher for the given options.
```typescript ```typescript
class BrowserFetcher { class BrowserFetcher {
constructor(options?: BrowserFetcherOptions); constructor(options: BrowserFetcherOptions);
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------------------------------------------------------------- | ----------------- | | --------- | ------------------------------------------------------------- | ----------- |
| options | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | <i>(Optional)</i> | | options | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | |

View File

@ -8,15 +8,15 @@ sidebar_label: BrowserFetcher.localRevisions
```typescript ```typescript
class BrowserFetcher { class BrowserFetcher {
localRevisions(): Promise<string[]>; localRevisions(): string[];
} }
``` ```
**Returns:** **Returns:**
Promise&lt;string\[\]&gt; string\[\]
A promise with a list of all revision strings (for the current `product`) available locally on disk. A list of all revision strings (for the current `product`) available locally on disk.
## Remarks ## Remarks

View File

@ -21,7 +21,7 @@ BrowserFetcher is not designed to work concurrently with other instances of Brow
An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it: An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it:
```ts ```ts
const browserFetcher = new BrowserFetcher(); const browserFetcher = new BrowserFetcher({path: 'path/to/download/folder'});
const revisionInfo = await browserFetcher.download('533271'); const revisionInfo = await browserFetcher.download('533271');
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
executablePath: revisionInfo.executablePath, executablePath: revisionInfo.executablePath,

View File

@ -13,8 +13,9 @@ export interface BrowserFetcherOptions
## Properties ## Properties
| Property | Modifiers | Type | Description | | Property | Modifiers | Type | Description |
| ---------------------------------------------------------- | --------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ | | ---------------------------------------------------------------------------- | --------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> Determines the host that will be used for downloading. | | [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> Determines the host that will be used for downloading. |
| [path?](./puppeteer.browserfetcheroptions.path.md) | | string | <i>(Optional)</i> Determines the path to download browsers to. | | [path](./puppeteer.browserfetcheroptions.path.md) | | string | Determines the path to download browsers to. |
| [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> Determines which platform the browser will be suited for. | | [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> Determines which platform the browser will be suited for. |
| [product?](./puppeteer.browserfetcheroptions.product.md) | | 'chrome' \| 'firefox' | <i>(Optional)</i> Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for. | | [product?](./puppeteer.browserfetcheroptions.product.md) | | 'chrome' \| 'firefox' | <i>(Optional)</i> Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for. |
| [useMacOSARMBinary?](./puppeteer.browserfetcheroptions.usemacosarmbinary.md) | | boolean | <i>(Optional)</i> Enables the use of the Chromium binary for macOS ARM. |

View File

@ -10,6 +10,6 @@ Determines the path to download browsers to.
```typescript ```typescript
interface BrowserFetcherOptions { interface BrowserFetcherOptions {
path?: string; path: string;
} }
``` ```

View File

@ -0,0 +1,15 @@
---
sidebar_label: BrowserFetcherOptions.useMacOSARMBinary
---
# BrowserFetcherOptions.useMacOSARMBinary property
Enables the use of the Chromium binary for macOS ARM.
**Signature:**
```typescript
interface BrowserFetcherOptions {
useMacOSARMBinary?: boolean;
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.browserRevision
---
# Configuration.browserRevision property
**Signature:**
```typescript
interface Configuration {
browserRevision?: string;
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.cacheDirectory
---
# Configuration.cacheDirectory property
**Signature:**
```typescript
interface Configuration {
cacheDirectory?: string;
}
```

View File

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

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.downloadHost
---
# Configuration.downloadHost property
**Signature:**
```typescript
interface Configuration {
downloadHost?: string;
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.downloadPath
---
# Configuration.downloadPath property
**Signature:**
```typescript
interface Configuration {
downloadPath?: string;
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.executablePath
---
# Configuration.executablePath property
**Signature:**
```typescript
interface Configuration {
executablePath?: string;
}
```

View File

@ -0,0 +1,15 @@
---
sidebar_label: Configuration.experiments
---
# Configuration.experiments property
**Signature:**
```typescript
interface Configuration {
experiments?: {
macArmChromiumEnabled?: boolean;
};
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.logLevel
---
# Configuration.logLevel property
**Signature:**
```typescript
interface Configuration {
logLevel?: 'silent' | 'error' | 'warn';
}
```

View File

@ -0,0 +1,26 @@
---
sidebar_label: Configuration
---
# Configuration interface
**Signature:**
```typescript
export interface Configuration
```
## Properties
| Property | Modifiers | Type | Description |
| ---------------------------------------------------------------------- | --------- | ------------------------------------ | ----------------- |
| [browserRevision?](./puppeteer.configuration.browserrevision.md) | | string | <i>(Optional)</i> |
| [cacheDirectory?](./puppeteer.configuration.cachedirectory.md) | | string | <i>(Optional)</i> |
| [defaultProduct?](./puppeteer.configuration.defaultproduct.md) | | [Product](./puppeteer.product.md) | <i>(Optional)</i> |
| [downloadHost?](./puppeteer.configuration.downloadhost.md) | | string | <i>(Optional)</i> |
| [downloadPath?](./puppeteer.configuration.downloadpath.md) | | string | <i>(Optional)</i> |
| [executablePath?](./puppeteer.configuration.executablepath.md) | | string | <i>(Optional)</i> |
| [experiments?](./puppeteer.configuration.experiments.md) | | { macArmChromiumEnabled?: boolean; } | <i>(Optional)</i> |
| [logLevel?](./puppeteer.configuration.loglevel.md) | | 'silent' \| 'error' \| 'warn' | <i>(Optional)</i> |
| [skipDownload?](./puppeteer.configuration.skipdownload.md) | | boolean | <i>(Optional)</i> |
| [temporaryDirectory?](./puppeteer.configuration.temporarydirectory.md) | | string | <i>(Optional)</i> |

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.skipDownload
---
# Configuration.skipDownload property
**Signature:**
```typescript
interface Configuration {
skipDownload?: boolean;
}
```

View File

@ -0,0 +1,13 @@
---
sidebar_label: Configuration.temporaryDirectory
---
# Configuration.temporaryDirectory property
**Signature:**
```typescript
interface Configuration {
temporaryDirectory?: string;
}
```

View File

@ -9,5 +9,5 @@ sidebar_label: connect
```typescript ```typescript
connect: ( connect: (
options: import('puppeteer-core/internal/common/Puppeteer.js').ConnectOptions options: import('puppeteer-core/internal/common/Puppeteer.js').ConnectOptions
) => Promise<import('./types').Browser>; ) => Promise<import('./types.js').Browser>;
``` ```

View File

@ -8,6 +8,8 @@ sidebar_label: createBrowserFetcher
```typescript ```typescript
createBrowserFetcher: ( createBrowserFetcher: (
options: import('puppeteer-core/internal/node/BrowserFetcher.js').BrowserFetcherOptions options: Partial<
import('puppeteer-core/internal/node/BrowserFetcher.js').BrowserFetcherOptions
>
) => import('puppeteer-core/internal/node/BrowserFetcher.js').BrowserFetcher; ) => import('puppeteer-core/internal/node/BrowserFetcher.js').BrowserFetcher;
``` ```

View File

@ -7,5 +7,9 @@ sidebar_label: executablePath
**Signature:** **Signature:**
```typescript ```typescript
executablePath: (channel?: string | undefined) => string; executablePath: (
channel?:
| import('puppeteer-core/internal/node/LaunchOptions.js').ChromeReleaseChannel
| undefined
) => string;
``` ```

View File

@ -11,5 +11,5 @@ launch: (
options?: options?:
| import('puppeteer-core/internal/node/PuppeteerNode.js').PuppeteerLaunchOptions | import('puppeteer-core/internal/node/PuppeteerNode.js').PuppeteerLaunchOptions
| undefined | undefined
) => Promise<import('./types').Browser>; ) => Promise<import('./types.js').Browser>;
``` ```

View File

@ -7,7 +7,7 @@ sidebar_label: ProductLauncher.defaultArgs
**Signature:** **Signature:**
```typescript ```typescript
interface ProductLauncher { class ProductLauncher {
defaultArgs(object: BrowserLaunchArgumentOptions): string[]; defaultArgs(object: BrowserLaunchArgumentOptions): string[];
} }
``` ```

View File

@ -2,12 +2,22 @@
sidebar_label: ProductLauncher.executablePath sidebar_label: ProductLauncher.executablePath
--- ---
# ProductLauncher.executablePath property # ProductLauncher.executablePath() method
**Signature:** **Signature:**
```typescript ```typescript
interface ProductLauncher { class ProductLauncher {
executablePath: (path?: any) => string; executablePath(channel?: ChromeReleaseChannel): string;
} }
``` ```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------------------------------------------- | ----------------- |
| channel | [ChromeReleaseChannel](./puppeteer.chromereleasechannel.md) | <i>(Optional)</i> |
**Returns:**
string

View File

@ -7,7 +7,7 @@ sidebar_label: ProductLauncher.launch
**Signature:** **Signature:**
```typescript ```typescript
interface ProductLauncher { class ProductLauncher {
launch(object: PuppeteerNodeLaunchOptions): Promise<Browser>; launch(object: PuppeteerNodeLaunchOptions): Promise<Browser>;
} }
``` ```

View File

@ -2,26 +2,30 @@
sidebar_label: ProductLauncher sidebar_label: ProductLauncher
--- ---
# ProductLauncher interface # ProductLauncher class
Describes a launcher - a class that is able to create and launch a browser instance. Describes a launcher - a class that is able to create and launch a browser instance.
**Signature:** **Signature:**
```typescript ```typescript
export interface ProductLauncher export declare class ProductLauncher
``` ```
## Remarks
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `ProductLauncher` class.
## Properties ## Properties
| Property | Modifiers | Type | Description | | Property | Modifiers | Type | Description |
| --------------------------------------------------------------- | --------- | --------------------------------- | ----------- | | ------------------------------------------------- | --------------------- | --------------------------------- | ----------- |
| [executablePath](./puppeteer.productlauncher.executablepath.md) | | (path?: any) =&gt; string | | | [product](./puppeteer.productlauncher.product.md) | <code>readonly</code> | [Product](./puppeteer.product.md) | |
| [product](./puppeteer.productlauncher.product.md) | | [Product](./puppeteer.product.md) | |
## Methods ## Methods
| Method | Description | | Method | Modifiers | Description |
| ----------------------------------------------------------------- | ----------- | | ------------------------------------------------------------------------ | --------- | ----------- |
| [defaultArgs(object)](./puppeteer.productlauncher.defaultargs.md) | | | [defaultArgs(object)](./puppeteer.productlauncher.defaultargs.md) | | |
| [launch(object)](./puppeteer.productlauncher.launch.md) | | | [executablePath(channel)](./puppeteer.productlauncher.executablepath.md) | | |
| [launch(object)](./puppeteer.productlauncher.launch.md) | | |

View File

@ -7,7 +7,7 @@ sidebar_label: ProductLauncher.product
**Signature:** **Signature:**
```typescript ```typescript
interface ProductLauncher { class ProductLauncher {
product: Product; get product(): Product;
} }
``` ```

View File

@ -12,15 +12,15 @@ sidebar_label: PuppeteerNode.createBrowserFetcher
```typescript ```typescript
class PuppeteerNode { class PuppeteerNode {
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher; createBrowserFetcher(options: Partial<BrowserFetcherOptions>): BrowserFetcher;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------------------------------------------------------------- | -------------------------------------------------------------------------- | | --------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| options | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | Set of configurable options to specify the settings of the BrowserFetcher. | | options | Partial&lt;[BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md)&gt; | Set of configurable options to specify the settings of the BrowserFetcher. |
**Returns:** **Returns:**

View File

@ -0,0 +1,13 @@
---
sidebar_label: PuppeteerNode.defaultProduct
---
# PuppeteerNode.defaultProduct property
**Signature:**
```typescript
class PuppeteerNode {
get defaultProduct(): Product;
}
```

View File

@ -8,22 +8,18 @@ sidebar_label: PuppeteerNode.executablePath
```typescript ```typescript
class PuppeteerNode { class PuppeteerNode {
executablePath(channel?: string): string; executablePath(channel?: ChromeReleaseChannel): string;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------ | ----------------- | | --------- | ----------------------------------------------------------- | ----------------- |
| channel | string | <i>(Optional)</i> | | channel | [ChromeReleaseChannel](./puppeteer.chromereleasechannel.md) | <i>(Optional)</i> |
**Returns:** **Returns:**
string string
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. The executable path.
## Remarks
**NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH` and `PUPPETEER_CHROMIUM_REVISION` environment variables.

View File

@ -0,0 +1,13 @@
---
sidebar_label: PuppeteerNode.lastLaunchedProduct
---
# PuppeteerNode.lastLaunchedProduct property
**Signature:**
```typescript
class PuppeteerNode {
get lastLaunchedProduct(): Product;
}
```

View File

@ -4,7 +4,7 @@ sidebar_label: PuppeteerNode.launch
# PuppeteerNode.launch() method # PuppeteerNode.launch() method
Launches puppeteer and launches a browser instance with given arguments and options when specified. Launches a browser instance with given arguments and options when specified.
**Signature:** **Signature:**
@ -17,18 +17,16 @@ class PuppeteerNode {
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | --------------------------------------------------------------- | -------------------------------------------------------------------- | | --------- | --------------------------------------------------------------- | ---------------------------------------------------------- |
| options | [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | <i>(Optional)</i> Set of configurable options to set on the browser. | | options | [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | <i>(Optional)</i> Options to configure launching behavior. |
**Returns:** **Returns:**
Promise&lt;[Browser](./puppeteer.browser.md)&gt; Promise&lt;[Browser](./puppeteer.browser.md)&gt;
Promise which resolves to browser instance.
## Remarks ## Remarks
**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 [Chrome Canary](https://www.google.com/chrome/browser/canary.html) or [Dev Channel](https://www.chromium.org/getting-involved/dev-channel) build is suggested. In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome. See [this article](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [This article](https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users. 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 [Chrome Canary](https://www.google.com/chrome/browser/canary.html) or [Dev Channel](https://www.chromium.org/getting-involved/dev-channel) build is suggested. In , any mention of Chromium also applies to Chrome. See [this article](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [This article](https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
## Example ## Example

View File

@ -45,15 +45,17 @@ Once you have created a `page` you have access to a large API to interact with t
## Properties ## Properties
| Property | Modifiers | Type | Description | | Property | Modifiers | Type | Description |
| ----------------------------------------------- | --------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- | | ----------------------------------------------------------------------- | --------------------- | --------------------------------- | ----------- |
| [product](./puppeteer.puppeteernode.product.md) | <code>readonly</code> | string | The name of the browser that is under automation (<code>&quot;chrome&quot;</code> or <code>&quot;firefox&quot;</code>) | | [defaultProduct](./puppeteer.puppeteernode.defaultproduct.md) | <code>readonly</code> | [Product](./puppeteer.product.md) | |
| [lastLaunchedProduct](./puppeteer.puppeteernode.lastlaunchedproduct.md) | <code>readonly</code> | [Product](./puppeteer.product.md) | |
| [product](./puppeteer.puppeteernode.product.md) | <code>readonly</code> | string | |
## Methods ## Methods
| Method | Modifiers | Description | | Method | Modifiers | Description |
| ---------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------- | | ---------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------- |
| [connect(options)](./puppeteer.puppeteernode.connect.md) | | This method attaches Puppeteer to an existing browser instance. | | [connect(options)](./puppeteer.puppeteernode.connect.md) | | This method attaches Puppeteer to an existing browser instance. |
| [createBrowserFetcher(options)](./puppeteer.puppeteernode.createbrowserfetcher.md) | | | | [createBrowserFetcher(options)](./puppeteer.puppeteernode.createbrowserfetcher.md) | | |
| [defaultArgs(options)](./puppeteer.puppeteernode.defaultargs.md) | | | | [defaultArgs(options)](./puppeteer.puppeteernode.defaultargs.md) | | |
| [executablePath(channel)](./puppeteer.puppeteernode.executablepath.md) | | | | [executablePath(channel)](./puppeteer.puppeteernode.executablepath.md) | | |
| [launch(options)](./puppeteer.puppeteernode.launch.md) | | Launches puppeteer and launches a browser instance with given arguments and options when specified. | | [launch(options)](./puppeteer.puppeteernode.launch.md) | | Launches a browser instance with given arguments and options when specified. |

View File

@ -4,7 +4,9 @@ sidebar_label: PuppeteerNode.product
# PuppeteerNode.product property # PuppeteerNode.product property
The name of the browser that is under automation (`"chrome"` or `"firefox"`) > Warning: This API is now obsolete.
>
> Do not use as this field as it does not take into account multiple browsers of different types. Use or .
**Signature:** **Signature:**
@ -13,7 +15,3 @@ class PuppeteerNode {
get product(): string; get product(): string;
} }
``` ```
## 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.

88
package-lock.json generated
View File

@ -84,7 +84,6 @@
"version": "7.12.11", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/highlight": "^7.10.4" "@babel/highlight": "^7.10.4"
} }
@ -93,7 +92,6 @@
"version": "7.19.1", "version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -102,7 +100,6 @@
"version": "7.18.6", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0", "chalk": "^2.0.0",
@ -116,7 +113,6 @@
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": { "dependencies": {
"color-convert": "^1.9.0" "color-convert": "^1.9.0"
}, },
@ -128,7 +124,6 @@
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": { "dependencies": {
"ansi-styles": "^3.2.1", "ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
@ -142,7 +137,6 @@
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": { "dependencies": {
"color-name": "1.1.3" "color-name": "1.1.3"
} }
@ -150,14 +144,12 @@
"node_modules/@babel/highlight/node_modules/color-name": { "node_modules/@babel/highlight/node_modules/color-name": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
"dev": true
}, },
"node_modules/@babel/highlight/node_modules/escape-string-regexp": { "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
} }
@ -166,7 +158,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -175,7 +166,6 @@
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": { "dependencies": {
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
}, },
@ -1916,8 +1906,7 @@
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
"dev": true
}, },
"node_modules/@types/pixelmatch": { "node_modules/@types/pixelmatch": {
"version": "5.2.4", "version": "5.2.4",
@ -2650,7 +2639,6 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -2901,7 +2889,6 @@
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
"dev": true,
"dependencies": { "dependencies": {
"@types/parse-json": "^4.0.0", "@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
@ -3135,7 +3122,6 @@
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"dependencies": { "dependencies": {
"is-arrayish": "^0.2.1" "is-arrayish": "^0.2.1"
} }
@ -4993,7 +4979,6 @@
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
"dependencies": { "dependencies": {
"parent-module": "^1.0.0", "parent-module": "^1.0.0",
"resolve-from": "^4.0.0" "resolve-from": "^4.0.0"
@ -5009,7 +4994,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -5111,8 +5095,7 @@
"node_modules/is-arrayish": { "node_modules/is-arrayish": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
"dev": true
}, },
"node_modules/is-bigint": { "node_modules/is-bigint": {
"version": "1.0.4", "version": "1.0.4",
@ -5558,8 +5541,7 @@
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
"dev": true
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "3.13.1", "version": "3.13.1",
@ -5583,8 +5565,7 @@
"node_modules/json-parse-even-better-errors": { "node_modules/json-parse-even-better-errors": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
"dev": true
}, },
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "1.0.0", "version": "1.0.0",
@ -5684,8 +5665,7 @@
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
"dev": true
}, },
"node_modules/load-json-file": { "node_modules/load-json-file": {
"version": "4.0.0", "version": "4.0.0",
@ -6568,7 +6548,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"dependencies": { "dependencies": {
"callsites": "^3.0.0" "callsites": "^3.0.0"
}, },
@ -6580,7 +6559,6 @@
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.0.0", "@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1", "error-ex": "^1.3.1",
@ -6638,7 +6616,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -8344,7 +8321,6 @@
"version": "1.10.2", "version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
} }
@ -8492,6 +8468,7 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"cosmiconfig": "7.0.1",
"https-proxy-agent": "5.0.1", "https-proxy-agent": "5.0.1",
"progress": "2.0.3", "progress": "2.0.3",
"proxy-from-env": "1.1.0", "proxy-from-env": "1.1.0",
@ -8550,7 +8527,6 @@
"version": "7.12.11", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"requires": { "requires": {
"@babel/highlight": "^7.10.4" "@babel/highlight": "^7.10.4"
} }
@ -8558,14 +8534,12 @@
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.19.1", "version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
"dev": true
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.18.6", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0", "chalk": "^2.0.0",
@ -8576,7 +8550,6 @@
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": { "requires": {
"color-convert": "^1.9.0" "color-convert": "^1.9.0"
} }
@ -8585,7 +8558,6 @@
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": { "requires": {
"ansi-styles": "^3.2.1", "ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
@ -8596,7 +8568,6 @@
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": { "requires": {
"color-name": "1.1.3" "color-name": "1.1.3"
} }
@ -8604,26 +8575,22 @@
"color-name": { "color-name": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
"dev": true
}, },
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
"dev": true
}, },
"has-flag": { "has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
"dev": true
}, },
"supports-color": { "supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": { "requires": {
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
} }
@ -9828,8 +9795,7 @@
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
"dev": true
}, },
"@types/pixelmatch": { "@types/pixelmatch": {
"version": "5.2.4", "version": "5.2.4",
@ -10358,8 +10324,7 @@
"callsites": { "callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
"dev": true
}, },
"camelcase": { "camelcase": {
"version": "5.3.1", "version": "5.3.1",
@ -10547,7 +10512,6 @@
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
"dev": true,
"requires": { "requires": {
"@types/parse-json": "^4.0.0", "@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
@ -10718,7 +10682,6 @@
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"requires": { "requires": {
"is-arrayish": "^0.2.1" "is-arrayish": "^0.2.1"
} }
@ -11990,7 +11953,6 @@
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
"requires": { "requires": {
"parent-module": "^1.0.0", "parent-module": "^1.0.0",
"resolve-from": "^4.0.0" "resolve-from": "^4.0.0"
@ -11999,8 +11961,7 @@
"resolve-from": { "resolve-from": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
"dev": true
} }
} }
}, },
@ -12083,8 +12044,7 @@
"is-arrayish": { "is-arrayish": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
"dev": true
}, },
"is-bigint": { "is-bigint": {
"version": "1.0.4", "version": "1.0.4",
@ -12407,8 +12367,7 @@
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
"dev": true
}, },
"js-yaml": { "js-yaml": {
"version": "3.13.1", "version": "3.13.1",
@ -12429,8 +12388,7 @@
"json-parse-even-better-errors": { "json-parse-even-better-errors": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
"dev": true
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "1.0.0", "version": "1.0.0",
@ -12507,8 +12465,7 @@
"lines-and-columns": { "lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
"dev": true
}, },
"load-json-file": { "load-json-file": {
"version": "4.0.0", "version": "4.0.0",
@ -13171,7 +13128,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"requires": { "requires": {
"callsites": "^3.0.0" "callsites": "^3.0.0"
} }
@ -13180,7 +13136,6 @@
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.0.0", "@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1", "error-ex": "^1.3.1",
@ -13222,8 +13177,7 @@
"path-type": { "path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
"dev": true
}, },
"pend": { "pend": {
"version": "1.2.0", "version": "1.2.0",
@ -13343,6 +13297,7 @@
"puppeteer": { "puppeteer": {
"version": "file:packages/puppeteer", "version": "file:packages/puppeteer",
"requires": { "requires": {
"cosmiconfig": "7.0.1",
"https-proxy-agent": "5.0.1", "https-proxy-agent": "5.0.1",
"progress": "2.0.3", "progress": "2.0.3",
"proxy-from-env": "1.1.0", "proxy-from-env": "1.1.0",
@ -14494,8 +14449,7 @@
"yaml": { "yaml": {
"version": "1.10.2", "version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
"dev": true
}, },
"yargs": { "yargs": {
"version": "17.6.0", "version": "17.6.0",

View File

@ -14,11 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
import {homedir} from 'os'; import {Product} from './Product.js';
import {join} from 'path';
/** /**
* @internal * @public
*/ */
export const PUPPETEER_CACHE_DIR = export interface Configuration {
process.env['PUPPETEER_CACHE_DIR'] ?? join(homedir(), '.cache', 'puppeteer'); browserRevision?: string;
cacheDirectory?: string;
downloadHost?: string;
downloadPath?: string;
executablePath?: string;
defaultProduct?: Product;
temporaryDirectory?: string;
skipDownload?: boolean;
logLevel?: 'silent' | 'error' | 'warn';
experiments?: {
macArmChromiumEnabled?: boolean;
};
}

View File

@ -107,7 +107,7 @@ export class Puppeteer {
/** /**
* @internal * @internal
*/ */
protected _isPuppeteerCore: boolean; _isPuppeteerCore: boolean;
/** /**
* @internal * @internal
*/ */

View File

@ -16,7 +16,7 @@
import {exec as execChildProcess} from 'child_process'; import {exec as execChildProcess} from 'child_process';
import extractZip from 'extract-zip'; import extractZip from 'extract-zip';
import {createReadStream, createWriteStream, existsSync} from 'fs'; import {createReadStream, createWriteStream, existsSync, readdirSync} from 'fs';
import {chmod, mkdir, readdir, unlink} from 'fs/promises'; import {chmod, mkdir, readdir, unlink} from 'fs/promises';
import * as http from 'http'; import * as http from 'http';
import * as https from 'https'; import * as https from 'https';
@ -35,13 +35,8 @@ import * as util from 'util';
import {promisify} from 'util'; import {promisify} from 'util';
import {debug} from '../common/Debug.js'; import {debug} from '../common/Debug.js';
import {Product} from '../common/Product.js'; import {Product} from '../common/Product.js';
import {PUPPETEER_CACHE_DIR} from '../constants.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
const experimentalChromiumMacArm =
process.env['PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM'] ||
process.env['npm_config_puppeteer_experimental_chromium_mac_arm'];
const debugFetcher = debug('puppeteer:fetcher'); const debugFetcher = debug('puppeteer:fetcher');
const downloadURLs: Record<Product, Partial<Record<Platform, string>>> = { const downloadURLs: Record<Product, Partial<Record<Platform, string>>> = {
@ -140,24 +135,39 @@ function handleArm64(): void {
* @public * @public
*/ */
export interface BrowserFetcherOptions { export interface BrowserFetcherOptions {
/**
* Determines the path to download browsers to.
*/
path: string;
/** /**
* Determines which platform the browser will be suited for. * Determines which platform the browser will be suited for.
*
* @defaultValue Auto-detected.
*/ */
platform?: Platform; platform?: Platform;
/** /**
* Determines which product the {@link BrowserFetcher} is for. * Determines which product the {@link BrowserFetcher} is for.
* *
* @defaultValue `"chrome"` * @defaultValue `"chrome"`.
*/ */
product?: 'chrome' | 'firefox'; product?: 'chrome' | 'firefox';
/**
* Determines the path to download browsers to.
*/
path?: string;
/** /**
* Determines the host that will be used for downloading. * Determines the host that will be used for downloading.
*
* @defaultValue Either
*
* - https://storage.googleapis.com or
* - https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central
*
*/ */
host?: string; host?: string;
/**
* Enables the use of the Chromium binary for macOS ARM.
*
* @experimental
*/
useMacOSARMBinary?: boolean;
} }
/** /**
@ -196,7 +206,7 @@ export interface BrowserFetcherRevisionInfo {
* and running Puppeteer against it: * and running Puppeteer against it:
* *
* ```ts * ```ts
* const browserFetcher = new BrowserFetcher(); * const browserFetcher = new BrowserFetcher({path: 'path/to/download/folder'});
* const revisionInfo = await browserFetcher.download('533271'); * const revisionInfo = await browserFetcher.download('533271');
* const browser = await puppeteer.launch({ * const browser = await puppeteer.launch({
* executablePath: revisionInfo.executablePath, * executablePath: revisionInfo.executablePath,
@ -208,23 +218,17 @@ export interface BrowserFetcherRevisionInfo {
export class BrowserFetcher { export class BrowserFetcher {
#product: Product; #product: Product;
#downloadFolder: string; #downloadPath: string;
#downloadHost: string; #downloadHost: string;
#platform: Platform; #platform: Platform;
/** /**
* Constructs a browser fetcher for the given options. * Constructs a browser fetcher for the given options.
*/ */
constructor(options: BrowserFetcherOptions = {}) { constructor(options: BrowserFetcherOptions) {
this.#product = (options.product || 'chrome').toLowerCase() as Product; this.#product = options.product ?? 'chrome';
assert( this.#downloadPath = options.path;
this.#product === 'chrome' || this.#product === 'firefox', this.#downloadHost = options.host ?? browserConfig[this.#product].host;
`Unknown product: "${options.product}"`
);
this.#downloadFolder =
options.path || path.join(PUPPETEER_CACHE_DIR, this.#product);
this.#downloadHost = options.host || browserConfig[this.#product].host;
if (options.platform) { if (options.platform) {
this.#platform = options.platform; this.#platform = options.platform;
@ -235,7 +239,7 @@ export class BrowserFetcher {
switch (this.#product) { switch (this.#product) {
case 'chrome': case 'chrome':
this.#platform = this.#platform =
os.arch() === 'arm64' && experimentalChromiumMacArm os.arch() === 'arm64' && options.useMacOSARMBinary
? 'mac_arm' ? 'mac_arm'
: 'mac'; : 'mac';
break; break;
@ -342,13 +346,13 @@ export class BrowserFetcher {
); );
const fileName = url.split('/').pop(); const fileName = url.split('/').pop();
assert(fileName, `A malformed download URL was found: ${url}.`); assert(fileName, `A malformed download URL was found: ${url}.`);
const archivePath = path.join(this.#downloadFolder, fileName); const archivePath = path.join(this.#downloadPath, fileName);
const outputPath = this.#getFolderPath(revision); const outputPath = this.#getFolderPath(revision);
if (existsSync(outputPath)) { if (existsSync(outputPath)) {
return this.revisionInfo(revision); return this.revisionInfo(revision);
} }
if (!existsSync(this.#downloadFolder)) { if (!existsSync(this.#downloadPath)) {
await mkdir(this.#downloadFolder, {recursive: true}); await mkdir(this.#downloadPath, {recursive: true});
} }
// Use system Chromium builds on Linux ARM devices // Use system Chromium builds on Linux ARM devices
@ -374,25 +378,21 @@ export class BrowserFetcher {
/** /**
* @remarks * @remarks
* This method is affected by the current `product`. * This method is affected by the current `product`.
* @returns A promise with a list of all revision strings (for the current `product`) * @returns A list of all revision strings (for the current `product`)
* available locally on disk. * available locally on disk.
*/ */
async localRevisions(): Promise<string[]> { localRevisions(): string[] {
if (!existsSync(this.#downloadFolder)) { if (!existsSync(this.#downloadPath)) {
return []; return [];
} }
const fileNames = await readdir(this.#downloadFolder); const fileNames = readdirSync(this.#downloadPath);
return fileNames return fileNames
.map(fileName => { .map(fileName => {
return parseFolderPath(this.#product, fileName); return parseFolderPath(this.#product, fileName);
}) })
.filter( .filter((entry): entry is Exclude<typeof entry, undefined> => {
(
entry
): entry is {product: string; platform: string; revision: string} => {
return (entry && entry.platform === this.#platform) ?? false; return (entry && entry.platform === this.#platform) ?? false;
} })
)
.map(entry => { .map(entry => {
return entry.revision; return entry.revision;
}); });
@ -502,7 +502,7 @@ export class BrowserFetcher {
} }
#getFolderPath(revision: string): string { #getFolderPath(revision: string): string {
return path.resolve(this.#downloadFolder, `${this.#platform}-${revision}`); return path.resolve(this.#downloadPath, `${this.#platform}-${revision}`);
} }
} }

View File

@ -1,7 +1,8 @@
import fs from 'fs'; import {accessSync} from 'fs';
import {mkdtemp} from 'fs/promises';
import os from 'os';
import path from 'path'; import path from 'path';
import {CDPBrowser} from '../common/Browser.js'; import {CDPBrowser} from '../common/Browser.js';
import {Product} from '../common/Product.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {BrowserRunner} from './BrowserRunner.js'; import {BrowserRunner} from './BrowserRunner.js';
import { import {
@ -9,32 +10,20 @@ import {
ChromeReleaseChannel, ChromeReleaseChannel,
PuppeteerNodeLaunchOptions, PuppeteerNodeLaunchOptions,
} from './LaunchOptions.js'; } from './LaunchOptions.js';
import { import {ProductLauncher} from './ProductLauncher.js';
executablePathForChannel, import {PuppeteerNode} from './PuppeteerNode.js';
ProductLauncher,
resolveExecutablePath,
} from './ProductLauncher.js';
import {tmpdir} from './util.js';
/** /**
* @internal * @internal
*/ */
export class ChromeLauncher implements ProductLauncher { export class ChromeLauncher extends ProductLauncher {
/** constructor(puppeteer: PuppeteerNode) {
* @internal super(puppeteer, 'chrome');
*/
_preferredRevision: string;
/**
* @internal
*/
_isPuppeteerCore: boolean;
constructor(preferredRevision: string, isPuppeteerCore: boolean) {
this._preferredRevision = preferredRevision;
this._isPuppeteerCore = isPuppeteerCore;
} }
async launch(options: PuppeteerNodeLaunchOptions = {}): Promise<CDPBrowser> { override async launch(
options: PuppeteerNodeLaunchOptions = {}
): Promise<CDPBrowser> {
const { const {
ignoreDefaultArgs = false, ignoreDefaultArgs = false,
args = [], args = [],
@ -93,9 +82,7 @@ export class ChromeLauncher implements ProductLauncher {
if (userDataDirIndex < 0) { if (userDataDirIndex < 0) {
isTempUserDataDir = true; isTempUserDataDir = true;
chromeArguments.push( chromeArguments.push(
`--user-data-dir=${await fs.promises.mkdtemp( `--user-data-dir=${await mkdtemp(this.getProfilePath())}`
path.join(tmpdir(), 'puppeteer_dev_chrome_profile-')
)}`
); );
userDataDirIndex = chromeArguments.length - 1; userDataDirIndex = chromeArguments.length - 1;
} }
@ -104,20 +91,12 @@ export class ChromeLauncher implements ProductLauncher {
assert(typeof userDataDir === 'string', '`--user-data-dir` is malformed'); assert(typeof userDataDir === 'string', '`--user-data-dir` is malformed');
let chromeExecutable = executablePath; let chromeExecutable = executablePath;
if (channel) { if (!chromeExecutable) {
// executablePath is detected by channel, so it should not be specified by user.
assert( assert(
!chromeExecutable, channel || !this.puppeteer._isPuppeteerCore,
'`executablePath` must not be specified when `channel` is given.' `An \`executablePath\` or \`channel\` must be specified for \`puppeteer-core\``
); );
chromeExecutable = this.executablePath(channel);
chromeExecutable = executablePathForChannel(channel);
} else if (!chromeExecutable) {
const {missingText, executablePath} = resolveExecutablePath(this);
if (missingText) {
throw new Error(missingText);
}
chromeExecutable = executablePath;
} }
const usePipe = chromeArguments.includes('--remote-debugging-pipe'); const usePipe = chromeArguments.includes('--remote-debugging-pipe');
@ -143,7 +122,7 @@ export class ChromeLauncher implements ProductLauncher {
usePipe, usePipe,
timeout, timeout,
slowMo, slowMo,
preferredRevision: this._preferredRevision, preferredRevision: this.puppeteer.browserRevision,
}); });
browser = await CDPBrowser._create( browser = await CDPBrowser._create(
this.product, this.product,
@ -177,7 +156,7 @@ export class ChromeLauncher implements ProductLauncher {
return browser; return browser;
} }
defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { override defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] {
const chromeArguments = [ const chromeArguments = [
'--allow-pre-commit-input', '--allow-pre-commit-input',
'--disable-background-networking', '--disable-background-networking',
@ -241,16 +220,88 @@ export class ChromeLauncher implements ProductLauncher {
return chromeArguments; return chromeArguments;
} }
executablePath(channel?: ChromeReleaseChannel): string { override executablePath(channel?: ChromeReleaseChannel): string {
if (channel) { if (channel) {
return executablePathForChannel(channel); return this.#executablePathForChannel(channel);
} else { } else {
const results = resolveExecutablePath(this); return this.resolveExecutablePath();
return results.executablePath;
} }
} }
get product(): Product { /**
return 'chrome'; * @internal
*/
#executablePathForChannel(channel: ChromeReleaseChannel): string {
const platform = os.platform();
let chromePath: string | undefined;
switch (platform) {
case 'win32':
switch (channel) {
case 'chrome':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe`;
break;
case 'chrome-beta':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome Beta\\Application\\chrome.exe`;
break;
case 'chrome-canary':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome SxS\\Application\\chrome.exe`;
break;
case 'chrome-dev':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome Dev\\Application\\chrome.exe`;
break;
}
break;
case 'darwin':
switch (channel) {
case 'chrome':
chromePath =
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'chrome-beta':
chromePath =
'/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta';
break;
case 'chrome-canary':
chromePath =
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary';
break;
case 'chrome-dev':
chromePath =
'/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev';
break;
}
break;
case 'linux':
switch (channel) {
case 'chrome':
chromePath = '/opt/google/chrome/chrome';
break;
case 'chrome-beta':
chromePath = '/opt/google/chrome-beta/chrome';
break;
case 'chrome-dev':
chromePath = '/opt/google/chrome-unstable/chrome';
break;
}
break;
}
if (!chromePath) {
throw new Error(
`Unable to detect browser executable path for '${channel}' on ${platform}.`
);
}
// Check if Chrome exists and is accessible.
try {
accessSync(chromePath);
} catch (error) {
throw new Error(
`Could not find Google Chrome executable for channel '${channel}' at '${chromePath}'.`
);
}
return chromePath;
} }
} }

View File

@ -4,7 +4,6 @@ import path from 'path';
import {Browser} from '../api/Browser.js'; import {Browser} from '../api/Browser.js';
import {Browser as BiDiBrowser} from '../common/bidi/Browser.js'; import {Browser as BiDiBrowser} from '../common/bidi/Browser.js';
import {CDPBrowser} from '../common/Browser.js'; import {CDPBrowser} from '../common/Browser.js';
import {Product} from '../common/Product.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {BrowserFetcher} from './BrowserFetcher.js'; import {BrowserFetcher} from './BrowserFetcher.js';
import {BrowserRunner} from './BrowserRunner.js'; import {BrowserRunner} from './BrowserRunner.js';
@ -12,33 +11,25 @@ import {
BrowserLaunchArgumentOptions, BrowserLaunchArgumentOptions,
PuppeteerNodeLaunchOptions, PuppeteerNodeLaunchOptions,
} from './LaunchOptions.js'; } from './LaunchOptions.js';
import {ProductLauncher, resolveExecutablePath} from './ProductLauncher.js'; import {ProductLauncher} from './ProductLauncher.js';
import {tmpdir} from './util.js'; import {PuppeteerNode} from './PuppeteerNode.js';
/** /**
* @internal * @internal
*/ */
export class FirefoxLauncher implements ProductLauncher { export class FirefoxLauncher extends ProductLauncher {
/** constructor(puppeteer: PuppeteerNode) {
* @internal super(puppeteer, 'firefox');
*/
_preferredRevision: string;
/**
* @internal
*/
_isPuppeteerCore: boolean;
constructor(preferredRevision: string, isPuppeteerCore: boolean) {
this._preferredRevision = preferredRevision;
this._isPuppeteerCore = isPuppeteerCore;
} }
async launch(options: PuppeteerNodeLaunchOptions = {}): Promise<Browser> { override async launch(
options: PuppeteerNodeLaunchOptions = {}
): Promise<Browser> {
const { const {
ignoreDefaultArgs = false, ignoreDefaultArgs = false,
args = [], args = [],
dumpio = false, dumpio = false,
executablePath = null, executablePath,
pipe = false, pipe = false,
env = process.env, env = process.env,
handleSIGINT = true, handleSIGINT = true,
@ -107,20 +98,15 @@ export class FirefoxLauncher implements ProductLauncher {
firefoxArguments.push(userDataDir); firefoxArguments.push(userDataDir);
} }
if (!this._isPuppeteerCore) { let firefoxExecutable: string;
await this._updateRevision(); if (this.puppeteer._isPuppeteerCore || executablePath) {
} assert(
let firefoxExecutable = executablePath; executablePath,
if (!executablePath) { `An \`executablePath\` must be specified for \`puppeteer-core\``
const {missingText, executablePath} = resolveExecutablePath(this); );
if (missingText) {
throw new Error(missingText);
}
firefoxExecutable = executablePath; firefoxExecutable = executablePath;
} } else {
firefoxExecutable = this.executablePath();
if (!firefoxExecutable) {
throw new Error('firefoxExecutable is not found.');
} }
const runner = new BrowserRunner( const runner = new BrowserRunner(
@ -145,7 +131,7 @@ export class FirefoxLauncher implements ProductLauncher {
const connection = await runner.setupWebDriverBiDiConnection({ const connection = await runner.setupWebDriverBiDiConnection({
timeout, timeout,
slowMo, slowMo,
preferredRevision: this._preferredRevision, preferredRevision: this.puppeteer.browserRevision,
}); });
browser = await BiDiBrowser.create({ browser = await BiDiBrowser.create({
connection, connection,
@ -166,7 +152,7 @@ export class FirefoxLauncher implements ProductLauncher {
usePipe: pipe, usePipe: pipe,
timeout, timeout,
slowMo, slowMo,
preferredRevision: this._preferredRevision, preferredRevision: this.puppeteer.browserRevision,
}); });
browser = await CDPBrowser._create( browser = await CDPBrowser._create(
this.product, this.product,
@ -200,28 +186,22 @@ export class FirefoxLauncher implements ProductLauncher {
return browser; return browser;
} }
executablePath(): string { override executablePath(): string {
return resolveExecutablePath(this).executablePath;
}
async _updateRevision(): Promise<void> {
// replace 'latest' placeholder with actual downloaded revision // replace 'latest' placeholder with actual downloaded revision
if (this._preferredRevision === 'latest') { if (this.puppeteer.browserRevision === 'latest') {
const browserFetcher = new BrowserFetcher({ const browserFetcher = new BrowserFetcher({
product: this.product, product: this.product,
path: this.puppeteer.defaultDownloadPath!,
}); });
const localRevisions = await browserFetcher.localRevisions(); const localRevisions = browserFetcher.localRevisions();
if (localRevisions[0]) { if (localRevisions[0]) {
this._preferredRevision = localRevisions[0]; this.puppeteer.configuration.browserRevision = localRevisions[0];
} }
} }
return this.resolveExecutablePath();
} }
get product(): Product { override defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] {
return 'firefox';
}
defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] {
const { const {
devtools = false, devtools = false,
headless = !devtools, headless = !devtools,
@ -503,7 +483,7 @@ export class FirefoxLauncher implements ProductLauncher {
async _createProfile(extraPrefs: {[x: string]: unknown}): Promise<string> { async _createProfile(extraPrefs: {[x: string]: unknown}): Promise<string> {
const temporaryProfilePath = await fs.promises.mkdtemp( const temporaryProfilePath = await fs.promises.mkdtemp(
path.join(tmpdir(), 'puppeteer_dev_firefox_profile-') this.getProfilePath()
); );
const prefs = this.defaultPreferences(extraPrefs); const prefs = this.defaultPreferences(extraPrefs);

View File

@ -13,192 +13,118 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import {accessSync, existsSync} from 'fs'; import {existsSync} from 'fs';
import os from 'os'; import os, {tmpdir} from 'os';
import {join} from 'path';
import {Browser} from '../api/Browser.js'; import {Browser} from '../api/Browser.js';
import {Product} from '../common/Product.js'; import {Product} from '../common/Product.js';
import {BrowserFetcher} from './BrowserFetcher.js'; import {BrowserFetcher} from './BrowserFetcher.js';
import {ChromeLauncher} from './ChromeLauncher.js';
import {FirefoxLauncher} from './FirefoxLauncher.js';
import { import {
BrowserLaunchArgumentOptions, BrowserLaunchArgumentOptions,
ChromeReleaseChannel, ChromeReleaseChannel,
PuppeteerNodeLaunchOptions, PuppeteerNodeLaunchOptions,
} from './LaunchOptions.js'; } from './LaunchOptions.js';
import {PuppeteerNode} from './PuppeteerNode.js';
/** /**
* Describes a launcher - a class that is able to create and launch a browser instance. * Describes a launcher - a class that is able to create and launch a browser instance.
*
* @public * @public
*/ */
export interface ProductLauncher { export class ProductLauncher {
#product: Product;
/**
* @internal
*/
puppeteer: PuppeteerNode;
/**
* @internal
*/
constructor(puppeteer: PuppeteerNode, product: Product) {
this.puppeteer = puppeteer;
this.#product = product;
}
get product(): Product {
return this.#product;
}
launch(object: PuppeteerNodeLaunchOptions): Promise<Browser>; launch(object: PuppeteerNodeLaunchOptions): Promise<Browser>;
executablePath: (path?: any) => string; launch(): Promise<Browser> {
throw new Error('Not implemented');
}
executablePath(channel?: ChromeReleaseChannel): string;
executablePath(): string {
throw new Error('Not implemented');
}
defaultArgs(object: BrowserLaunchArgumentOptions): string[]; defaultArgs(object: BrowserLaunchArgumentOptions): string[];
product: Product; defaultArgs(): string[] {
} throw new Error('Not implemented');
}
/** /**
* @internal * @internal
*/ */
export function executablePathForChannel( protected getProfilePath(): string {
channel: ChromeReleaseChannel return join(
): string { this.puppeteer.configuration.temporaryDirectory ?? tmpdir(),
const platform = os.platform(); `puppeteer_dev_${this.product}_profile-`
let chromePath: string | undefined;
switch (platform) {
case 'win32':
switch (channel) {
case 'chrome':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe`;
break;
case 'chrome-beta':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome Beta\\Application\\chrome.exe`;
break;
case 'chrome-canary':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome SxS\\Application\\chrome.exe`;
break;
case 'chrome-dev':
chromePath = `${process.env['PROGRAMFILES']}\\Google\\Chrome Dev\\Application\\chrome.exe`;
break;
}
break;
case 'darwin':
switch (channel) {
case 'chrome':
chromePath =
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
break;
case 'chrome-beta':
chromePath =
'/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta';
break;
case 'chrome-canary':
chromePath =
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary';
break;
case 'chrome-dev':
chromePath =
'/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev';
break;
}
break;
case 'linux':
switch (channel) {
case 'chrome':
chromePath = '/opt/google/chrome/chrome';
break;
case 'chrome-beta':
chromePath = '/opt/google/chrome-beta/chrome';
break;
case 'chrome-dev':
chromePath = '/opt/google/chrome-unstable/chrome';
break;
}
break;
}
if (!chromePath) {
throw new Error(
`Unable to detect browser executable path for '${channel}' on ${platform}.`
); );
} }
// Check if Chrome exists and is accessible. /**
try {
accessSync(chromePath);
} catch (error) {
throw new Error(
`Could not find Google Chrome executable for channel '${channel}' at '${chromePath}'.`
);
}
return chromePath;
}
/**
* @internal * @internal
*/ */
export function resolveExecutablePath( protected resolveExecutablePath(): string {
launcher: ChromeLauncher | FirefoxLauncher const executablePath = this.puppeteer.configuration.executablePath;
): {
executablePath: string;
missingText?: string;
} {
const {product, _isPuppeteerCore, _preferredRevision} = launcher;
let downloadPath: string | undefined;
// puppeteer-core doesn't take into account PUPPETEER_* env variables.
if (!_isPuppeteerCore) {
const executablePath =
process.env['PUPPETEER_EXECUTABLE_PATH'] ||
process.env['npm_config_puppeteer_executable_path'] ||
process.env['npm_package_config_puppeteer_executable_path'];
if (executablePath) { if (executablePath) {
const missingText = !existsSync(executablePath) if (!existsSync(executablePath)) {
? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' + throw new Error(
executablePath `Tried to find the browser at the configured path (${executablePath}), but no executable was found.`
: undefined; );
return {executablePath, missingText};
} }
return executablePath;
}
const ubuntuChromiumPath = '/usr/bin/chromium-browser'; const ubuntuChromiumPath = '/usr/bin/chromium-browser';
if ( if (
product === 'chrome' && this.product === 'chrome' &&
os.platform() !== 'darwin' && os.platform() !== 'darwin' &&
os.arch() === 'arm64' && os.arch() === 'arm64' &&
existsSync(ubuntuChromiumPath) existsSync(ubuntuChromiumPath)
) { ) {
return {executablePath: ubuntuChromiumPath, missingText: undefined}; return ubuntuChromiumPath;
}
downloadPath =
process.env['PUPPETEER_DOWNLOAD_PATH'] ||
process.env['npm_config_puppeteer_download_path'] ||
process.env['npm_package_config_puppeteer_download_path'];
} }
const browserFetcher = new BrowserFetcher({ const browserFetcher = new BrowserFetcher({
product: product, product: this.product,
path: downloadPath, path: this.puppeteer.defaultDownloadPath!,
}); });
if (!_isPuppeteerCore) { const revisionInfo = browserFetcher.revisionInfo(
let revision = process.env['PUPPETEER_BROWSER_REVISION']; this.puppeteer.browserRevision
if (product === 'chrome') { );
revision ??= process.env['PUPPETEER_CHROMIUM_REVISION']; if (!revisionInfo.local) {
if (this.puppeteer.configuration.browserRevision) {
throw new Error(
`Tried to find the browser at the configured path (${revisionInfo.executablePath}) for revision ${this.puppeteer.browserRevision}, but no executable was found.`
);
} }
if (revision) { switch (this.product) {
const revisionInfo = browserFetcher.revisionInfo(revision);
const missingText = !revisionInfo.local
? 'Tried to use PUPPETEER_CHROMIUM_REVISION env variable to launch browser but did not find executable at: ' +
revisionInfo.executablePath
: undefined;
return {executablePath: revisionInfo.executablePath, missingText};
}
}
const revisionInfo = browserFetcher.revisionInfo(_preferredRevision);
const firefoxHelp = `Run \`PUPPETEER_PRODUCT=firefox npm install\` to download a supported Firefox browser binary.`;
const chromeHelp = `Run \`npm install\` to download the correct Chromium revision (${launcher._preferredRevision}).`;
const missingText = !revisionInfo.local
? `Could not find expected browser (${product}) locally. ${
product === 'chrome' ? chromeHelp : firefoxHelp
}`
: undefined;
return {executablePath: revisionInfo.executablePath, missingText};
}
/**
* @internal
*/
export function createLauncher(
preferredRevision: string,
isPuppeteerCore: boolean,
product: Product = 'chrome'
): ProductLauncher {
switch (product) {
case 'firefox':
return new FirefoxLauncher(preferredRevision, isPuppeteerCore);
case 'chrome': case 'chrome':
return new ChromeLauncher(preferredRevision, isPuppeteerCore); throw new Error(
default: `Run \`npm install\` to download the correct Chromium revision (${this.puppeteer.browserRevision}).`
throw new Error(`Unknown product: ${product}`); );
case 'firefox':
throw new Error(
`Run \`PUPPETEER_PRODUCT=firefox npm install\` to download a supported Firefox browser binary.`
);
}
}
return revisionInfo.executablePath;
} }
} }

View File

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {join} from 'path';
import {Browser} from '../api/Browser.js'; import {Browser} from '../api/Browser.js';
import {BrowserConnectOptions} from '../common/BrowserConnector.js'; import {BrowserConnectOptions} from '../common/BrowserConnector.js';
import {Product} from '../common/Product.js'; import {Product} from '../common/Product.js';
@ -22,10 +23,17 @@ import {
ConnectOptions, ConnectOptions,
Puppeteer, Puppeteer,
} from '../common/Puppeteer.js'; } from '../common/Puppeteer.js';
import {Configuration} from '../common/Configuration.js';
import {PUPPETEER_REVISIONS} from '../revisions.js'; import {PUPPETEER_REVISIONS} from '../revisions.js';
import {BrowserFetcher, BrowserFetcherOptions} from './BrowserFetcher.js'; import {BrowserFetcher, BrowserFetcherOptions} from './BrowserFetcher.js';
import {BrowserLaunchArgumentOptions, LaunchOptions} from './LaunchOptions.js'; import {ChromeLauncher} from './ChromeLauncher.js';
import {createLauncher, ProductLauncher} from './ProductLauncher.js'; import {FirefoxLauncher} from './FirefoxLauncher.js';
import {
BrowserLaunchArgumentOptions,
ChromeReleaseChannel,
LaunchOptions,
} from './LaunchOptions.js';
import {ProductLauncher} from './ProductLauncher.js';
/** /**
* @public * @public
@ -74,28 +82,40 @@ export interface PuppeteerLaunchOptions
* @public * @public
*/ */
export class PuppeteerNode extends Puppeteer { export class PuppeteerNode extends Puppeteer {
#launcher?: ProductLauncher; #_launcher?: ProductLauncher;
#productName?: Product; #lastLaunchedProduct?: Product;
/** /**
* @internal * @internal
*/ */
_preferredRevision = PUPPETEER_REVISIONS.chromium; defaultBrowserRevision: string;
/**
* @internal
*/
configuration: Configuration = {};
/** /**
* @internal * @internal
*/ */
constructor( constructor(
settings: { settings: {
preferredRevision?: string; configuration?: Configuration;
productName?: Product;
} & CommonPuppeteerSettings } & CommonPuppeteerSettings
) { ) {
const {preferredRevision, productName, ...commonSettings} = settings; const {configuration, ...commonSettings} = settings;
super(commonSettings); super(commonSettings);
this.#productName = productName; if (configuration) {
if (preferredRevision) { this.configuration = configuration;
this._preferredRevision = preferredRevision; }
switch (this.configuration.defaultProduct) {
case 'firefox':
this.defaultBrowserRevision = PUPPETEER_REVISIONS.firefox;
break;
default:
this.configuration.defaultProduct = 'chrome';
this.defaultBrowserRevision = PUPPETEER_REVISIONS.chromium;
break;
} }
this.connect = this.connect.bind(this); this.connect = this.connect.bind(this);
@ -116,21 +136,8 @@ export class PuppeteerNode extends Puppeteer {
} }
/** /**
* @internal * Launches a browser instance with given arguments and options when
*/ * specified.
get _productName(): Product | undefined {
return this.#productName;
}
set _productName(name: Product | undefined) {
if (this.#productName !== name) {
this._changedProduct = true;
}
this.#productName = name;
}
/**
* Launches puppeteer and launches a browser instance with given arguments and
* options when specified.
* *
* @example * @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments: * You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
@ -142,90 +149,118 @@ export class PuppeteerNode extends Puppeteer {
* ``` * ```
* *
* @remarks * @remarks
* **NOTE** Puppeteer can also be used to control the Chrome browser, but it * Puppeteer can also be used to control the Chrome browser, but it works best
* works best with the version of Chromium it is bundled with. There is no * with the version of Chromium it is bundled with. There is no guarantee it
* guarantee it will work with any other version. Use `executablePath` option * will work with any other version. Use `executablePath` option with extreme
* with extreme caution. If Google Chrome (rather than Chromium) is preferred, * caution. If Google Chrome (rather than Chromium) is preferred, a
* a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} * {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary}
* or * or
* {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} * {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel}
* build is suggested. In `puppeteer.launch([options])`, any mention of * build is suggested. In {@link Puppeteer.launch}, any mention of Chromium
* Chromium also applies to Chrome. See * also applies to Chrome. See
* {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} * {@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. * 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} * {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article}
* describes some differences for Linux users. * describes some differences for Linux users.
* *
* @param options - Set of configurable options to set on the browser. * @param options - Options to configure launching behavior.
* @returns Promise which resolves to browser instance.
*/ */
launch(options: PuppeteerLaunchOptions = {}): Promise<Browser> { launch(options: PuppeteerLaunchOptions = {}): Promise<Browser> {
if (options.product) { const {product = this.defaultProduct} = options;
this._productName = options.product; this.#lastLaunchedProduct = product;
} return this.#launcher.launch(options);
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(channel?: string): string {
return this._launcher.executablePath(channel);
} }
/** /**
* @internal * @internal
*/ */
get _launcher(): ProductLauncher { get #launcher(): ProductLauncher {
if ( if (
!this.#launcher || this.#_launcher &&
this.#launcher.product !== this._productName || this.#_launcher.product === this.lastLaunchedProduct
this._changedProduct
) { ) {
switch (this._productName) { return this.#_launcher;
case 'firefox': }
this._preferredRevision = PUPPETEER_REVISIONS.firefox; switch (this.lastLaunchedProduct) {
break;
case 'chrome': case 'chrome':
this.defaultBrowserRevision = PUPPETEER_REVISIONS.chromium;
this.#_launcher = new ChromeLauncher(this);
break;
case 'firefox':
this.defaultBrowserRevision = PUPPETEER_REVISIONS.firefox;
this.#_launcher = new FirefoxLauncher(this);
break;
default: default:
this._preferredRevision = PUPPETEER_REVISIONS.chromium; throw new Error(`Unknown product: ${this.#lastLaunchedProduct}`);
} }
this._changedProduct = false; return this.#_launcher;
this.#launcher = createLauncher(
this._preferredRevision,
this._isPuppeteerCore,
this._productName
);
}
return this.#launcher;
} }
/** /**
* The name of the browser that is under automation (`"chrome"` or * @returns The executable path.
* `"firefox"`) */
executablePath(channel?: ChromeReleaseChannel): string {
return this.#launcher.executablePath(channel);
}
/**
* @internal
*/
get browserRevision(): string {
return this.configuration.browserRevision ?? this.defaultBrowserRevision!;
}
/**
* @returns The default download path for puppeteer. For puppeteer-core, this
* code should never be called as it is never defined.
* *
* @remarks * @internal
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the */
* `product` option in `puppeteer.launch([options])` and defaults to `chrome`. get defaultDownloadPath(): string | undefined {
* Firefox support is experimental. return (
this.configuration.downloadPath ??
join(this.configuration.cacheDirectory!, this.product)
);
}
/**
* @returns The name of the browser that was last launched.
*
* @public
*/
get lastLaunchedProduct(): Product {
return this.#lastLaunchedProduct ?? this.defaultProduct;
}
/**
* @returns The name of the browser that will be launched by default. For
* `puppeteer`, this is influenced by your configuration. Otherwise, it's
* `chrome`.
*
* @public
*/
get defaultProduct(): Product {
return this.configuration.defaultProduct ?? 'chrome';
}
/**
* @deprecated Do not use as this field as it does not take into account
* multiple browsers of different types. Use {@link defaultProduct} or
* {@link lastLaunchedProduct}.
*
* @returns The name of the browser that is under automation.
*/ */
get product(): string { get product(): string {
return this._launcher.product; return this.#launcher.product;
} }
/** /**
* @param options - Set of configurable options to set on the browser. * @param options - Set of configurable options to set on the browser.
*
* @returns The default flags that Chromium will be launched with. * @returns The default flags that Chromium will be launched with.
*/ */
defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] {
return this._launcher.defaultArgs(options); return this.#launcher.defaultArgs(options);
} }
/** /**
@ -237,7 +272,22 @@ export class PuppeteerNode extends Puppeteer {
* *
* @returns A new BrowserFetcher instance. * @returns A new BrowserFetcher instance.
*/ */
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher { createBrowserFetcher(
return new BrowserFetcher(options); options: Partial<BrowserFetcherOptions>
): BrowserFetcher {
const downloadPath = this.defaultDownloadPath;
if (downloadPath) {
options.path = downloadPath;
}
if (!options.path) {
throw new Error('A `path` must be specified for `puppeteer-core`.');
}
if (this.configuration.experiments?.macArmChromiumEnabled) {
options.useMacOSARMBinary = true;
}
if (this.configuration.downloadHost) {
options.host = this.configuration.downloadHost;
}
return new BrowserFetcher(options as BrowserFetcherOptions);
} }
} }

View File

@ -1,13 +0,0 @@
import {tmpdir as osTmpDir} from 'os';
/**
* Gets the temporary directory, either from the environmental variable
* `PUPPETEER_TMP_DIR` or the `os.tmpdir`.
*
* @returns The temporary directory path.
*
* @internal
*/
export const tmpdir = (): string => {
return process.env['PUPPETEER_TMP_DIR'] || osTmpDir();
};

View File

@ -9,6 +9,7 @@ export * from './common/Browser.js';
export * from './common/BrowserConnector.js'; export * from './common/BrowserConnector.js';
export * from './common/BrowserWebSocketTransport.js'; export * from './common/BrowserWebSocketTransport.js';
export * from './common/ChromeTargetManager.js'; export * from './common/ChromeTargetManager.js';
export * from './common/Configuration.js';
export * from './common/Connection.js'; export * from './common/Connection.js';
export * from './common/ConnectionTransport.js'; export * from './common/ConnectionTransport.js';
export * from './common/ConsoleMessage.js'; export * from './common/ConsoleMessage.js';
@ -55,7 +56,6 @@ export * from './common/USKeyboardLayout.js';
export * from './common/util.js'; export * from './common/util.js';
export * from './common/WaitTask.js'; export * from './common/WaitTask.js';
export * from './common/WebWorker.js'; export * from './common/WebWorker.js';
export * from './constants.js';
export * from './environment.js'; export * from './environment.js';
export * from './generated/injected.js'; export * from './generated/injected.js';
export * from './generated/version.js'; export * from './generated/version.js';
@ -67,7 +67,6 @@ export * from './node/LaunchOptions.js';
export * from './node/PipeTransport.js'; export * from './node/PipeTransport.js';
export * from './node/ProductLauncher.js'; export * from './node/ProductLauncher.js';
export * from './node/PuppeteerNode.js'; export * from './node/PuppeteerNode.js';
export * from './node/util.js';
export * from './puppeteer-core.js'; export * from './puppeteer-core.js';
export * from './revisions.js'; export * from './revisions.js';
export * from './util/assert.js'; export * from './util/assert.js';

View File

@ -28,69 +28,13 @@ const path = require('path');
const fs = require('fs'); const fs = require('fs');
const {execSync} = require('child_process'); const {execSync} = require('child_process');
async function download() { // Need to ensure TS is compiled before loading the installer
if (!fs.existsSync(path.join(__dirname, 'lib'))) { if (!fs.existsSync(path.join(__dirname, 'lib'))) {
console.log('It seems we are installing from the git repo.'); console.log('It seems we are installing from the git repo.');
console.log('Building install tools from scratch...'); console.log('Building install tools from scratch...');
execSync('npm run build'); execSync('npm run build --workspace puppeteer');
}
// need to ensure TS is compiled before loading the installer
const {
downloadBrowser,
logPolitely,
} = require('puppeteer/lib/cjs/puppeteer/node/install.js');
if (process.env.PUPPETEER_SKIP_DOWNLOAD) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" environment variable was found.'
);
return;
}
if (
process.env.NPM_CONFIG_PUPPETEER_SKIP_DOWNLOAD ||
process.env.npm_config_puppeteer_skip_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" was set in npm config.'
);
return;
}
if (
process.env.NPM_PACKAGE_CONFIG_PUPPETEER_SKIP_DOWNLOAD ||
process.env.npm_package_config_puppeteer_skip_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" was set in project config.'
);
return;
}
if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.'
);
return;
}
if (
process.env.NPM_CONFIG_PUPPETEER_SKIP_CHROMIUM_DOWNLOAD ||
process.env.npm_config_puppeteer_skip_chromium_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" was set in npm config.'
);
return;
}
if (
process.env.NPM_PACKAGE_CONFIG_PUPPETEER_SKIP_CHROMIUM_DOWNLOAD ||
process.env.npm_package_config_puppeteer_skip_chromium_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" was set in project config.'
);
return;
}
downloadBrowser();
} }
download(); const {downloadBrowser} = require('puppeteer/internal/node/install.js');
downloadBrowser();

View File

@ -135,6 +135,7 @@
"author": "The Chromium Authors", "author": "The Chromium Authors",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"cosmiconfig": "7.0.1",
"https-proxy-agent": "5.0.1", "https-proxy-agent": "5.0.1",
"progress": "2.0.3", "progress": "2.0.3",
"proxy-from-env": "1.1.0", "proxy-from-env": "1.1.0",

View File

@ -0,0 +1,95 @@
import {cosmiconfigSync} from 'cosmiconfig';
import {homedir} from 'os';
import {join} from 'path';
import {Configuration, Product} from 'puppeteer-core';
/**
* @internal
*/
function isSupportedProduct(product: unknown): product is Product {
switch (product) {
case 'chrome':
case 'firefox':
return true;
default:
return false;
}
}
/**
* @internal
*/
export const getConfiguration = (): Configuration => {
const result = cosmiconfigSync('puppeteer').search();
const configuration: Configuration = result ? result.config : {};
// Merging environment variables.
configuration.browserRevision =
process.env['PUPPETEER_CHROMIUM_REVISION'] ??
process.env['PUPPETEER_BROWSER_REVISION'] ??
process.env['npm_config_puppeteer_browser_revision'] ??
process.env['npm_package_config_puppeteer_browser_revision'] ??
configuration.browserRevision;
configuration.cacheDirectory =
process.env['PUPPETEER_CACHE_DIR'] ??
process.env['npm_config_puppeteer_cache_dir'] ??
process.env['npm_package_config_puppeteer_cache_dir'] ??
configuration.cacheDirectory ??
join(homedir(), '.cache', 'puppeteer');
configuration.downloadHost =
process.env['PUPPETEER_DOWNLOAD_HOST'] ??
process.env['npm_config_puppeteer_download_host'] ??
process.env['npm_package_config_puppeteer_download_host'] ??
configuration.downloadHost;
configuration.downloadPath =
process.env['PUPPETEER_DOWNLOAD_PATH'] ??
process.env['npm_config_puppeteer_download_path'] ??
process.env['npm_package_config_puppeteer_download_path'] ??
configuration.downloadPath;
configuration.executablePath =
process.env['PUPPETEER_EXECUTABLE_PATH'] ??
process.env['npm_config_puppeteer_executable_path'] ??
process.env['npm_package_config_puppeteer_executable_path'] ??
configuration.executablePath;
configuration.defaultProduct = (process.env['PUPPETEER_PRODUCT'] ??
process.env['npm_config_puppeteer_product'] ??
process.env['npm_package_config_puppeteer_product'] ??
configuration.defaultProduct ??
'chrome') as Product;
configuration.temporaryDirectory =
process.env['PUPPETEER_TMP_DIR'] ??
process.env['npm_config_puppeteer_tmp_dir'] ??
process.env['npm_package_config_puppeteer_tmp_dir'] ??
configuration.temporaryDirectory;
configuration.experiments ??= {};
configuration.experiments.macArmChromiumEnabled = Boolean(
process.env['PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM'] ??
process.env['npm_config_puppeteer_experimental_chromium_mac_arm'] ??
process.env[
'npm_package_config_puppeteer_experimental_chromium_mac_arm'
] ??
configuration.experiments.macArmChromiumEnabled
);
configuration.skipDownload = Boolean(
process.env['PUPPETEER_SKIP_DOWNLOAD'] ??
process.env['npm_config_puppeteer_skip_download'] ??
process.env['npm_package_config_puppeteer_skip_download'] ??
process.env['PUPPETEER_SKIP_CHROMIUM_DOWNLOAD'] ??
process.env['npm_config_puppeteer_skip_chromium_download'] ??
process.env['npm_package_config_puppeteer_skip_chromium_download'] ??
configuration.skipDownload
);
configuration.logLevel = (process.env['PUPPETEER_LOGLEVEL'] ??
process.env['npm_config_LOGLEVEL'] ??
process.env['npm_package_config_LOGLEVEL'] ??
configuration.logLevel) as 'silent' | 'error' | 'warn';
// Validate configuration.
if (!isSupportedProduct(configuration.defaultProduct)) {
throw new Error(`Unsupported product ${configuration.defaultProduct}`);
}
return configuration;
};

View File

@ -16,13 +16,13 @@
import https, {RequestOptions} from 'https'; import https, {RequestOptions} from 'https';
import createHttpsProxyAgent, {HttpsProxyAgentOptions} from 'https-proxy-agent'; import createHttpsProxyAgent, {HttpsProxyAgentOptions} from 'https-proxy-agent';
import {join} from 'path';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
import {getProxyForUrl} from 'proxy-from-env'; import {getProxyForUrl} from 'proxy-from-env';
import {BrowserFetcher} from 'puppeteer-core'; import {BrowserFetcher} from 'puppeteer-core';
import {PuppeteerNode} from 'puppeteer-core/internal/node/PuppeteerNode.js';
import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js';
import URL from 'url'; import URL from 'url';
import puppeteer from '../puppeteer.js'; import {getConfiguration} from '../getConfiguration.js';
/** /**
* @internal * @internal
@ -32,61 +32,40 @@ const supportedProducts = {
firefox: 'Firefox Nightly', firefox: 'Firefox Nightly',
} as const; } as const;
/**
* @internal
*/
function getProduct(input: string): 'chrome' | 'firefox' {
if (input !== 'chrome' && input !== 'firefox') {
throw new Error(`Unsupported product ${input}`);
}
return input;
}
/** /**
* @internal * @internal
*/ */
export async function downloadBrowser(): Promise<void> { export async function downloadBrowser(): Promise<void> {
const downloadHost = const configuration = getConfiguration();
process.env['PUPPETEER_DOWNLOAD_HOST'] || if (configuration.skipDownload) {
process.env['npm_config_puppeteer_download_host'] || logPolitely('**INFO** Skipping browser download as instructed.');
process.env['npm_package_config_puppeteer_download_host']; }
const product = getProduct(
process.env['PUPPETEER_PRODUCT'] || const product = configuration.defaultProduct!;
process.env['npm_config_puppeteer_product'] ||
process.env['npm_package_config_puppeteer_product'] ||
'chrome'
);
const downloadPath =
process.env['PUPPETEER_DOWNLOAD_PATH'] ||
process.env['npm_config_puppeteer_download_path'] ||
process.env['npm_package_config_puppeteer_download_path'];
const browserFetcher = new BrowserFetcher({ const browserFetcher = new BrowserFetcher({
product, product,
host: downloadHost, host: configuration.downloadHost,
path: downloadPath, path:
configuration.downloadPath ??
join(configuration.cacheDirectory!, product),
}); });
const revision = await getRevision();
await fetchBinary(revision);
async function getRevision(): Promise<string> { let revision = configuration.browserRevision;
if (product === 'chrome') {
return ( if (!revision) {
process.env['PUPPETEER_CHROMIUM_REVISION'] || switch (product) {
process.env['npm_config_puppeteer_chromium_revision'] || case 'chrome':
PUPPETEER_REVISIONS.chromium revision = PUPPETEER_REVISIONS.chromium;
); break;
} else if (product === 'firefox') { case 'firefox':
(puppeteer as PuppeteerNode)._preferredRevision = revision = PUPPETEER_REVISIONS.firefox;
PUPPETEER_REVISIONS.firefox; revision = await getFirefoxNightlyVersion();
return getFirefoxNightlyVersion().catch(error => { break;
console.error(error);
process.exit(1);
});
} else {
throw new Error(`Unsupported product ${product}`);
} }
} }
await fetchBinary(revision);
function fetchBinary(revision: string) { function fetchBinary(revision: string) {
const revisionInfo = browserFetcher.revisionInfo(revision); const revisionInfo = browserFetcher.revisionInfo(revision);
@ -222,7 +201,7 @@ export async function downloadBrowser(): Promise<void> {
/** /**
* @internal * @internal
*/ */
export function logPolitely(toBeLogged: unknown): void { function logPolitely(toBeLogged: unknown): void {
const logLevel = process.env['npm_config_loglevel'] || ''; const logLevel = process.env['npm_config_loglevel'] || '';
const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel) > -1; const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel) > -1;

View File

@ -19,37 +19,24 @@ export * from 'puppeteer-core/internal/common/Device.js';
export * from 'puppeteer-core/internal/common/Errors.js'; export * from 'puppeteer-core/internal/common/Errors.js';
export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js'; export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js';
export * from 'puppeteer-core/internal/common/Puppeteer.js'; export * from 'puppeteer-core/internal/common/Puppeteer.js';
export * from 'puppeteer-core/internal/node/BrowserFetcher.js';
/** /**
* @deprecated Use the query handler API defined on {@link Puppeteer} * @deprecated Use the query handler API defined on {@link Puppeteer}
*/ */
export * from 'puppeteer-core/internal/common/QueryHandler.js'; export * from 'puppeteer-core/internal/common/QueryHandler.js';
export * from 'puppeteer-core/internal/node/BrowserFetcher.js';
export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js'; export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js';
import {Product} from 'puppeteer-core';
import {PuppeteerNode} from 'puppeteer-core/internal/node/PuppeteerNode.js'; import {PuppeteerNode} from 'puppeteer-core/internal/node/PuppeteerNode.js';
import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; import {getConfiguration} from './getConfiguration.js';
const productName = (process.env['PUPPETEER_PRODUCT'] || const configuration = getConfiguration();
process.env['npm_config_puppeteer_product'] ||
process.env['npm_package_config_puppeteer_product']) as Product;
let preferredRevision: string;
switch (productName) {
case 'firefox':
preferredRevision = PUPPETEER_REVISIONS.firefox;
break;
default:
preferredRevision = PUPPETEER_REVISIONS.chromium;
}
/** /**
* @public * @public
*/ */
const puppeteer = new PuppeteerNode({ const puppeteer = new PuppeteerNode({
preferredRevision,
isPuppeteerCore: false, isPuppeteerCore: false,
productName, configuration,
}); });
export const { export const {

View File

@ -9,6 +9,7 @@ export * from 'puppeteer-core/internal/common/Browser.js';
export * from 'puppeteer-core/internal/common/BrowserConnector.js'; export * from 'puppeteer-core/internal/common/BrowserConnector.js';
export * from 'puppeteer-core/internal/common/BrowserWebSocketTransport.js'; export * from 'puppeteer-core/internal/common/BrowserWebSocketTransport.js';
export * from 'puppeteer-core/internal/common/ChromeTargetManager.js'; export * from 'puppeteer-core/internal/common/ChromeTargetManager.js';
export * from 'puppeteer-core/internal/common/Configuration.js';
export * from 'puppeteer-core/internal/common/Connection.js'; export * from 'puppeteer-core/internal/common/Connection.js';
export * from 'puppeteer-core/internal/common/ConnectionTransport.js'; export * from 'puppeteer-core/internal/common/ConnectionTransport.js';
export * from 'puppeteer-core/internal/common/ConsoleMessage.js'; export * from 'puppeteer-core/internal/common/ConsoleMessage.js';
@ -55,7 +56,6 @@ export * from 'puppeteer-core/internal/common/USKeyboardLayout.js';
export * from 'puppeteer-core/internal/common/util.js'; export * from 'puppeteer-core/internal/common/util.js';
export * from 'puppeteer-core/internal/common/WaitTask.js'; export * from 'puppeteer-core/internal/common/WaitTask.js';
export * from 'puppeteer-core/internal/common/WebWorker.js'; export * from 'puppeteer-core/internal/common/WebWorker.js';
export * from 'puppeteer-core/internal/constants.js';
export * from 'puppeteer-core/internal/environment.js'; export * from 'puppeteer-core/internal/environment.js';
export * from 'puppeteer-core/internal/generated/injected.js'; export * from 'puppeteer-core/internal/generated/injected.js';
export * from 'puppeteer-core/internal/generated/version.js'; export * from 'puppeteer-core/internal/generated/version.js';
@ -67,10 +67,10 @@ export * from 'puppeteer-core/internal/node/LaunchOptions.js';
export * from 'puppeteer-core/internal/node/PipeTransport.js'; export * from 'puppeteer-core/internal/node/PipeTransport.js';
export * from 'puppeteer-core/internal/node/ProductLauncher.js'; export * from 'puppeteer-core/internal/node/ProductLauncher.js';
export * from 'puppeteer-core/internal/node/PuppeteerNode.js'; export * from 'puppeteer-core/internal/node/PuppeteerNode.js';
export * from 'puppeteer-core/internal/node/util.js';
export * from 'puppeteer-core/internal/revisions.js'; export * from 'puppeteer-core/internal/revisions.js';
export * from 'puppeteer-core/internal/util/assert.js'; export * from 'puppeteer-core/internal/util/assert.js';
export * from 'puppeteer-core/internal/util/DebuggableDeferredPromise.js'; export * from 'puppeteer-core/internal/util/DebuggableDeferredPromise.js';
export * from 'puppeteer-core/internal/util/DeferredPromise.js'; export * from 'puppeteer-core/internal/util/DeferredPromise.js';
export * from 'puppeteer-core/internal/util/ErrorLike.js'; export * from 'puppeteer-core/internal/util/ErrorLike.js';
export * from './getConfiguration.js';
export * from './puppeteer.js'; export * from './puppeteer.js';

View File

@ -0,0 +1,8 @@
const {join} = require('path');
/**
* @type {import("puppeteer").PuppeteerConfiguration}
*/
module.exports = {
cacheDirectory: join(__dirname, '.cache', 'puppeteer'),
};

View File

@ -51,6 +51,7 @@ export interface DescribeInstallationOptions {
* This should be idempotent. * This should be idempotent.
*/ */
env?: ((cwd: string) => NodeJS.ProcessEnv) | NodeJS.ProcessEnv; env?: ((cwd: string) => NodeJS.ProcessEnv) | NodeJS.ProcessEnv;
before?: (cwd: string) => Promise<void>;
} }
export interface DescribeInstallationContext { export interface DescribeInstallationContext {
@ -92,6 +93,10 @@ export const describeInstallation = (
}; };
} }
env = {...process.env, ...getEnv(sandbox)}; env = {...process.env, ...getEnv(sandbox)};
if (options.before) {
await options.before(sandbox);
}
}); });
after(async () => { after(async () => {

View File

@ -0,0 +1,43 @@
/**
* Copyright 2022 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 assert from 'assert';
import {readdir, writeFile} from 'fs/promises';
import {join} from 'path';
import {describeInstallation} from './describeInstallation.js';
import {readAsset} from './util.js';
describeInstallation(
'`puppeteer` with configuration',
{
dependencies: ['puppeteer-core', 'puppeteer'],
before: async cwd => {
await writeFile(
join(cwd, '.puppeteerrc.cjs'),
await readAsset('puppeteer', 'configuration', '.puppeteerrc.cjs')
);
},
},
({itEvaluates}) => {
itEvaluates('properly', async cwd => {
const files = await readdir(join(cwd, '.cache', 'puppeteer'));
assert.equal(files.length, 1);
assert.equal(files[0], 'chrome');
return readAsset('puppeteer', 'basic.js');
});
}
);

View File

@ -20,7 +20,6 @@ import os from 'os';
import path from 'path'; import path from 'path';
import {BrowserFetcher, TimeoutError} from 'puppeteer'; import {BrowserFetcher, TimeoutError} from 'puppeteer';
import {Page} from 'puppeteer-core/internal/api/Page.js'; import {Page} from 'puppeteer-core/internal/api/Page.js';
import {Product} from 'puppeteer-core/internal/common/Product.js';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import sinon from 'sinon'; import sinon from 'sinon';
import {TLSSocket} from 'tls'; import {TLSSocket} from 'tls';
@ -259,7 +258,8 @@ describe('Launcher specs', function () {
const testTmpDir = await fs.promises.mkdtemp( const testTmpDir = await fs.promises.mkdtemp(
path.join(os.tmpdir(), 'puppeteer_test_chrome_profile-') path.join(os.tmpdir(), 'puppeteer_test_chrome_profile-')
); );
process.env['PUPPETEER_TMP_DIR'] = testTmpDir; const oldTmpDir = puppeteer.configuration.temporaryDirectory;
puppeteer.configuration.temporaryDirectory = testTmpDir;
// Path should be empty before starting the browser. // Path should be empty before starting the browser.
expect(fs.readdirSync(testTmpDir).length).toEqual(0); expect(fs.readdirSync(testTmpDir).length).toEqual(0);
@ -277,8 +277,9 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
// Profile should be deleted after closing the browser // Profile should be deleted after closing the browser
expect(fs.readdirSync(testTmpDir).length).toEqual(0); expect(fs.readdirSync(testTmpDir).length).toEqual(0);
// Restore env var // Restore env var
process.env['PUPPETEER_TMP_DIR'] = ''; puppeteer.configuration.temporaryDirectory = oldTmpDir;
}); });
it('userDataDir option restores preferences', async () => { it('userDataDir option restores preferences', async () => {
const {defaultBrowserOptions, puppeteer} = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
@ -624,21 +625,6 @@ describe('Launcher specs', function () {
}); });
describe('Puppeteer.launch', function () { describe('Puppeteer.launch', function () {
let productName!: Product;
before(async () => {
const {puppeteer} = getTestState();
productName = puppeteer._productName!;
});
after(async () => {
const {puppeteer} = getTestState();
// @ts-expect-error launcher is a private property that users can't
// touch, but for testing purposes we need to reset it.
puppeteer._lazyLauncher = undefined;
puppeteer._productName = productName;
});
itOnlyRegularInstall('should be able to launch Chrome', async () => { itOnlyRegularInstall('should be able to launch Chrome', async () => {
const {puppeteer} = getTestState(); const {puppeteer} = getTestState();
const browser = await puppeteer.launch({product: 'chrome'}); const browser = await puppeteer.launch({product: 'chrome'});
@ -890,26 +876,29 @@ describe('Launcher specs', function () {
const executablePath = puppeteer.executablePath('chrome'); const executablePath = puppeteer.executablePath('chrome');
expect(executablePath).toBeTruthy(); expect(executablePath).toBeTruthy();
}); });
describe('when PUPPETEER_EXECUTABLE_PATH is set', () => { describe('when executable path is configured', () => {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
beforeEach(() => { beforeEach(() => {
process.env['PUPPETEER_EXECUTABLE_PATH'] = ''; const {puppeteer} = getTestState();
sandbox sandbox
.stub(process.env, 'PUPPETEER_EXECUTABLE_PATH') .stub(puppeteer.configuration, 'executablePath')
.value('SOME_CUSTOM_EXECUTABLE'); .value('SOME_CUSTOM_EXECUTABLE');
}); });
afterEach(() => { afterEach(() => {
return sandbox.restore(); sandbox.restore();
}); });
it('its value is returned', async () => { it('its value is used', async () => {
const {puppeteer} = getTestState(); const {puppeteer} = getTestState();
try {
const executablePath = puppeteer.executablePath(); puppeteer.executablePath();
} catch (error) {
expect(executablePath).toEqual('SOME_CUSTOM_EXECUTABLE'); expect((error as Error).message).toContain(
'SOME_CUSTOM_EXECUTABLE'
);
}
}); });
}); });
@ -930,26 +919,29 @@ describe('Launcher specs', function () {
osArchStub.restore(); osArchStub.restore();
fsExistsStub.restore(); fsExistsStub.restore();
}); });
describe('and PUPPETEER_EXECUTABLE_PATH is set', () => { describe('and the executable path is configured', () => {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
beforeEach(() => { beforeEach(() => {
process.env['PUPPETEER_EXECUTABLE_PATH'] = ''; const {puppeteer} = getTestState();
sandbox sandbox
.stub(process.env, 'PUPPETEER_EXECUTABLE_PATH') .stub(puppeteer.configuration, 'executablePath')
.value('SOME_CUSTOM_EXECUTABLE'); .value('SOME_CUSTOM_EXECUTABLE');
}); });
afterEach(() => { afterEach(() => {
return sandbox.restore(); sandbox.restore();
}); });
it('its value is returned', async () => { it('its value is used', async () => {
const {puppeteer} = getTestState(); const {puppeteer} = getTestState();
try {
const executablePath = puppeteer.executablePath(); puppeteer.executablePath();
} catch (error) {
expect(executablePath).toEqual('SOME_CUSTOM_EXECUTABLE'); expect((error as Error).message).toContain(
'SOME_CUSTOM_EXECUTABLE'
);
}
}); });
}); });
}); });
@ -961,9 +953,9 @@ describe('Launcher specs', function () {
const fsExistsStub = sinon.stub(fs, 'existsSync'); const fsExistsStub = sinon.stub(fs, 'existsSync');
fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(false); fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(false);
const executablePath = puppeteer.executablePath(); expect(() => {
return puppeteer.executablePath();
expect(executablePath).not.toEqual('/usr/bin/chromium-browser'); }).toThrowError();
osPlatformStub.restore(); osPlatformStub.restore();
osArchStub.restore(); osArchStub.restore();

View File

@ -101,14 +101,6 @@ const defaultBrowserOptions = Object.assign(
`WARN: running ${product} tests with ${defaultBrowserOptions.executablePath}` `WARN: running ${product} tests with ${defaultBrowserOptions.executablePath}`
); );
} else { } else {
// TODO(jackfranklin): declare updateRevision in some form for the Firefox
// launcher.
if (product === 'firefox') {
// @ts-expect-error _updateRevision is defined on the FF launcher
// but not the Chrome one. The types need tidying so that TS can infer that
// properly and not error here.
await puppeteer._launcher._updateRevision();
}
const executablePath = puppeteer.executablePath(); const executablePath = puppeteer.executablePath();
if (!fs.existsSync(executablePath)) { if (!fs.existsSync(executablePath)) {
throw new Error( throw new Error(