2020-05-05 08:36:44 +00:00
/ * *
* Copyright 2017 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 .
* /
2020-06-18 14:53:23 +00:00
import Launcher from '../node/Launcher' ;
2020-06-04 10:47:13 +00:00
import {
2020-05-07 10:54:55 +00:00
LaunchOptions ,
ChromeArgOptions ,
BrowserOptions ,
2020-06-18 14:53:23 +00:00
} from '../node/LaunchOptions' ;
import { ProductLauncher } from '../node/Launcher' ;
import { BrowserFetcher , BrowserFetcherOptions } from '../node/BrowserFetcher' ;
2020-05-07 10:54:55 +00:00
import { puppeteerErrors , PuppeteerErrors } from './Errors' ;
2020-06-04 10:47:13 +00:00
import { ConnectionTransport } from './ConnectionTransport' ;
2020-05-07 10:54:55 +00:00
import { devicesMap } from './DeviceDescriptors' ;
2020-06-18 14:53:23 +00:00
import { DevicesMap } from './DeviceDescriptors' ;
2020-05-07 10:54:55 +00:00
import { Browser } from './Browser' ;
2020-06-04 10:47:13 +00:00
import {
registerCustomQueryHandler ,
unregisterCustomQueryHandler ,
customQueryHandlers ,
clearQueryHandlers ,
QueryHandler ,
} from './QueryHandler' ;
2020-06-29 15:13:24 +00:00
import { PUPPETEER_REVISIONS } from '../revisions' ;
2020-05-05 08:36:44 +00:00
2020-06-04 10:47:13 +00:00
/ * *
* The main Puppeteer class
2020-06-24 14:21:46 +00:00
* Puppeteer module provides a method to launch a browser instance .
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation :
* ` ` ` js
* const puppeteer = require ( 'puppeteer' ) ;
*
* ( async ( ) = > {
* const browser = await puppeteer . launch ( ) ;
* const page = await browser . newPage ( ) ;
* await page . goto ( 'https://www.google.com' ) ;
* // other actions...
* await browser . close ( ) ;
* } ) ( ) ;
* ` ` `
2020-06-04 10:47:13 +00:00
* @public
* /
2020-05-05 08:36:44 +00:00
export class Puppeteer {
2020-06-29 15:13:24 +00:00
private _projectRoot : string ;
2020-05-05 08:36:44 +00:00
_preferredRevision : string ;
_isPuppeteerCore : boolean ;
_changedProduct = false ;
__productName : string ;
_lazyLauncher : ProductLauncher ;
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-07 10:54:55 +00:00
constructor (
projectRoot : string ,
preferredRevision : string ,
isPuppeteerCore : boolean ,
productName : string
) {
2020-05-05 08:36:44 +00:00
this . _projectRoot = projectRoot ;
this . _preferredRevision = preferredRevision ;
this . _isPuppeteerCore = isPuppeteerCore ;
// track changes to Launcher configuration via options or environment variables
this . __productName = productName ;
}
2020-06-24 14:21:46 +00:00
/ * *
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified .
*
* @remarks
*
* @example
* You can use ` ignoreDefaultArgs ` to filter out ` --mute-audio ` from default arguments :
* ` ` ` js
* const browser = await puppeteer . launch ( {
* ignoreDefaultArgs : [ '--mute-audio' ]
* } ) ;
* ` ` `
*
* * * NOTE * * Puppeteer can also be used to control the Chrome browser ,
* but it works best with the version of Chromium it is bundled with .
* There is no guarantee it will work with any other version .
* Use ` executablePath ` option with extreme caution .
* If Google Chrome ( rather than Chromium ) is preferred , a { @link https : //www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In ` puppeteer.launch([options]) ` , any mention of Chromium also applies to Chrome .
* See { @link https : //www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser .
* @returns Promise which resolves to browser instance .
* /
2020-05-07 10:54:55 +00:00
launch (
options : LaunchOptions &
ChromeArgOptions &
BrowserOptions & { product? : string ; extraPrefsFirefox ? : { } } = { }
) : Promise < Browser > {
if ( options . product ) this . _productName = options . product ;
2020-05-05 08:36:44 +00:00
return this . _launcher . launch ( options ) ;
}
2020-06-24 14:21:46 +00:00
/ * *
* This method attaches Puppeteer to an existing browser instance .
*
* @remarks
*
* @param options - Set of configurable options to set on the browser .
* @returns Promise which resolves to browser instance .
* /
2020-05-07 10:54:55 +00:00
connect (
options : BrowserOptions & {
browserWSEndpoint? : string ;
browserURL? : string ;
transport? : ConnectionTransport ;
product? : string ;
}
) : Promise < Browser > {
if ( options . product ) this . _productName = options . product ;
2020-05-05 08:36:44 +00:00
return this . _launcher . connect ( options ) ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
set _productName ( name : string ) {
2020-05-07 10:54:55 +00:00
if ( this . __productName !== name ) this . _changedProduct = true ;
2020-05-05 08:36:44 +00:00
this . __productName = name ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
get _productName ( ) : string {
return this . __productName ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @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 .
* /
2020-05-05 08:36:44 +00:00
executablePath ( ) : string {
return this . _launcher . executablePath ( ) ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
get _launcher ( ) : ProductLauncher {
2020-05-07 10:54:55 +00:00
if (
! this . _lazyLauncher ||
this . _lazyLauncher . product !== this . _productName ||
this . _changedProduct
) {
2020-05-05 08:36:44 +00:00
switch ( this . _productName ) {
case 'firefox' :
2020-06-29 15:13:24 +00:00
this . _preferredRevision = PUPPETEER_REVISIONS . firefox ;
2020-05-05 08:36:44 +00:00
break ;
case 'chrome' :
default :
2020-06-29 15:13:24 +00:00
this . _preferredRevision = PUPPETEER_REVISIONS . chromium ;
2020-05-05 08:36:44 +00:00
}
this . _changedProduct = false ;
2020-05-07 10:54:55 +00:00
this . _lazyLauncher = Launcher (
this . _projectRoot ,
this . _preferredRevision ,
this . _isPuppeteerCore ,
this . _productName
) ;
2020-05-05 08:36:44 +00:00
}
return this . _lazyLauncher ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @returns The name of the browser that is under automation ( ` "chrome" ` or ` "firefox" ` )
*
* @remarks
* The product is set by the ` PUPPETEER_PRODUCT ` environment variable or the ` product `
* option in ` puppeteer.launch([options]) ` and defaults to ` chrome ` .
* Firefox support is experimental .
* /
2020-05-05 08:36:44 +00:00
get product ( ) : string {
return this . _launcher . product ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @remarks
* @example
*
* ` ` ` js
* const puppeteer = require ( 'puppeteer' ) ;
* const iPhone = puppeteer . devices [ 'iPhone 6' ] ;
*
* ( async ( ) = > {
* const browser = await puppeteer . launch ( ) ;
* const page = await browser . newPage ( ) ;
* await page . emulate ( iPhone ) ;
* await page . goto ( 'https://www.google.com' ) ;
* // other actions...
* await browser . close ( ) ;
* } ) ( ) ;
* ` ` `
*
* @returns a list of devices to be used with ` page.emulate(options) ` . Actual list of devices can be found in { @link https : //github.com/puppeteer/puppeteer/blob/main/src/DeviceDescriptors.ts | src/DeviceDescriptors.ts}.
* /
2020-05-05 08:36:44 +00:00
get devices ( ) : DevicesMap {
return devicesMap ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @remarks
*
* Puppeteer methods might throw errors if they are unable to fulfill a request .
* For example , ` page.waitForSelector(selector[, options]) ` might fail if
* the selector doesn ' t match any nodes during the given timeframe .
*
* For certain types of errors Puppeteer uses specific error classes .
* These classes are available via ` puppeteer.errors `
* @example
* An example of handling a timeout error :
* ` ` ` js
* try {
* await page . waitForSelector ( '.foo' ) ;
* } catch ( e ) {
* if ( e instanceof puppeteer . errors . TimeoutError ) {
* // Do something if this is a timeout.
* }
* }
* ` ` `
* /
2020-05-05 08:36:44 +00:00
get errors ( ) : PuppeteerErrors {
return puppeteerErrors ;
}
2020-06-24 14:21:46 +00:00
/ * *
*
* @param options Set of configurable options to set on the browser .
* @returns The default flags that Chromium will be launched with .
* /
2020-06-23 05:18:46 +00:00
defaultArgs ( options : ChromeArgOptions = { } ) : string [ ] {
2020-05-05 08:36:44 +00:00
return this . _launcher . defaultArgs ( options ) ;
}
2020-06-24 14:21:46 +00:00
/ * *
*
* @param options Set of configurable options to specify the settings
* of the BrowserFetcher .
* @returns A new BrowserFetcher instance .
* /
2020-05-05 08:36:44 +00:00
createBrowserFetcher ( options : BrowserFetcherOptions ) : BrowserFetcher {
return new BrowserFetcher ( this . _projectRoot , options ) ;
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
2020-05-07 10:54:55 +00:00
__experimental_registerCustomQueryHandler (
name : string ,
2020-06-04 10:47:13 +00:00
queryHandler : QueryHandler
2020-05-07 10:54:55 +00:00
) : void {
2020-06-04 10:47:13 +00:00
registerCustomQueryHandler ( name , queryHandler ) ;
2020-05-05 08:36:44 +00:00
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_unregisterCustomQueryHandler ( name : string ) : void {
2020-06-04 10:47:13 +00:00
unregisterCustomQueryHandler ( name ) ;
2020-05-05 08:36:44 +00:00
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
2020-06-04 10:47:13 +00:00
__experimental_customQueryHandlers ( ) : Map < string , QueryHandler > {
return customQueryHandlers ( ) ;
2020-05-05 08:36:44 +00:00
}
2020-06-24 14:21:46 +00:00
/ * *
* @internal
* /
2020-05-05 08:36:44 +00:00
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_clearQueryHandlers ( ) : void {
2020-06-04 10:47:13 +00:00
clearQueryHandlers ( ) ;
2020-05-05 08:36:44 +00:00
}
}