Skip to content

Commit

Permalink
feat(launcher): add option to run Puppeteer with different browsers (#…
Browse files Browse the repository at this point in the history
…5137)

* feat: Set which browser to launch via PUPPETEER_PRODUCT

This change introduces a PUPPETEER_PRODUCT environment
variable as a first step toward using Puppeteer with
many different browsers. Setting PUPPETEER_PRODUCT=firefox, for
example, enables Firefox-specific Launcher settings.

The state is also exposed as `puppeteer.product` in the API
to support adding other product-specific behaviour as needed.

The bulk of the change is a refactoring in Launcher
to decouple generic browser start-up from product-specific
configuration.

Respecting the puppeteer-core restriction for PUPPETEER_
environment variables, lazily instantiate the Launcher
based on a `product` Puppeteer.launch option, if available.

* test: Distinguish Juggler unit tests from Firefox

The funit script is renamed to fjunit (j for Juggler, which is
used only by the experimental puppeteer-firefox package.

In contrast, the funit script now refers to running Puppeteer
unit tests against the main puppeteer package with Firefox.
To do so with Firefox Nightly, run:

`BINARY=path/to/firefox npm run funit`

A number of changes in this patch make it easier to run
Puppeteer unit tests in Mozilla's CI.
  • Loading branch information
mjzffr authored and mathiasbynens committed Nov 26, 2019
1 parent d17708b commit c5a72e9
Show file tree
Hide file tree
Showing 16 changed files with 559 additions and 214 deletions.
4 changes: 2 additions & 2 deletions .cirrus.yml
Expand Up @@ -24,12 +24,12 @@ task:

task:
matrix:
- name: Firefox (node8 + linux)
- name: Firefox Juggler (node8 + linux)
container:
dockerfile: .ci/node8/Dockerfile.linux
xvfb_start_background_script: Xvfb :99 -ac -screen 0 1024x768x24
install_script: npm install --unsafe-perm && cd experimental/puppeteer-firefox && npm install --unsafe-perm
test_script: npm run funit
test_script: npm run fjunit

task:
osx_instance:
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -19,7 +19,7 @@ script:
- 'if [ "$NODE8" = "true" ]; then npm run lint; fi'
- 'if [ "$NODE8" = "true" ]; then npm run coverage; fi'
- 'if [ "$FIREFOX" = "true" ]; then cd experimental/puppeteer-firefox && npm i && cd ../..; fi'
- 'if [ "$FIREFOX" = "true" ]; then npm run funit; fi'
- 'if [ "$FIREFOX" = "true" ]; then npm run fjunit; fi'
- 'if [ "$NODE8" = "true" ]; then npm run test-doclint; fi'
- 'if [ "$NODE8" = "true" ]; then npm run test-types; fi'
- 'if [ "$NODE8" = "true" ]; then npm run bundle; fi'
Expand Down
11 changes: 9 additions & 2 deletions CONTRIBUTING.md
Expand Up @@ -199,10 +199,10 @@ npm run unit -- --break-on-failure
HEADLESS=false npm run unit
```

- To run tests with custom Chromium executable:
- To run tests with custom browser executable:

```bash
CHROME=<path-to-executable> npm run unit
BINARY=<path-to-executable> npm run unit
```

- To run tests in slow-mode:
Expand All @@ -211,6 +211,13 @@ CHROME=<path-to-executable> npm run unit
HEADLESS=false SLOW_MO=500 npm run unit
```

- To run tests with additional Launcher options:

```bash
EXTRA_LAUNCH_OPTIONS='{"args": ["--user-data-dir=some/path"], "handleSIGINT": true}' npm run unit
```


- To debug a test, "focus" a test first and then run:

```bash
Expand Down
14 changes: 12 additions & 2 deletions docs/api.md
Expand Up @@ -31,6 +31,7 @@
* [puppeteer.errors](#puppeteererrors)
* [puppeteer.executablePath()](#puppeteerexecutablepath)
* [puppeteer.launch([options])](#puppeteerlaunchoptions)
* [puppeteer.product](#puppeteerproduct)
- [class: BrowserFetcher](#class-browserfetcher)
* [browserFetcher.canDownload(revision)](#browserfetchercandownloadrevision)
* [browserFetcher.download(revision[, progressCallback])](#browserfetcherdownloadrevision-progresscallback)
Expand Down Expand Up @@ -388,6 +389,7 @@ If Puppeteer doesn't find them in the environment during the installation step,
- `PUPPETEER_DOWNLOAD_HOST` - overwrite URL prefix that is used to download Chromium. Note: this includes protocol and might even include path prefix. Defaults to `https://storage.googleapis.com`.
- `PUPPETEER_CHROMIUM_REVISION` - specify a certain version of Chromium you'd like Puppeteer to use. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
- `PUPPETEER_EXECUTABLE_PATH` - specify an executable path to be used in `puppeteer.launch`. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how the executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
- `PUPPETEER_PRODUCT` - specify which browser you'd like Puppeteer to use. Must be one of `chrome` or `firefox`. Setting `product` programmatically in [puppeteer.launch([options])](#puppeteerlaunchoptions) supercedes this environment variable. The product is exposed in [`puppeteer.product`](#puppeteerproduct)

> **NOTE** PUPPETEER_* env variables are not accounted for in the [`puppeteer-core`](https://www.npmjs.com/package/puppeteer-core) package.
Expand Down Expand Up @@ -525,9 +527,10 @@ try {

#### puppeteer.launch([options])
- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
- `product` <[string]> Which browser to launch. At this time, this is either `chrome` or `firefox`. See also `PUPPETEER_PRODUCT`.
- `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
- `headless` <[boolean]> Whether to run browser in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). Defaults to `true` unless the `devtools` option is `true`.
- `executablePath` <[string]> Path to a Chromium or Chrome executable to run instead of the bundled Chromium. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
- `executablePath` <[string]> Path to a browser executable to run instead of the bundled Chromium. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
- `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
- `defaultViewport` <?[Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
- `width` <[number]> page width in pixels.
Expand All @@ -536,7 +539,7 @@ try {
- `isMobile` <[boolean]> Whether the `meta viewport` tag is taken into account. Defaults to `false`.
- `hasTouch`<[boolean]> Specifies if viewport supports touch events. Defaults to `false`
- `isLandscape` <[boolean]> Specifies if viewport is in landscape mode. Defaults to `false`.
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/), and here is the list of [Firefox flags](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options).
- `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, then do not use [`puppeteer.defaultArgs()`](#puppeteerdefaultargsoptions). If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
Expand All @@ -547,6 +550,7 @@ try {
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
- `devtools` <[boolean]> Whether to auto-open a DevTools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
- `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
- `extraPrefsFirefox` <[Object]> Additional [preferences](https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference) that can be passed to Firefox (see `PUPPETEER_PRODUCT`)
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.


Expand All @@ -565,6 +569,12 @@ const browser = await puppeteer.launch({
>
> 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.product
- returns: <[string]> returns the name of the browser that is under automation ("chrome" or "firefox")

The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product` option in [puppeteer.launch([options])](#puppeteerlaunchoptions) and defaults to `chrome`. Firefox support is experimental.


### class: BrowserFetcher

BrowserFetcher can download and manage different versions of Chromium.
Expand Down
6 changes: 3 additions & 3 deletions experimental/puppeteer-firefox/.cirrus.yml
Expand Up @@ -7,7 +7,7 @@ task:
dockerfile: .ci/node8/Dockerfile.linux
xvfb_start_background_script: Xvfb :99 -ac -screen 0 1024x768x24
install_script: npm install
test_script: npm run funit
test_script: npm run fjunit

task:
name: node8 (macOS)
Expand All @@ -19,7 +19,7 @@ task:
- brew install node@8
- brew link --force node@8
install_script: npm install
test_script: npm run funit
test_script: npm run fjunit

# task:
# allow_failures: true
Expand All @@ -28,4 +28,4 @@ task:
# os_version: 2016
# name: node8 (windows)
# install_script: npm install --unsafe-perm
# test_script: npm run funit
# test_script: npm run fjunit
9 changes: 8 additions & 1 deletion index.js
Expand Up @@ -28,4 +28,11 @@ const packageJson = require('./package.json');
const preferredRevision = packageJson.puppeteer.chromium_revision;
const isPuppeteerCore = packageJson.name === 'puppeteer-core';

module.exports = new Puppeteer(__dirname, preferredRevision, isPuppeteerCore);
const puppeteer = new Puppeteer(__dirname, preferredRevision, isPuppeteerCore);

// The introspection in `Helper.installAsyncStackHooks` references `Puppeteer._launcher`
// before the Puppeteer ctor is called, such that an invalid Launcher is selected at import,
// so we reset it.
puppeteer._lazyLauncher = undefined;

module.exports = puppeteer;

0 comments on commit c5a72e9

Please sign in to comment.