puppeteer-core
Advanced tools
Comparing version 3.0.2 to 3.0.3
@@ -28,3 +28,3 @@ /** | ||
const Puppeteer = require('./lib/Puppeteer'); | ||
const {Puppeteer} = require('./lib/Puppeteer'); | ||
const packageJson = require('./package.json'); | ||
@@ -31,0 +31,0 @@ let preferredRevision = packageJson.puppeteer.chromium_revision; |
@@ -16,2 +16,6 @@ /** | ||
*/ | ||
/* This file is used in two places: | ||
* 1) the coverage-utils use it to gain a list of all methods we check for test coverage on | ||
* 2) index.js uses it to iterate through all methods and call helper.installAsyncStackHooks on | ||
*/ | ||
module.exports = { | ||
@@ -34,3 +38,3 @@ Accessibility: require('./Accessibility').Accessibility, | ||
Page: require('./Page').Page, | ||
Puppeteer: require('./Puppeteer'), | ||
Puppeteer: require('./Puppeteer').Puppeteer, | ||
Request: require('./NetworkManager').Request, | ||
@@ -37,0 +41,0 @@ Response: require('./NetworkManager').Response, |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
/** | ||
@@ -16,48 +17,24 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const { helper, assert } = require('./helper'); | ||
const { Target } = require('./Target'); | ||
const EventEmitter = require('events'); | ||
const { TaskQueue } = require('./TaskQueue'); | ||
const { Events } = require('./Events'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { Connection } = require('./Connection'); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const helper_1 = require("./helper"); | ||
const Target_1 = require("./Target"); | ||
const EventEmitter = require("events"); | ||
const TaskQueue_1 = require("./TaskQueue"); | ||
const Events_1 = require("./Events"); | ||
class Browser extends EventEmitter { | ||
/** | ||
* @param {!Connection} connection | ||
* @param {!Array<string>} contextIds | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {?Puppeteer.Viewport} defaultViewport | ||
* @param {?Puppeteer.ChildProcess} process | ||
* @param {function()=} closeCallback | ||
*/ | ||
static async create(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback) { | ||
const browser = new Browser(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback); | ||
await connection.send('Target.setDiscoverTargets', { discover: true }); | ||
return browser; | ||
} | ||
/** | ||
* @param {!Connection} connection | ||
* @param {!Array<string>} contextIds | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {?Puppeteer.Viewport} defaultViewport | ||
* @param {?Puppeteer.ChildProcess} process | ||
* @param {(function():Promise)=} closeCallback | ||
*/ | ||
constructor(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback) { | ||
super(); | ||
this._screenshotTaskQueue = new TaskQueue_1.TaskQueue(); | ||
this._ignoreHTTPSErrors = ignoreHTTPSErrors; | ||
this._defaultViewport = defaultViewport; | ||
this._process = process; | ||
this._screenshotTaskQueue = new TaskQueue(); | ||
this._screenshotTaskQueue = new TaskQueue_1.TaskQueue(); | ||
this._connection = connection; | ||
this._closeCallback = closeCallback || new Function(); | ||
this._closeCallback = closeCallback || function () { }; | ||
this._defaultContext = new BrowserContext(this._connection, this, null); | ||
/** @type {Map<string, BrowserContext>} */ | ||
this._contexts = new Map(); | ||
for (const contextId of contextIds) | ||
this._contexts.set(contextId, new BrowserContext(this._connection, this, contextId)); | ||
/** @type {Map<string, Target>} */ | ||
this._targets = new Map(); | ||
this._connection.on(Events.Connection.Disconnected, () => this.emit(Events.Browser.Disconnected)); | ||
this._connection.on(Events_1.Events.Connection.Disconnected, () => this.emit(Events_1.Events.Browser.Disconnected)); | ||
this._connection.on('Target.targetCreated', this._targetCreated.bind(this)); | ||
@@ -67,11 +44,10 @@ this._connection.on('Target.targetDestroyed', this._targetDestroyed.bind(this)); | ||
} | ||
/** | ||
* @return {?Puppeteer.ChildProcess} | ||
*/ | ||
static async create(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback) { | ||
const browser = new Browser(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback); | ||
await connection.send('Target.setDiscoverTargets', { discover: true }); | ||
return browser; | ||
} | ||
process() { | ||
return this._process; | ||
} | ||
/** | ||
* @return {!Promise<!BrowserContext>} | ||
*/ | ||
async createIncognitoBrowserContext() { | ||
@@ -83,11 +59,5 @@ const { browserContextId } = await this._connection.send('Target.createBrowserContext'); | ||
} | ||
/** | ||
* @return {!Array<!BrowserContext>} | ||
*/ | ||
browserContexts() { | ||
return [this._defaultContext, ...Array.from(this._contexts.values())]; | ||
} | ||
/** | ||
* @return {!BrowserContext} | ||
*/ | ||
defaultBrowserContext() { | ||
@@ -97,4 +67,4 @@ return this._defaultContext; | ||
/** | ||
* @param {?string} contextId | ||
*/ | ||
* @param {?string} contextId | ||
*/ | ||
async _disposeContext(contextId) { | ||
@@ -104,5 +74,2 @@ await this._connection.send('Target.disposeBrowserContext', { browserContextId: contextId || undefined }); | ||
} | ||
/** | ||
* @param {!Protocol.Target.targetCreatedPayload} event | ||
*/ | ||
async _targetCreated(event) { | ||
@@ -112,13 +79,13 @@ const targetInfo = event.targetInfo; | ||
const context = (browserContextId && this._contexts.has(browserContextId)) ? this._contexts.get(browserContextId) : this._defaultContext; | ||
const target = new Target(targetInfo, context, () => this._connection.createSession(targetInfo), this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue); | ||
assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated'); | ||
const target = new Target_1.Target(targetInfo, context, () => this._connection.createSession(targetInfo), this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue); | ||
helper_1.assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated'); | ||
this._targets.set(event.targetInfo.targetId, target); | ||
if (await target._initializedPromise) { | ||
this.emit(Events.Browser.TargetCreated, target); | ||
context.emit(Events.BrowserContext.TargetCreated, target); | ||
this.emit(Events_1.Events.Browser.TargetCreated, target); | ||
context.emit(Events_1.Events.BrowserContext.TargetCreated, target); | ||
} | ||
} | ||
/** | ||
* @param {{targetId: string}} event | ||
*/ | ||
* @param {{targetId: string}} event | ||
*/ | ||
async _targetDestroyed(event) { | ||
@@ -130,12 +97,12 @@ const target = this._targets.get(event.targetId); | ||
if (await target._initializedPromise) { | ||
this.emit(Events.Browser.TargetDestroyed, target); | ||
target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target); | ||
this.emit(Events_1.Events.Browser.TargetDestroyed, target); | ||
target.browserContext().emit(Events_1.Events.BrowserContext.TargetDestroyed, target); | ||
} | ||
} | ||
/** | ||
* @param {!Protocol.Target.targetInfoChangedPayload} event | ||
*/ | ||
* @param {!Protocol.Target.targetInfoChangedPayload} event | ||
*/ | ||
_targetInfoChanged(event) { | ||
const target = this._targets.get(event.targetInfo.targetId); | ||
assert(target, 'target should exist before targetInfoChanged'); | ||
helper_1.assert(target, 'target should exist before targetInfoChanged'); | ||
const previousURL = target.url(); | ||
@@ -145,38 +112,22 @@ const wasInitialized = target._isInitialized; | ||
if (wasInitialized && previousURL !== target.url()) { | ||
this.emit(Events.Browser.TargetChanged, target); | ||
target.browserContext().emit(Events.BrowserContext.TargetChanged, target); | ||
this.emit(Events_1.Events.Browser.TargetChanged, target); | ||
target.browserContext().emit(Events_1.Events.BrowserContext.TargetChanged, target); | ||
} | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
wsEndpoint() { | ||
return this._connection.url(); | ||
} | ||
/** | ||
* @return {!Promise<!Puppeteer.Page>} | ||
*/ | ||
async newPage() { | ||
return this._defaultContext.newPage(); | ||
} | ||
/** | ||
* @param {?string} contextId | ||
* @return {!Promise<!Puppeteer.Page>} | ||
*/ | ||
async _createPageInContext(contextId) { | ||
const { targetId } = await this._connection.send('Target.createTarget', { url: 'about:blank', browserContextId: contextId || undefined }); | ||
const target = await this._targets.get(targetId); | ||
assert(await target._initializedPromise, 'Failed to create target for page'); | ||
helper_1.assert(await target._initializedPromise, 'Failed to create target for page'); | ||
const page = await target.page(); | ||
return page; | ||
} | ||
/** | ||
* @return {!Array<!Target>} | ||
*/ | ||
targets() { | ||
return Array.from(this._targets.values()).filter(target => target._isInitialized); | ||
} | ||
/** | ||
* @return {!Target} | ||
*/ | ||
target() { | ||
@@ -186,6 +137,6 @@ return this.targets().find(target => target.type() === 'browser'); | ||
/** | ||
* @param {function(!Target):boolean} predicate | ||
* @param {{timeout?: number}=} options | ||
* @return {!Promise<!Target>} | ||
*/ | ||
* @param {function(!Target):boolean} predicate | ||
* @param {{timeout?: number}=} options | ||
* @return {!Promise<!Target>} | ||
*/ | ||
async waitForTarget(predicate, options = {}) { | ||
@@ -198,16 +149,13 @@ const { timeout = 30000 } = options; | ||
const targetPromise = new Promise(x => resolve = x); | ||
this.on(Events.Browser.TargetCreated, check); | ||
this.on(Events.Browser.TargetChanged, check); | ||
this.on(Events_1.Events.Browser.TargetCreated, check); | ||
this.on(Events_1.Events.Browser.TargetChanged, check); | ||
try { | ||
if (!timeout) | ||
return await targetPromise; | ||
return await helper.waitWithTimeout(targetPromise, 'target', timeout); | ||
return await helper_1.helper.waitWithTimeout(targetPromise, 'target', timeout); | ||
} | ||
finally { | ||
this.removeListener(Events.Browser.TargetCreated, check); | ||
this.removeListener(Events.Browser.TargetChanged, check); | ||
this.removeListener(Events_1.Events.Browser.TargetCreated, check); | ||
this.removeListener(Events_1.Events.Browser.TargetChanged, check); | ||
} | ||
/** | ||
* @param {!Target} target | ||
*/ | ||
function check(target) { | ||
@@ -218,5 +166,2 @@ if (predicate(target)) | ||
} | ||
/** | ||
* @return {!Promise<!Array<!Puppeteer.Page>>} | ||
*/ | ||
async pages() { | ||
@@ -227,5 +172,2 @@ const contextPages = await Promise.all(this.browserContexts().map(context => context.pages())); | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async version() { | ||
@@ -235,5 +177,2 @@ const version = await this._getVersion(); | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async userAgent() { | ||
@@ -250,11 +189,5 @@ const version = await this._getVersion(); | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isConnected() { | ||
return !this._connection._closed; | ||
} | ||
/** | ||
* @return {!Promise<!Object>} | ||
*/ | ||
_getVersion() { | ||
@@ -264,8 +197,4 @@ return this._connection.send('Browser.getVersion'); | ||
} | ||
exports.Browser = Browser; | ||
class BrowserContext extends EventEmitter { | ||
/** | ||
* @param {!Connection} connection | ||
* @param {!Browser} browser | ||
* @param {?string} contextId | ||
*/ | ||
constructor(connection, browser, contextId) { | ||
@@ -277,19 +206,8 @@ super(); | ||
} | ||
/** | ||
* @return {!Array<!Target>} target | ||
*/ | ||
targets() { | ||
return this._browser.targets().filter(target => target.browserContext() === this); | ||
} | ||
/** | ||
* @param {function(!Target):boolean} predicate | ||
* @param {{timeout?: number}=} options | ||
* @return {!Promise<!Target>} | ||
*/ | ||
waitForTarget(predicate, options) { | ||
return this._browser.waitForTarget(target => target.browserContext() === this && predicate(target), options); | ||
} | ||
/** | ||
* @return {!Promise<!Array<!Puppeteer.Page>>} | ||
*/ | ||
async pages() { | ||
@@ -301,12 +219,5 @@ const pages = await Promise.all(this.targets() | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isIncognito() { | ||
return !!this._id; | ||
} | ||
/** | ||
* @param {string} origin | ||
* @param {!Array<string>} permissions | ||
*/ | ||
async overridePermissions(origin, permissions) { | ||
@@ -317,3 +228,4 @@ const webPermissionToProtocol = new Map([ | ||
['notifications', 'notifications'], | ||
['push', 'push'], | ||
// TODO: push isn't a valid type? | ||
// ['push', 'push'], | ||
['camera', 'videoCapture'], | ||
@@ -344,11 +256,5 @@ ['microphone', 'audioCapture'], | ||
} | ||
/** | ||
* @return {!Promise<!Puppeteer.Page>} | ||
*/ | ||
newPage() { | ||
return this._browser._createPageInContext(this._id); | ||
} | ||
/** | ||
* @return {!Browser} | ||
*/ | ||
browser() { | ||
@@ -358,6 +264,6 @@ return this._browser; | ||
async close() { | ||
assert(this._id, 'Non-incognito profiles cannot be closed!'); | ||
helper_1.assert(this._id, 'Non-incognito profiles cannot be closed!'); | ||
await this._browser._disposeContext(this._id); | ||
} | ||
} | ||
module.exports = { Browser, BrowserContext }; | ||
exports.BrowserContext = BrowserContext; |
@@ -375,3 +375,3 @@ "use strict"; | ||
} | ||
return new Promise(mountAndCopy).catch(err => { console.error(err); }).finally(unmount); | ||
return new Promise(mountAndCopy).catch(error => { console.error(error); }).finally(unmount); | ||
} | ||
@@ -378,0 +378,0 @@ function httpRequest(url, method, response) { |
@@ -19,4 +19,3 @@ "use strict"; | ||
const helper_1 = require("./helper"); | ||
const EventsModule = require("./Events"); | ||
const { Events } = EventsModule; | ||
const Events_1 = require("./Events"); | ||
const debug = require("debug"); | ||
@@ -26,7 +25,2 @@ const debugProtocol = debug('puppeteer:protocol'); | ||
class Connection extends EventEmitter { | ||
/** | ||
* @param {string} url | ||
* @param {!Puppeteer.ConnectionTransport} transport | ||
* @param {number=} delay | ||
*/ | ||
constructor(url, transport, delay = 0) { | ||
@@ -57,3 +51,3 @@ super(); | ||
} | ||
send(method, params = {}) { | ||
send(method, params) { | ||
const id = this._rawSend({ method, params }); | ||
@@ -120,3 +114,3 @@ return new Promise((resolve, reject) => { | ||
this._sessions.clear(); | ||
this.emit(Events.Connection.Disconnected); | ||
this.emit(Events_1.Events.Connection.Disconnected); | ||
} | ||
@@ -185,3 +179,3 @@ dispose() { | ||
this._connection = null; | ||
this.emit(Events.CDPSession.Disconnected); | ||
this.emit(Events_1.Events.CDPSession.Disconnected); | ||
} | ||
@@ -188,0 +182,0 @@ } |
@@ -86,5 +86,5 @@ "use strict"; | ||
} | ||
catch (e) { | ||
catch (error) { | ||
// This might happen if the page has already navigated away. | ||
helper_1.debugError(e); | ||
helper_1.debugError(error); | ||
} | ||
@@ -163,5 +163,5 @@ } | ||
} | ||
catch (e) { | ||
catch (error) { | ||
// This might happen if the page has already navigated away. | ||
helper_1.debugError(e); | ||
helper_1.debugError(error); | ||
} | ||
@@ -168,0 +168,0 @@ } |
@@ -17,2 +17,3 @@ "use strict"; | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const devices = [ | ||
@@ -873,4 +874,4 @@ { | ||
const devicesMap = {}; | ||
exports.devicesMap = devicesMap; | ||
for (const device of devices) | ||
devicesMap[device.name] = device; | ||
module.exports = devicesMap; |
@@ -17,3 +17,7 @@ "use strict"; | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const helper_1 = require("./helper"); | ||
/* TODO(jacktfranklin): protocol.d.ts defines this | ||
* so let's ditch this and avoid the duplication | ||
*/ | ||
var DialogType; | ||
@@ -25,3 +29,3 @@ (function (DialogType) { | ||
DialogType["Prompt"] = "prompt"; | ||
})(DialogType || (DialogType = {})); | ||
})(DialogType = exports.DialogType || (exports.DialogType = {})); | ||
class Dialog { | ||
@@ -60,3 +64,3 @@ constructor(client, type, message, defaultValue = '') { | ||
} | ||
exports.Dialog = Dialog; | ||
Dialog.Type = DialogType; | ||
module.exports = { Dialog }; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
/** | ||
@@ -16,42 +17,21 @@ * Copyright 2019 Google Inc. All rights reserved. | ||
*/ | ||
const fs = require('fs'); | ||
const { helper, assert } = require('./helper'); | ||
const { LifecycleWatcher } = require('./LifecycleWatcher'); | ||
const { TimeoutError } = require('./Errors'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { JSHandle, ElementHandle } = require('./JSHandle'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { ExecutionContext } = require('./ExecutionContext'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { TimeoutSettings } = require('./TimeoutSettings'); | ||
const readFileAsync = helper.promisify(fs.readFile); | ||
/** | ||
* @unrestricted | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs = require("fs"); | ||
const helper_1 = require("./helper"); | ||
const LifecycleWatcher_1 = require("./LifecycleWatcher"); | ||
const Errors_1 = require("./Errors"); | ||
const QueryHandler_1 = require("./QueryHandler"); | ||
const readFileAsync = helper_1.helper.promisify(fs.readFile); | ||
class DOMWorld { | ||
/** | ||
* @param {!Puppeteer.FrameManager} frameManager | ||
* @param {!Puppeteer.Frame} frame | ||
* @param {!TimeoutSettings} timeoutSettings | ||
*/ | ||
constructor(frameManager, frame, timeoutSettings) { | ||
this._documentPromise = null; | ||
this._contextPromise = null; | ||
this._contextResolveCallback = null; | ||
this._detached = false; | ||
this._waitTasks = new Set(); | ||
this._frameManager = frameManager; | ||
this._frame = frame; | ||
this._timeoutSettings = timeoutSettings; | ||
/** @type {?Promise<!ElementHandle>} */ | ||
this._documentPromise = null; | ||
/** @type {!Promise<!ExecutionContext>} */ | ||
this._contextPromise; | ||
this._contextResolveCallback = null; | ||
this._setContext(null); | ||
/** @type {!Set<!WaitTask>} */ | ||
this._waitTasks = new Set(); | ||
this._detached = false; | ||
} | ||
/** | ||
* @return {!Puppeteer.Frame} | ||
*/ | ||
frame() { | ||
@@ -77,5 +57,2 @@ return this._frame; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
_hasContext() { | ||
@@ -124,5 +101,2 @@ return !this._contextResolveCallback; | ||
} | ||
/** | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async _document() { | ||
@@ -137,6 +111,2 @@ if (this._documentPromise) | ||
} | ||
/** | ||
* @param {string} expression | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $x(expression) { | ||
@@ -147,8 +117,2 @@ const document = await this._document(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $eval(selector, pageFunction, ...args) { | ||
@@ -158,8 +122,2 @@ const document = await this._document(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $$eval(selector, pageFunction, ...args) { | ||
@@ -179,5 +137,2 @@ const document = await this._document(); | ||
} | ||
/** | ||
* @return {!Promise<String>} | ||
*/ | ||
async content() { | ||
@@ -193,6 +148,2 @@ return await this.evaluate(() => { | ||
} | ||
/** | ||
* @param {string} html | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
*/ | ||
async setContent(html, options = {}) { | ||
@@ -207,3 +158,3 @@ const { waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), } = options; | ||
}, html); | ||
const watcher = new LifecycleWatcher(this._frameManager, this._frame, waitUntil, timeout); | ||
const watcher = new LifecycleWatcher_1.LifecycleWatcher(this._frameManager, this._frame, waitUntil, timeout); | ||
const error = await Promise.race([ | ||
@@ -243,7 +194,2 @@ watcher.timeoutOrTerminationPromise(), | ||
throw new Error('Provide an object with a `url`, `path` or `content` property'); | ||
/** | ||
* @param {string} url | ||
* @param {string} type | ||
* @return {!Promise<!HTMLElement>} | ||
*/ | ||
async function addScriptUrl(url, type) { | ||
@@ -262,7 +208,2 @@ const script = document.createElement('script'); | ||
} | ||
/** | ||
* @param {string} content | ||
* @param {string} type | ||
* @return {!HTMLElement} | ||
*/ | ||
function addScriptContent(content, type = 'text/javascript') { | ||
@@ -280,6 +221,2 @@ const script = document.createElement('script'); | ||
} | ||
/** | ||
* @param {!{url?: string, path?: string, content?: string}} options | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async addStyleTag(options) { | ||
@@ -307,6 +244,2 @@ const { url = null, path = null, content = null } = options; | ||
throw new Error('Provide an object with a `url`, `path` or `content` property'); | ||
/** | ||
* @param {string} url | ||
* @return {!Promise<!HTMLElement>} | ||
*/ | ||
async function addStyleUrl(url) { | ||
@@ -324,6 +257,2 @@ const link = document.createElement('link'); | ||
} | ||
/** | ||
* @param {string} content | ||
* @return {!Promise<!HTMLElement>} | ||
*/ | ||
async function addStyleContent(content) { | ||
@@ -342,38 +271,23 @@ const style = document.createElement('style'); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options | ||
*/ | ||
async click(selector, options) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
await handle.click(options); | ||
await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async focus(selector) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
await handle.focus(); | ||
await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async hover(selector) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
await handle.hover(); | ||
await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!Array<string>} values | ||
* @return {!Promise<!Array<string>>} | ||
*/ | ||
async select(selector, ...values) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
const result = await handle.select(...values); | ||
@@ -383,59 +297,27 @@ await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async tap(selector) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
await handle.tap(); | ||
await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {string} text | ||
* @param {{delay: (number|undefined)}=} options | ||
*/ | ||
async type(selector, text, options) { | ||
const handle = await this.$(selector); | ||
assert(handle, 'No node found for selector: ' + selector); | ||
helper_1.assert(handle, 'No node found for selector: ' + selector); | ||
await handle.type(text, options); | ||
await handle.dispose(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
waitForSelector(selector, options) { | ||
return this._waitForSelectorOrXPath(selector, false, options); | ||
} | ||
/** | ||
* @param {string} xpath | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
waitForXPath(xpath, options) { | ||
return this._waitForSelectorOrXPath(xpath, true, options); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!{polling?: string|number, timeout?: number}=} options | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
waitForFunction(pageFunction, options = {}, ...args) { | ||
const { polling = 'raf', timeout = this._timeoutSettings.timeout(), } = options; | ||
return new WaitTask(this, pageFunction, 'function', polling, timeout, ...args).promise; | ||
return new WaitTask(this, pageFunction, undefined, 'function', polling, timeout, ...args).promise; | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async title() { | ||
return this.evaluate(() => document.title); | ||
} | ||
/** | ||
* @param {string} selectorOrXPath | ||
* @param {boolean} isXPath | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
async _waitForSelectorOrXPath(selectorOrXPath, isXPath, options = {}) { | ||
@@ -445,3 +327,4 @@ const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options; | ||
const title = `${isXPath ? 'XPath' : 'selector'} "${selectorOrXPath}"${waitForHidden ? ' to be hidden' : ''}`; | ||
const waitTask = new WaitTask(this, predicate, title, polling, timeout, selectorOrXPath, isXPath, waitForVisible, waitForHidden); | ||
const { updatedSelector, queryHandler } = QueryHandler_1.getQueryHandlerAndSelector(selectorOrXPath, (element, selector) => document.querySelector(selector)); | ||
const waitTask = new WaitTask(this, predicate, queryHandler, title, polling, timeout, updatedSelector, isXPath, waitForVisible, waitForHidden); | ||
const handle = await waitTask.promise; | ||
@@ -463,3 +346,3 @@ if (!handle.asElement()) { | ||
? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue | ||
: document.querySelector(selectorOrXPath); | ||
: predicateQueryHandler ? predicateQueryHandler(document, selectorOrXPath) : document.querySelector(selectorOrXPath); | ||
if (!node) | ||
@@ -469,3 +352,3 @@ return waitForHidden; | ||
return node; | ||
const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node); | ||
const element = (node.nodeType === Node.TEXT_NODE ? node.parentElement : node); | ||
const style = window.getComputedStyle(element); | ||
@@ -475,5 +358,2 @@ const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox(); | ||
return success ? node : null; | ||
/** | ||
* @return {boolean} | ||
*/ | ||
function hasVisibleBoundingBox() { | ||
@@ -486,21 +366,29 @@ const rect = element.getBoundingClientRect(); | ||
} | ||
exports.DOMWorld = DOMWorld; | ||
class WaitTask { | ||
/** | ||
* @param {!DOMWorld} domWorld | ||
* @param {Function|string} predicateBody | ||
* @param {string|number} polling | ||
* @param {number} timeout | ||
* @param {!Array<*>} args | ||
*/ | ||
constructor(domWorld, predicateBody, title, polling, timeout, ...args) { | ||
if (helper.isString(polling)) | ||
assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling); | ||
else if (helper.isNumber(polling)) | ||
assert(polling > 0, 'Cannot poll with non-positive interval: ' + polling); | ||
constructor(domWorld, predicateBody, predicateQueryHandlerBody, title, polling, timeout, ...args) { | ||
this._runCount = 0; | ||
this._terminated = false; | ||
if (helper_1.helper.isString(polling)) | ||
helper_1.assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling); | ||
else if (helper_1.helper.isNumber(polling)) | ||
helper_1.assert(polling > 0, 'Cannot poll with non-positive interval: ' + polling); | ||
else | ||
throw new Error('Unknown polling options: ' + polling); | ||
function getPredicateBody(predicateBody, predicateQueryHandlerBody) { | ||
if (helper_1.helper.isString(predicateBody)) | ||
return `return (${predicateBody});`; | ||
if (predicateQueryHandlerBody) { | ||
return ` | ||
return (function wrapper(args) { | ||
const predicateQueryHandler = ${predicateQueryHandlerBody}; | ||
return (${predicateBody})(...args); | ||
})(args);`; | ||
} | ||
return `return (${predicateBody})(...args);`; | ||
} | ||
this._domWorld = domWorld; | ||
this._polling = polling; | ||
this._timeout = timeout; | ||
this._predicateBody = helper.isString(predicateBody) ? 'return (' + predicateBody + ')' : 'return (' + predicateBody + ')(...args)'; | ||
this._predicateBody = getPredicateBody(predicateBody, predicateQueryHandlerBody); | ||
this._args = args; | ||
@@ -516,3 +404,3 @@ this._runCount = 0; | ||
if (timeout) { | ||
const timeoutError = new TimeoutError(`waiting for ${title} failed: timeout ${timeout}ms exceeded`); | ||
const timeoutError = new Errors_1.TimeoutError(`waiting for ${title} failed: timeout ${timeout}ms exceeded`); | ||
this._timeoutTimer = setTimeout(() => this.terminate(timeoutError), timeout); | ||
@@ -522,5 +410,2 @@ } | ||
} | ||
/** | ||
* @param {!Error} error | ||
*/ | ||
terminate(error) { | ||
@@ -539,4 +424,4 @@ this._terminated = true; | ||
} | ||
catch (e) { | ||
error = e; | ||
catch (error_) { | ||
error = error_; | ||
} | ||
@@ -551,3 +436,3 @@ if (this._terminated || runCount !== this._runCount) { | ||
// throw an error - ignore this predicate run altogether. | ||
if (!error && await this._domWorld.evaluate(s => !s, success).catch(e => true)) { | ||
if (!error && await this._domWorld.evaluate(s => !s, success).catch(() => true)) { | ||
await success.dispose(); | ||
@@ -573,11 +458,4 @@ return; | ||
this._domWorld._waitTasks.delete(this); | ||
this._runningTask = null; | ||
} | ||
} | ||
/** | ||
* @param {string} predicateBody | ||
* @param {string} polling | ||
* @param {number} timeout | ||
* @return {!Promise<*>} | ||
*/ | ||
async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) { | ||
@@ -598,3 +476,3 @@ const predicate = new Function('...args', predicateBody); | ||
function pollMutation() { | ||
const success = predicate.apply(null, args); | ||
const success = predicate(...args); | ||
if (success) | ||
@@ -604,3 +482,3 @@ return Promise.resolve(success); | ||
const result = new Promise(x => fulfill = x); | ||
const observer = new MutationObserver(mutations => { | ||
const observer = new MutationObserver(() => { | ||
if (timedOut) { | ||
@@ -610,3 +488,3 @@ observer.disconnect(); | ||
} | ||
const success = predicate.apply(null, args); | ||
const success = predicate(...args); | ||
if (success) { | ||
@@ -624,5 +502,2 @@ observer.disconnect(); | ||
} | ||
/** | ||
* @return {!Promise<*>} | ||
*/ | ||
function pollRaf() { | ||
@@ -638,3 +513,3 @@ let fulfill; | ||
} | ||
const success = predicate.apply(null, args); | ||
const success = predicate(...args); | ||
if (success) | ||
@@ -646,6 +521,2 @@ fulfill(success); | ||
} | ||
/** | ||
* @param {number} pollInterval | ||
* @return {!Promise<*>} | ||
*/ | ||
function pollInterval(pollInterval) { | ||
@@ -661,3 +532,3 @@ let fulfill; | ||
} | ||
const success = predicate.apply(null, args); | ||
const success = predicate(...args); | ||
if (success) | ||
@@ -670,2 +541,1 @@ fulfill(success); | ||
} | ||
module.exports = { DOMWorld }; |
@@ -1,32 +0,9 @@ | ||
/** | ||
* 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. | ||
*/ | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { CDPSession } = require('./Connection'); | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class EmulationManager { | ||
/** | ||
* @param {!CDPSession} client | ||
*/ | ||
constructor(client) { | ||
this._client = client; | ||
this._emulatingMobile = false; | ||
this._hasTouch = false; | ||
this._client = client; | ||
} | ||
/** | ||
* @param {!Puppeteer.Viewport} viewport | ||
* @return {Promise<boolean>} | ||
*/ | ||
async emulateViewport(viewport) { | ||
@@ -37,3 +14,2 @@ const mobile = viewport.isMobile || false; | ||
const deviceScaleFactor = viewport.deviceScaleFactor || 1; | ||
/** @type {Protocol.Emulation.ScreenOrientation} */ | ||
const screenOrientation = viewport.isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' }; | ||
@@ -53,2 +29,2 @@ const hasTouch = viewport.hasTouch || false; | ||
} | ||
module.exports = { EmulationManager }; | ||
exports.EmulationManager = EmulationManager; |
@@ -28,1 +28,4 @@ "use strict"; | ||
exports.TimeoutError = TimeoutError; | ||
exports.puppeteerErrors = { | ||
TimeoutError, | ||
}; |
@@ -60,3 +60,3 @@ "use strict"; | ||
} | ||
catch (e1) { | ||
catch (error) { | ||
// This means we might have a function shorthand. Try another | ||
@@ -71,3 +71,3 @@ // time prefixing 'function '. | ||
} | ||
catch (e2) { | ||
catch (error) { | ||
// We tried hard to serialize, but there's a weird beast here. | ||
@@ -88,6 +88,6 @@ throw new Error('Passed function is not well-serializable!'); | ||
} | ||
catch (err) { | ||
if (err instanceof TypeError && err.message.startsWith('Converting circular structure to JSON')) | ||
err.message += ' Are you passing a nested JSHandle?'; | ||
throw err; | ||
catch (error) { | ||
if (error instanceof TypeError && error.message.startsWith('Converting circular structure to JSON')) | ||
error.message += ' Are you passing a nested JSHandle?'; | ||
throw error; | ||
} | ||
@@ -94,0 +94,0 @@ const { exceptionDetails, result: remoteObject } = await callFunctionOnPromise.catch(rewriteError); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
/** | ||
@@ -16,38 +17,21 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const EventEmitter = require('events'); | ||
const { helper, assert, debugError } = require('./helper'); | ||
const { Events } = require('./Events'); | ||
const { ExecutionContext, EVALUATION_SCRIPT_URL } = require('./ExecutionContext'); | ||
const { LifecycleWatcher } = require('./LifecycleWatcher'); | ||
const { DOMWorld } = require('./DOMWorld'); | ||
const { NetworkManager } = require('./NetworkManager'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { TimeoutSettings } = require('./TimeoutSettings'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { CDPSession } = require('./Connection'); | ||
// Used as a TypeDef | ||
// eslint-disable-next-line no-unused-vars | ||
const { JSHandle, ElementHandle } = require('./JSHandle'); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const EventEmitter = require("events"); | ||
const helper_1 = require("./helper"); | ||
const Events_1 = require("./Events"); | ||
const ExecutionContext_1 = require("./ExecutionContext"); | ||
const LifecycleWatcher_1 = require("./LifecycleWatcher"); | ||
const DOMWorld_1 = require("./DOMWorld"); | ||
const NetworkManager_1 = require("./NetworkManager"); | ||
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__'; | ||
class FrameManager extends EventEmitter { | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {!Puppeteer.Page} page | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {!TimeoutSettings} timeoutSettings | ||
*/ | ||
constructor(client, page, ignoreHTTPSErrors, timeoutSettings) { | ||
super(); | ||
this._frames = new Map(); | ||
this._contextIdToContext = new Map(); | ||
this._isolatedWorlds = new Set(); | ||
this._client = client; | ||
this._page = page; | ||
this._networkManager = new NetworkManager(client, ignoreHTTPSErrors, this); | ||
this._networkManager = new NetworkManager_1.NetworkManager(client, ignoreHTTPSErrors, this); | ||
this._timeoutSettings = timeoutSettings; | ||
/** @type {!Map<string, !Frame>} */ | ||
this._frames = new Map(); | ||
/** @type {!Map<number, !ExecutionContext>} */ | ||
this._contextIdToContext = new Map(); | ||
/** @type {!Set<string>} */ | ||
this._isolatedWorlds = new Set(); | ||
this._client.on('Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId)); | ||
@@ -60,3 +44,3 @@ this._client.on('Page.frameNavigated', event => this._onFrameNavigated(event.frame)); | ||
this._client.on('Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId)); | ||
this._client.on('Runtime.executionContextsCleared', event => this._onExecutionContextsCleared()); | ||
this._client.on('Runtime.executionContextsCleared', () => this._onExecutionContextsCleared()); | ||
this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event)); | ||
@@ -69,3 +53,3 @@ } | ||
]); | ||
const { frameTree } = /** @type Protocol.Page.getFrameTreeReturnValue*/ (result[1]); | ||
const { frameTree } = result[1]; | ||
this._handleFrameTree(frameTree); | ||
@@ -78,18 +62,9 @@ await Promise.all([ | ||
} | ||
/** | ||
* @return {!NetworkManager} | ||
*/ | ||
networkManager() { | ||
return this._networkManager; | ||
} | ||
/** | ||
* @param {!Puppeteer.Frame} frame | ||
* @param {string} url | ||
* @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async navigateFrame(frame, url, options = {}) { | ||
assertNoLegacyNavigationOptions(options); | ||
const { referer = this._networkManager.extraHTTPHeaders()['referer'], waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), } = options; | ||
const watcher = new LifecycleWatcher(this, frame, waitUntil, timeout); | ||
const watcher = new LifecycleWatcher_1.LifecycleWatcher(this, frame, waitUntil, timeout); | ||
let ensureNewDocumentNavigation = false; | ||
@@ -110,9 +85,2 @@ let error = await Promise.race([ | ||
return watcher.navigationResponse(); | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {string} url | ||
* @param {string} referrer | ||
* @param {string} frameId | ||
* @return {!Promise<?Error>} | ||
*/ | ||
async function navigate(client, url, referrer, frameId) { | ||
@@ -129,11 +97,6 @@ try { | ||
} | ||
/** | ||
* @param {!Puppeteer.Frame} frame | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async waitForFrameNavigation(frame, options = {}) { | ||
assertNoLegacyNavigationOptions(options); | ||
const { waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), } = options; | ||
const watcher = new LifecycleWatcher(this, frame, waitUntil, timeout); | ||
const watcher = new LifecycleWatcher_1.LifecycleWatcher(this, frame, waitUntil, timeout); | ||
const error = await Promise.race([ | ||
@@ -149,5 +112,2 @@ watcher.timeoutOrTerminationPromise(), | ||
} | ||
/** | ||
* @param {!Protocol.Page.lifecycleEventPayload} event | ||
*/ | ||
_onLifecycleEvent(event) { | ||
@@ -158,7 +118,4 @@ const frame = this._frames.get(event.frameId); | ||
frame._onLifecycleEvent(event.loaderId, event.name); | ||
this.emit(Events.FrameManager.LifecycleEvent, frame); | ||
this.emit(Events_1.Events.FrameManager.LifecycleEvent, frame); | ||
} | ||
/** | ||
* @param {string} frameId | ||
*/ | ||
_onFrameStoppedLoading(frameId) { | ||
@@ -169,7 +126,4 @@ const frame = this._frames.get(frameId); | ||
frame._onLoadingStopped(); | ||
this.emit(Events.FrameManager.LifecycleEvent, frame); | ||
this.emit(Events_1.Events.FrameManager.LifecycleEvent, frame); | ||
} | ||
/** | ||
* @param {!Protocol.Page.FrameTree} frameTree | ||
*/ | ||
_handleFrameTree(frameTree) { | ||
@@ -184,47 +138,27 @@ if (frameTree.frame.parentId) | ||
} | ||
/** | ||
* @return {!Puppeteer.Page} | ||
*/ | ||
page() { | ||
return this._page; | ||
} | ||
/** | ||
* @return {!Frame} | ||
*/ | ||
mainFrame() { | ||
return this._mainFrame; | ||
} | ||
/** | ||
* @return {!Array<!Frame>} | ||
*/ | ||
frames() { | ||
return Array.from(this._frames.values()); | ||
} | ||
/** | ||
* @param {!string} frameId | ||
* @return {?Frame} | ||
*/ | ||
frame(frameId) { | ||
return this._frames.get(frameId) || null; | ||
} | ||
/** | ||
* @param {string} frameId | ||
* @param {?string} parentFrameId | ||
*/ | ||
_onFrameAttached(frameId, parentFrameId) { | ||
if (this._frames.has(frameId)) | ||
return; | ||
assert(parentFrameId); | ||
helper_1.assert(parentFrameId); | ||
const parentFrame = this._frames.get(parentFrameId); | ||
const frame = new Frame(this, this._client, parentFrame, frameId); | ||
this._frames.set(frame._id, frame); | ||
this.emit(Events.FrameManager.FrameAttached, frame); | ||
this.emit(Events_1.Events.FrameManager.FrameAttached, frame); | ||
} | ||
/** | ||
* @param {!Protocol.Page.Frame} framePayload | ||
*/ | ||
_onFrameNavigated(framePayload) { | ||
const isMainFrame = !framePayload.parentId; | ||
let frame = isMainFrame ? this._mainFrame : this._frames.get(framePayload.id); | ||
assert(isMainFrame || frame, 'We either navigate top level or have old version of the navigated frame'); | ||
helper_1.assert(isMainFrame || frame, 'We either navigate top level or have old version of the navigated frame'); | ||
// Detach all child frames first. | ||
@@ -251,7 +185,4 @@ if (frame) { | ||
frame._navigated(framePayload); | ||
this.emit(Events.FrameManager.FrameNavigated, frame); | ||
this.emit(Events_1.Events.FrameManager.FrameNavigated, frame); | ||
} | ||
/** | ||
* @param {string} name | ||
*/ | ||
async _ensureIsolatedWorld(name) { | ||
@@ -262,3 +193,3 @@ if (this._isolatedWorlds.has(name)) | ||
await this._client.send('Page.addScriptToEvaluateOnNewDocument', { | ||
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`, | ||
source: `//# sourceURL=${ExecutionContext_1.EVALUATION_SCRIPT_URL}`, | ||
worldName: name, | ||
@@ -270,8 +201,4 @@ }), | ||
worldName: name, | ||
}).catch(debugError))); // frames might be removed before we send this | ||
}).catch(helper_1.debugError))); // frames might be removed before we send this | ||
} | ||
/** | ||
* @param {string} frameId | ||
* @param {string} url | ||
*/ | ||
_onFrameNavigatedWithinDocument(frameId, url) { | ||
@@ -282,8 +209,5 @@ const frame = this._frames.get(frameId); | ||
frame._navigatedWithinDocument(url); | ||
this.emit(Events.FrameManager.FrameNavigatedWithinDocument, frame); | ||
this.emit(Events.FrameManager.FrameNavigated, frame); | ||
this.emit(Events_1.Events.FrameManager.FrameNavigatedWithinDocument, frame); | ||
this.emit(Events_1.Events.FrameManager.FrameNavigated, frame); | ||
} | ||
/** | ||
* @param {string} frameId | ||
*/ | ||
_onFrameDetached(frameId) { | ||
@@ -295,3 +219,4 @@ const frame = this._frames.get(frameId); | ||
_onExecutionContextCreated(contextPayload) { | ||
const frameId = contextPayload.auxData ? contextPayload.auxData.frameId : null; | ||
const auxData = contextPayload.auxData; | ||
const frameId = auxData ? auxData.frameId : null; | ||
const frame = this._frames.get(frameId) || null; | ||
@@ -312,4 +237,3 @@ let world = null; | ||
this._isolatedWorlds.add(contextPayload.name); | ||
/** @type {!ExecutionContext} */ | ||
const context = new ExecutionContext(this._client, contextPayload, world); | ||
const context = new ExecutionContext_1.ExecutionContext(this._client, contextPayload, world); | ||
if (world) | ||
@@ -337,14 +261,7 @@ world._setContext(context); | ||
} | ||
/** | ||
* @param {number} contextId | ||
* @return {!ExecutionContext} | ||
*/ | ||
executionContextById(contextId) { | ||
const context = this._contextIdToContext.get(contextId); | ||
assert(context, 'INTERNAL ERROR: missing context with id = ' + contextId); | ||
helper_1.assert(context, 'INTERNAL ERROR: missing context with id = ' + contextId); | ||
return context; | ||
} | ||
/** | ||
* @param {!Frame} frame | ||
*/ | ||
_removeFramesRecursively(frame) { | ||
@@ -355,16 +272,12 @@ for (const child of frame.childFrames()) | ||
this._frames.delete(frame._id); | ||
this.emit(Events.FrameManager.FrameDetached, frame); | ||
this.emit(Events_1.Events.FrameManager.FrameDetached, frame); | ||
} | ||
} | ||
/** | ||
* @unrestricted | ||
*/ | ||
exports.FrameManager = FrameManager; | ||
class Frame { | ||
/** | ||
* @param {!FrameManager} frameManager | ||
* @param {!CDPSession} client | ||
* @param {?Frame} parentFrame | ||
* @param {string} frameId | ||
*/ | ||
constructor(frameManager, client, parentFrame, frameId) { | ||
this._url = ''; | ||
this._detached = false; | ||
this._loaderId = ''; | ||
this._lifecycleEvents = new Set(); | ||
this._frameManager = frameManager; | ||
@@ -377,9 +290,4 @@ this._client = client; | ||
this._loaderId = ''; | ||
/** @type {!Set<string>} */ | ||
this._lifecycleEvents = new Set(); | ||
/** @type {!DOMWorld} */ | ||
this._mainWorld = new DOMWorld(frameManager, this, frameManager._timeoutSettings); | ||
/** @type {!DOMWorld} */ | ||
this._secondaryWorld = new DOMWorld(frameManager, this, frameManager._timeoutSettings); | ||
/** @type {!Set<!Frame>} */ | ||
this._mainWorld = new DOMWorld_1.DOMWorld(frameManager, this, frameManager._timeoutSettings); | ||
this._secondaryWorld = new DOMWorld_1.DOMWorld(frameManager, this, frameManager._timeoutSettings); | ||
this._childFrames = new Set(); | ||
@@ -389,186 +297,81 @@ if (this._parentFrame) | ||
} | ||
/** | ||
* @param {string} url | ||
* @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async goto(url, options) { | ||
return await this._frameManager.navigateFrame(this, url, options); | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async waitForNavigation(options) { | ||
return await this._frameManager.waitForFrameNavigation(this, options); | ||
} | ||
/** | ||
* @return {!Promise<!ExecutionContext>} | ||
*/ | ||
executionContext() { | ||
return this._mainWorld.executionContext(); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
async evaluateHandle(pageFunction, ...args) { | ||
return this._mainWorld.evaluateHandle(pageFunction, ...args); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<*>} | ||
*/ | ||
async evaluate(pageFunction, ...args) { | ||
return this._mainWorld.evaluate(pageFunction, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
async $(selector) { | ||
return this._mainWorld.$(selector); | ||
} | ||
/** | ||
* @param {string} expression | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $x(expression) { | ||
return this._mainWorld.$x(expression); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $eval(selector, pageFunction, ...args) { | ||
return this._mainWorld.$eval(selector, pageFunction, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $$eval(selector, pageFunction, ...args) { | ||
return this._mainWorld.$$eval(selector, pageFunction, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $$(selector) { | ||
return this._mainWorld.$$(selector); | ||
} | ||
/** | ||
* @return {!Promise<String>} | ||
*/ | ||
async content() { | ||
return this._secondaryWorld.content(); | ||
} | ||
/** | ||
* @param {string} html | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
*/ | ||
async setContent(html, options = {}) { | ||
return this._secondaryWorld.setContent(html, options); | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
name() { | ||
return this._name || ''; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
url() { | ||
return this._url; | ||
} | ||
/** | ||
* @return {?Frame} | ||
*/ | ||
parentFrame() { | ||
return this._parentFrame; | ||
} | ||
/** | ||
* @return {!Array.<!Frame>} | ||
*/ | ||
childFrames() { | ||
return Array.from(this._childFrames); | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isDetached() { | ||
return this._detached; | ||
} | ||
/** | ||
* @param {!{url?: string, path?: string, content?: string, type?: string}} options | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async addScriptTag(options) { | ||
return this._mainWorld.addScriptTag(options); | ||
} | ||
/** | ||
* @param {!{url?: string, path?: string, content?: string}} options | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async addStyleTag(options) { | ||
return this._mainWorld.addStyleTag(options); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options | ||
*/ | ||
async click(selector, options) { | ||
return this._secondaryWorld.click(selector, options); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async focus(selector) { | ||
return this._secondaryWorld.focus(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async hover(selector) { | ||
return this._secondaryWorld.hover(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!Array<string>} values | ||
* @return {!Promise<!Array<string>>} | ||
*/ | ||
select(selector, ...values) { | ||
return this._secondaryWorld.select(selector, ...values); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
async tap(selector) { | ||
return this._secondaryWorld.tap(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {string} text | ||
* @param {{delay: (number|undefined)}=} options | ||
*/ | ||
async type(selector, text, options) { | ||
return this._mainWorld.type(selector, text, options); | ||
} | ||
/** | ||
* @param {(string|number|Function)} selectorOrFunctionOrTimeout | ||
* @param {!Object=} options | ||
* @param {!Array<*>} args | ||
* @return {!Promise<?JSHandle>} | ||
*/ | ||
waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) { | ||
const xPathPattern = '//'; | ||
if (helper.isString(selectorOrFunctionOrTimeout)) { | ||
const string = /** @type {string} */ (selectorOrFunctionOrTimeout); | ||
if (helper_1.helper.isString(selectorOrFunctionOrTimeout)) { | ||
const string = selectorOrFunctionOrTimeout; | ||
if (string.startsWith(xPathPattern)) | ||
@@ -578,4 +381,4 @@ return this.waitForXPath(string, options); | ||
} | ||
if (helper.isNumber(selectorOrFunctionOrTimeout)) | ||
return new Promise(fulfill => setTimeout(fulfill, /** @type {number} */ (selectorOrFunctionOrTimeout))); | ||
if (helper_1.helper.isNumber(selectorOrFunctionOrTimeout)) | ||
return new Promise(fulfill => setTimeout(fulfill, selectorOrFunctionOrTimeout)); | ||
if (typeof selectorOrFunctionOrTimeout === 'function') | ||
@@ -585,7 +388,2 @@ return this.waitForFunction(selectorOrFunctionOrTimeout, options, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
async waitForSelector(selector, options) { | ||
@@ -600,7 +398,2 @@ const handle = await this._secondaryWorld.waitForSelector(selector, options); | ||
} | ||
/** | ||
* @param {string} xpath | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
async waitForXPath(xpath, options) { | ||
@@ -615,35 +408,15 @@ const handle = await this._secondaryWorld.waitForXPath(xpath, options); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!{polling?: string|number, timeout?: number}=} options | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
waitForFunction(pageFunction, options = {}, ...args) { | ||
return this._mainWorld.waitForFunction(pageFunction, options, ...args); | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async title() { | ||
return this._secondaryWorld.title(); | ||
} | ||
/** | ||
* @param {!Protocol.Page.Frame} framePayload | ||
*/ | ||
_navigated(framePayload) { | ||
this._name = framePayload.name; | ||
// TODO(lushnikov): remove this once requestInterception has loaderId exposed. | ||
this._navigationURL = framePayload.url; | ||
this._url = framePayload.url; | ||
} | ||
/** | ||
* @param {string} url | ||
*/ | ||
_navigatedWithinDocument(url) { | ||
this._url = url; | ||
} | ||
/** | ||
* @param {string} loaderId | ||
* @param {string} name | ||
*/ | ||
_onLifecycleEvent(loaderId, name) { | ||
@@ -669,7 +442,7 @@ if (name === 'init') { | ||
} | ||
exports.Frame = Frame; | ||
function assertNoLegacyNavigationOptions(options) { | ||
assert(options['networkIdleTimeout'] === undefined, 'ERROR: networkIdleTimeout option is no longer supported.'); | ||
assert(options['networkIdleInflight'] === undefined, 'ERROR: networkIdleInflight option is no longer supported.'); | ||
assert(options.waitUntil !== 'networkidle', 'ERROR: "networkidle" option is no longer supported. Use "networkidle2" instead'); | ||
helper_1.assert(options['networkIdleTimeout'] === undefined, 'ERROR: networkIdleTimeout option is no longer supported.'); | ||
helper_1.assert(options['networkIdleInflight'] === undefined, 'ERROR: networkIdleInflight option is no longer supported.'); | ||
helper_1.assert(options.waitUntil !== 'networkidle', 'ERROR: "networkidle" option is no longer supported. Use "networkidle2" instead'); | ||
} | ||
module.exports = { FrameManager, Frame }; |
@@ -83,8 +83,8 @@ "use strict"; | ||
Error.captureStackTrace(syncStack); | ||
return method.call(this, ...args).catch(e => { | ||
return method.call(this, ...args).catch(error => { | ||
const stack = syncStack.stack.substring(syncStack.stack.indexOf('\n') + 1); | ||
const clientStack = stack.substring(stack.indexOf('\n')); | ||
if (e instanceof Error && e.stack && !e.stack.includes(clientStack)) | ||
e.stack += '\n -- ASYNC --\n' + stack; | ||
throw e; | ||
if (error instanceof Error && error.stack && !error.stack.includes(clientStack)) | ||
error.stack += '\n -- ASYNC --\n' + stack; | ||
throw error; | ||
}); | ||
@@ -132,5 +132,5 @@ }); | ||
return r; | ||
}, e => { | ||
}, error => { | ||
cleanup(); | ||
throw e; | ||
throw error; | ||
}); | ||
@@ -137,0 +137,0 @@ if (result instanceof Error) |
@@ -19,2 +19,3 @@ "use strict"; | ||
const helper_1 = require("./helper"); | ||
const QueryHandler_1 = require("./QueryHandler"); | ||
function createJSHandle(context, remoteObject) { | ||
@@ -101,9 +102,2 @@ const frame = context.frame(); | ||
class ElementHandle extends JSHandle { | ||
/** | ||
* @param {!ExecutionContext} context | ||
* @param {!CDPSession} client | ||
* @param {!Protocol.Runtime.RemoteObject} remoteObject | ||
* @param {!Puppeteer.Page} page | ||
* @param {!Puppeteer.FrameManager} frameManager | ||
*/ | ||
constructor(context, client, remoteObject, page, frameManager) { | ||
@@ -199,8 +193,2 @@ super(context, client, remoteObject); | ||
} | ||
/** | ||
* @param {!Array<{x: number, y: number}>} quad | ||
* @param {number} width | ||
* @param {number} height | ||
* @return {!Array<{x: number, y: number}>} | ||
*/ | ||
_intersectQuadWithViewport(quad, width, height) { | ||
@@ -222,6 +210,2 @@ return quad.map(point => ({ | ||
} | ||
/** | ||
* @param {!Array<string>} values | ||
* @return {!Promise<!Array<string>>} | ||
*/ | ||
async select(...values) { | ||
@@ -365,3 +349,5 @@ for (const value of values) | ||
async $(selector) { | ||
const handle = await this.evaluateHandle((element, selector) => element.querySelector(selector), selector); | ||
const defaultHandler = (element, selector) => element.querySelector(selector); | ||
const { updatedSelector, queryHandler } = QueryHandler_1.getQueryHandlerAndSelector(selector, defaultHandler); | ||
const handle = await this.evaluateHandle(queryHandler, updatedSelector); | ||
const element = handle.asElement(); | ||
@@ -373,8 +359,6 @@ if (element) | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $$(selector) { | ||
const arrayHandle = await this.evaluateHandle((element, selector) => element.querySelectorAll(selector), selector); | ||
const defaultHandler = (element, selector) => element.querySelectorAll(selector); | ||
const { updatedSelector, queryHandler } = QueryHandler_1.getQueryHandlerAndSelector(selector, defaultHandler); | ||
const arrayHandle = await this.evaluateHandle(queryHandler, updatedSelector); | ||
const properties = await arrayHandle.getProperties(); | ||
@@ -399,3 +383,5 @@ await arrayHandle.dispose(); | ||
async $$eval(selector, pageFunction, ...args) { | ||
const arrayHandle = await this.evaluateHandle((element, selector) => Array.from(element.querySelectorAll(selector)), selector); | ||
const defaultHandler = (element, selector) => Array.from(element.querySelectorAll(selector)); | ||
const { updatedSelector, queryHandler } = QueryHandler_1.getQueryHandlerAndSelector(selector, defaultHandler); | ||
const arrayHandle = await this.evaluateHandle(queryHandler, updatedSelector); | ||
const result = await arrayHandle.evaluate(pageFunction, ...args); | ||
@@ -402,0 +388,0 @@ await arrayHandle.dispose(); |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
@@ -16,32 +18,25 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const os = require('os'); | ||
const path = require('path'); | ||
const http = require('http'); | ||
const https = require('https'); | ||
const URL = require('url'); | ||
const removeFolder = require('rimraf'); | ||
const childProcess = require('child_process'); | ||
const { BrowserFetcher } = require('./BrowserFetcher'); | ||
const { Connection } = require('./Connection'); | ||
const { Browser } = require('./Browser'); | ||
const readline = require('readline'); | ||
const fs = require('fs'); | ||
const { helper, assert, debugError } = require('./helper'); | ||
const debugLauncher = require('debug')(`puppeteer:launcher`); | ||
const { TimeoutError } = require('./Errors'); | ||
const { WebSocketTransport } = require('./WebSocketTransport'); | ||
const { PipeTransport } = require('./PipeTransport'); | ||
const mkdtempAsync = helper.promisify(fs.mkdtemp); | ||
const removeFolderAsync = helper.promisify(removeFolder); | ||
const writeFileAsync = helper.promisify(fs.writeFile); | ||
const os = require("os"); | ||
const path = require("path"); | ||
const http = require("http"); | ||
const https = require("https"); | ||
const URL = require("url"); | ||
const fs = require("fs"); | ||
const readline = require("readline"); | ||
const debug = require("debug"); | ||
const removeFolder = require("rimraf"); | ||
const childProcess = require("child_process"); | ||
const BrowserFetcher_1 = require("./BrowserFetcher"); | ||
const Connection_1 = require("./Connection"); | ||
const Browser_1 = require("./Browser"); | ||
const helper_1 = require("./helper"); | ||
const Errors_1 = require("./Errors"); | ||
const WebSocketTransport_1 = require("./WebSocketTransport"); | ||
const PipeTransport_1 = require("./PipeTransport"); | ||
const mkdtempAsync = helper_1.helper.promisify(fs.mkdtemp); | ||
const removeFolderAsync = helper_1.helper.promisify(removeFolder); | ||
const writeFileAsync = helper_1.helper.promisify(fs.writeFile); | ||
const debugLauncher = debug('puppeteer:launcher'); | ||
class BrowserRunner { | ||
/** | ||
* @param {string} executablePath | ||
* @param {!Array<string>} processArguments | ||
* @param {string=} tempDirectory | ||
*/ | ||
constructor(executablePath, processArguments, tempDirectory) { | ||
this._executablePath = executablePath; | ||
this._processArguments = processArguments; | ||
this._tempDirectory = tempDirectory; | ||
this.proc = null; | ||
@@ -51,9 +46,8 @@ this.connection = null; | ||
this._listeners = []; | ||
this._executablePath = executablePath; | ||
this._processArguments = processArguments; | ||
this._tempDirectory = tempDirectory; | ||
} | ||
/** | ||
* @param {!(Launcher.LaunchOptions)=} options | ||
*/ | ||
start(options = {}) { | ||
const { handleSIGINT, handleSIGTERM, handleSIGHUP, dumpio, env, pipe } = options; | ||
/** @type {!Array<"ignore"|"pipe">} */ | ||
let stdio = ['pipe', 'pipe', 'pipe']; | ||
@@ -66,3 +60,3 @@ if (pipe) { | ||
} | ||
assert(!this.proc, 'This process has previously been started.'); | ||
helper_1.assert(!this.proc, 'This process has previously been started.'); | ||
debugLauncher(`Calling ${this._executablePath} ${this._processArguments.join(' ')}`); | ||
@@ -82,3 +76,3 @@ this.proc = childProcess.spawn(this._executablePath, this._processArguments, { | ||
this._closed = false; | ||
this._processClosing = new Promise((fulfill, reject) => { | ||
this._processClosing = new Promise(fulfill => { | ||
this.proc.once('exit', () => { | ||
@@ -90,3 +84,3 @@ this._closed = true; | ||
.then(() => fulfill()) | ||
.catch(err => console.error(err)); | ||
.catch(error => console.error(error)); | ||
} | ||
@@ -98,17 +92,14 @@ else { | ||
}); | ||
this._listeners = [helper.addEventListener(process, 'exit', this.kill.bind(this))]; | ||
this._listeners = [helper_1.helper.addEventListener(process, 'exit', this.kill.bind(this))]; | ||
if (handleSIGINT) | ||
this._listeners.push(helper.addEventListener(process, 'SIGINT', () => { this.kill(); process.exit(130); })); | ||
this._listeners.push(helper_1.helper.addEventListener(process, 'SIGINT', () => { this.kill(); process.exit(130); })); | ||
if (handleSIGTERM) | ||
this._listeners.push(helper.addEventListener(process, 'SIGTERM', this.close.bind(this))); | ||
this._listeners.push(helper_1.helper.addEventListener(process, 'SIGTERM', this.close.bind(this))); | ||
if (handleSIGHUP) | ||
this._listeners.push(helper.addEventListener(process, 'SIGHUP', this.close.bind(this))); | ||
this._listeners.push(helper_1.helper.addEventListener(process, 'SIGHUP', this.close.bind(this))); | ||
} | ||
/** | ||
* @return {Promise} | ||
*/ | ||
close() { | ||
if (this._closed) | ||
return Promise.resolve(); | ||
helper.removeEventListeners(this._listeners); | ||
helper_1.helper.removeEventListeners(this._listeners); | ||
if (this._tempDirectory) { | ||
@@ -120,3 +111,3 @@ this.kill(); | ||
this.connection.send('Browser.close').catch(error => { | ||
debugError(error); | ||
helper_1.debugError(error); | ||
this.kill(); | ||
@@ -127,5 +118,4 @@ }); | ||
} | ||
// This function has to be sync to be used as 'exit' event handler. | ||
kill() { | ||
helper.removeEventListeners(this._listeners); | ||
helper_1.helper.removeEventListeners(this._listeners); | ||
if (this.proc && this.proc.pid && !this.proc.killed && !this._closed) { | ||
@@ -157,10 +147,10 @@ try { | ||
const browserWSEndpoint = await waitForWSEndpoint(this.proc, timeout, preferredRevision); | ||
const transport = await WebSocketTransport.create(browserWSEndpoint); | ||
this.connection = new Connection(browserWSEndpoint, transport, slowMo); | ||
const transport = await WebSocketTransport_1.WebSocketTransport.create(browserWSEndpoint); | ||
this.connection = new Connection_1.Connection(browserWSEndpoint, transport, slowMo); | ||
} | ||
else { | ||
// stdio was assigned during start(), and the 'pipe' option there adds the 4th and 5th items to stdio array | ||
const { 3: pipeWrite, 4: pipeRead } = /** @type {!Array<any>} */ (this.proc.stdio); | ||
const transport = new PipeTransport(/** @type {!NodeJS.WritableStream} */ pipeWrite, /** @type {!NodeJS.ReadableStream} */ pipeRead); | ||
this.connection = new Connection('', transport, slowMo); | ||
const { 3: pipeWrite, 4: pipeRead } = this.proc.stdio; | ||
const transport = new PipeTransport_1.PipeTransport(pipeWrite, pipeRead); | ||
this.connection = new Connection_1.Connection('', transport, slowMo); | ||
} | ||
@@ -170,11 +160,3 @@ return this.connection; | ||
} | ||
/** | ||
* @implements {!Puppeteer.ProductLauncher} | ||
*/ | ||
class ChromeLauncher { | ||
/** | ||
* @param {string} projectRoot | ||
* @param {string} preferredRevision | ||
* @param {boolean} isPuppeteerCore | ||
*/ | ||
constructor(projectRoot, preferredRevision, isPuppeteerCore) { | ||
@@ -185,6 +167,2 @@ this._projectRoot = projectRoot; | ||
} | ||
/** | ||
* @param {!(Launcher.LaunchOptions & Launcher.ChromeArgOptions & Launcher.BrowserOptions)=} options | ||
* @return {!Promise<!Browser>} | ||
*/ | ||
async launch(options = {}) { | ||
@@ -219,3 +197,3 @@ const { ignoreDefaultArgs = false, args = [], dumpio = false, executablePath = null, pipe = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, slowMo = 0, timeout = 30000 } = options; | ||
const connection = await runner.setupConnection({ usePipe, timeout, slowMo, preferredRevision: this._preferredRevision }); | ||
const browser = await Browser.create(connection, [], ignoreHTTPSErrors, defaultViewport, runner.proc, runner.close.bind(runner)); | ||
const browser = await Browser_1.Browser.create(connection, [], ignoreHTTPSErrors, defaultViewport, runner.proc, runner.close.bind(runner)); | ||
await browser.waitForTarget(t => t.type() === 'page'); | ||
@@ -272,47 +250,29 @@ return browser; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
executablePath() { | ||
return resolveExecutablePath(this).executablePath; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
get product() { | ||
return 'chrome'; | ||
} | ||
/** | ||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserURL?: string, transport?: !Puppeteer.ConnectionTransport})} options | ||
* @return {!Promise<!Browser>} | ||
*/ | ||
async connect(options) { | ||
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options; | ||
assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'); | ||
helper_1.assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'); | ||
let connection = null; | ||
if (transport) { | ||
connection = new Connection('', transport, slowMo); | ||
connection = new Connection_1.Connection('', transport, slowMo); | ||
} | ||
else if (browserWSEndpoint) { | ||
const connectionTransport = await WebSocketTransport.create(browserWSEndpoint); | ||
connection = new Connection(browserWSEndpoint, connectionTransport, slowMo); | ||
const connectionTransport = await WebSocketTransport_1.WebSocketTransport.create(browserWSEndpoint); | ||
connection = new Connection_1.Connection(browserWSEndpoint, connectionTransport, slowMo); | ||
} | ||
else if (browserURL) { | ||
const connectionURL = await getWSEndpoint(browserURL); | ||
const connectionTransport = await WebSocketTransport.create(connectionURL); | ||
connection = new Connection(connectionURL, connectionTransport, slowMo); | ||
const connectionTransport = await WebSocketTransport_1.WebSocketTransport.create(connectionURL); | ||
connection = new Connection_1.Connection(connectionURL, connectionTransport, slowMo); | ||
} | ||
const { browserContextIds } = await connection.send('Target.getBrowserContexts'); | ||
return Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(debugError)); | ||
return Browser_1.Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(helper_1.debugError)); | ||
} | ||
} | ||
/** | ||
* @implements {!Puppeteer.ProductLauncher} | ||
*/ | ||
class FirefoxLauncher { | ||
/** | ||
* @param {string} projectRoot | ||
* @param {string} preferredRevision | ||
* @param {boolean} isPuppeteerCore | ||
*/ | ||
constructor(projectRoot, preferredRevision, isPuppeteerCore) { | ||
@@ -323,6 +283,2 @@ this._projectRoot = projectRoot; | ||
} | ||
/** | ||
* @param {!(Launcher.LaunchOptions & Launcher.ChromeArgOptions & Launcher.BrowserOptions & {extraPrefsFirefox?: !object})=} options | ||
* @return {!Promise<!Browser>} | ||
*/ | ||
async launch(options = {}) { | ||
@@ -357,3 +313,3 @@ const { ignoreDefaultArgs = false, args = [], dumpio = false, executablePath = null, pipe = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, slowMo = 0, timeout = 30000, extraPrefsFirefox = {} } = options; | ||
const connection = await runner.setupConnection({ usePipe: pipe, timeout, slowMo, preferredRevision: this._preferredRevision }); | ||
const browser = await Browser.create(connection, [], ignoreHTTPSErrors, defaultViewport, runner.proc, runner.close.bind(runner)); | ||
const browser = await Browser_1.Browser.create(connection, [], ignoreHTTPSErrors, defaultViewport, runner.proc, runner.close.bind(runner)); | ||
await browser.waitForTarget(t => t.type() === 'page'); | ||
@@ -367,28 +323,21 @@ return browser; | ||
} | ||
/** | ||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserURL?: string, transport?: !Puppeteer.ConnectionTransport})} options | ||
* @return {!Promise<!Browser>} | ||
*/ | ||
async connect(options) { | ||
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options; | ||
assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'); | ||
helper_1.assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'); | ||
let connection = null; | ||
if (transport) { | ||
connection = new Connection('', transport, slowMo); | ||
connection = new Connection_1.Connection('', transport, slowMo); | ||
} | ||
else if (browserWSEndpoint) { | ||
const connectionTransport = await WebSocketTransport.create(browserWSEndpoint); | ||
connection = new Connection(browserWSEndpoint, connectionTransport, slowMo); | ||
const connectionTransport = await WebSocketTransport_1.WebSocketTransport.create(browserWSEndpoint); | ||
connection = new Connection_1.Connection(browserWSEndpoint, connectionTransport, slowMo); | ||
} | ||
else if (browserURL) { | ||
const connectionURL = await getWSEndpoint(browserURL); | ||
const connectionTransport = await WebSocketTransport.create(connectionURL); | ||
connection = new Connection(connectionURL, connectionTransport, slowMo); | ||
const connectionTransport = await WebSocketTransport_1.WebSocketTransport.create(connectionURL); | ||
connection = new Connection_1.Connection(connectionURL, connectionTransport, slowMo); | ||
} | ||
const { browserContextIds } = await connection.send('Target.getBrowserContexts'); | ||
return Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(debugError)); | ||
return Browser_1.Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(helper_1.debugError)); | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
executablePath() { | ||
@@ -400,3 +349,3 @@ return resolveExecutablePath(this).executablePath; | ||
if (this._preferredRevision === 'latest') { | ||
const browserFetcher = new BrowserFetcher(this._projectRoot, { product: this.product }); | ||
const browserFetcher = new BrowserFetcher_1.BrowserFetcher(this._projectRoot, { product: this.product }); | ||
const localRevisions = await browserFetcher.localRevisions(); | ||
@@ -407,12 +356,5 @@ if (localRevisions[0]) | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
get product() { | ||
return 'firefox'; | ||
} | ||
/** | ||
* @param {!Launcher.ChromeArgOptions=} options | ||
* @return {!Array<string>} | ||
*/ | ||
defaultArgs(options = {}) { | ||
@@ -437,6 +379,2 @@ const firefoxArguments = [ | ||
} | ||
/** | ||
* @param {!Object=} extraPrefs | ||
* @return {!Promise<string>} | ||
*/ | ||
async _createProfile(extraPrefs) { | ||
@@ -612,8 +550,2 @@ const profilePath = await mkdtempAsync(path.join(os.tmpdir(), 'puppeteer_dev_firefox_profile-')); | ||
} | ||
/** | ||
* @param {!Puppeteer.ChildProcess} browserProcess | ||
* @param {number} timeout | ||
* @param {string} preferredRevision | ||
* @return {!Promise<string>} | ||
*/ | ||
function waitForWSEndpoint(browserProcess, timeout, preferredRevision) { | ||
@@ -624,6 +556,6 @@ return new Promise((resolve, reject) => { | ||
const listeners = [ | ||
helper.addEventListener(rl, 'line', onLine), | ||
helper.addEventListener(rl, 'close', () => onClose()), | ||
helper.addEventListener(browserProcess, 'exit', () => onClose()), | ||
helper.addEventListener(browserProcess, 'error', error => onClose(error)) | ||
helper_1.helper.addEventListener(rl, 'line', onLine), | ||
helper_1.helper.addEventListener(rl, 'close', () => onClose()), | ||
helper_1.helper.addEventListener(browserProcess, 'exit', () => onClose()), | ||
helper_1.helper.addEventListener(browserProcess, 'error', error => onClose(error)) | ||
]; | ||
@@ -646,7 +578,4 @@ const timeoutId = timeout ? setTimeout(onTimeout, timeout) : 0; | ||
cleanup(); | ||
reject(new TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Only Chrome at revision r${preferredRevision} is guaranteed to work.`)); | ||
reject(new Errors_1.TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Only Chrome at revision r${preferredRevision} is guaranteed to work.`)); | ||
} | ||
/** | ||
* @param {string} line | ||
*/ | ||
function onLine(line) { | ||
@@ -663,10 +592,6 @@ stderr += line + '\n'; | ||
clearTimeout(timeoutId); | ||
helper.removeEventListeners(listeners); | ||
helper_1.helper.removeEventListeners(listeners); | ||
} | ||
}); | ||
} | ||
/** | ||
* @param {string} browserURL | ||
* @return {!Promise<string>} | ||
*/ | ||
function getWSEndpoint(browserURL) { | ||
@@ -692,12 +617,7 @@ let resolve, reject; | ||
request.end(); | ||
return promise.catch(e => { | ||
e.message = `Failed to fetch browser webSocket url from ${endpointURL}: ` + e.message; | ||
throw e; | ||
return promise.catch(error => { | ||
error.message = `Failed to fetch browser webSocket url from ${endpointURL}: ` + error.message; | ||
throw error; | ||
}); | ||
} | ||
/** | ||
* @param {ChromeLauncher|FirefoxLauncher} launcher | ||
* | ||
* @return {{executablePath: string, missingText: ?string}} | ||
*/ | ||
function resolveExecutablePath(launcher) { | ||
@@ -712,3 +632,3 @@ // puppeteer-core doesn't take into account PUPPETEER_* env variables. | ||
} | ||
const browserFetcher = new BrowserFetcher(launcher._projectRoot, { product: launcher.product }); | ||
const browserFetcher = new BrowserFetcher_1.BrowserFetcher(launcher._projectRoot, { product: launcher.product }); | ||
if (!launcher._isPuppeteerCore && launcher.product === 'chrome') { | ||
@@ -726,9 +646,2 @@ const revision = process.env['PUPPETEER_CHROMIUM_REVISION']; | ||
} | ||
/** | ||
* @param {string} projectRoot | ||
* @param {string} preferredRevision | ||
* @param {boolean} isPuppeteerCore | ||
* @param {string=} product | ||
* @return {!Puppeteer.ProductLauncher} | ||
*/ | ||
function Launcher(projectRoot, preferredRevision, isPuppeteerCore, product) { | ||
@@ -746,27 +659,2 @@ // puppeteer-core doesn't take into account PUPPETEER_* env variables. | ||
} | ||
/** | ||
* @typedef {Object} Launcher.ChromeArgOptions | ||
* @property {boolean=} headless | ||
* @property {Array<string>=} args | ||
* @property {string=} userDataDir | ||
* @property {boolean=} devtools | ||
*/ | ||
/** | ||
* @typedef {Object} Launcher.LaunchOptions | ||
* @property {string=} executablePath | ||
* @property {boolean|Array<string>=} ignoreDefaultArgs | ||
* @property {boolean=} handleSIGINT | ||
* @property {boolean=} handleSIGTERM | ||
* @property {boolean=} handleSIGHUP | ||
* @property {number=} timeout | ||
* @property {boolean=} dumpio | ||
* @property {!Object<string, string | undefined>=} env | ||
* @property {boolean=} pipe | ||
*/ | ||
/** | ||
* @typedef {Object} Launcher.BrowserOptions | ||
* @property {boolean=} ignoreHTTPSErrors | ||
* @property {(?Puppeteer.Viewport)=} defaultViewport | ||
* @property {number=} slowMo | ||
*/ | ||
module.exports = Launcher; | ||
exports.default = Launcher; |
@@ -42,3 +42,2 @@ "use strict"; | ||
this._timeout = timeout; | ||
/** @type {?Puppeteer.Request} */ | ||
this._navigationRequest = null; | ||
@@ -122,3 +121,3 @@ this._eventListeners = [ | ||
/** | ||
* @param {!Puppeteer.Frame} frame | ||
* @param {!Frame} frame | ||
* @param {!Array<string>} expectedLifecycle | ||
@@ -125,0 +124,0 @@ * @return {boolean} |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
@@ -16,28 +18,13 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const EventEmitter = require('events'); | ||
const { helper, assert, debugError } = require('./helper'); | ||
const { Events } = require('./Events'); | ||
// CDPSession is used only as a typedef | ||
// eslint-disable-next-line no-unused-vars | ||
const { CDPSession } = require('./Connection'); | ||
const EventEmitter = require("events"); | ||
const helper_1 = require("./helper"); | ||
const Events_1 = require("./Events"); | ||
class NetworkManager extends EventEmitter { | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {!Puppeteer.FrameManager} frameManager | ||
*/ | ||
constructor(client, ignoreHTTPSErrors, frameManager) { | ||
super(); | ||
this._client = client; | ||
this._ignoreHTTPSErrors = ignoreHTTPSErrors; | ||
this._frameManager = frameManager; | ||
/** @type {!Map<string, !Request>} */ | ||
this._requestIdToRequest = new Map(); | ||
/** @type {!Map<string, !Protocol.Network.requestWillBeSentPayload>} */ | ||
this._requestIdToRequestWillBeSentEvent = new Map(); | ||
/** @type {!Object<string, string>} */ | ||
this._extraHTTPHeaders = {}; | ||
this._offline = false; | ||
/** @type {?{username: string, password: string}} */ | ||
this._credentials = null; | ||
/** @type {!Set<string>} */ | ||
this._attemptedAuthentications = new Set(); | ||
@@ -47,4 +34,6 @@ this._userRequestInterceptionEnabled = false; | ||
this._userCacheDisabled = false; | ||
/** @type {!Map<string, string>} */ | ||
this._requestIdToInterceptionId = new Map(); | ||
this._client = client; | ||
this._ignoreHTTPSErrors = ignoreHTTPSErrors; | ||
this._frameManager = frameManager; | ||
this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this)); | ||
@@ -63,5 +52,2 @@ this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this)); | ||
} | ||
/** | ||
* @param {?{username: string, password: string}} credentials | ||
*/ | ||
async authenticate(credentials) { | ||
@@ -71,5 +57,2 @@ this._credentials = credentials; | ||
} | ||
/** | ||
* @param {!Object<string, string>} extraHTTPHeaders | ||
*/ | ||
async setExtraHTTPHeaders(extraHTTPHeaders) { | ||
@@ -79,3 +62,3 @@ this._extraHTTPHeaders = {}; | ||
const value = extraHTTPHeaders[key]; | ||
assert(helper.isString(value), `Expected value of header "${key}" to be String, but "${typeof value}" is found.`); | ||
helper_1.assert(helper_1.helper.isString(value), `Expected value of header "${key}" to be String, but "${typeof value}" is found.`); | ||
this._extraHTTPHeaders[key.toLowerCase()] = value; | ||
@@ -85,11 +68,5 @@ } | ||
} | ||
/** | ||
* @return {!Object<string, string>} | ||
*/ | ||
extraHTTPHeaders() { | ||
return Object.assign({}, this._extraHTTPHeaders); | ||
} | ||
/** | ||
* @param {boolean} value | ||
*/ | ||
async setOfflineMode(value) { | ||
@@ -107,11 +84,5 @@ if (this._offline === value) | ||
} | ||
/** | ||
* @param {string} userAgent | ||
*/ | ||
async setUserAgent(userAgent) { | ||
await this._client.send('Network.setUserAgentOverride', { userAgent }); | ||
} | ||
/** | ||
* @param {boolean} enabled | ||
*/ | ||
async setCacheEnabled(enabled) { | ||
@@ -121,5 +92,2 @@ this._userCacheDisabled = !enabled; | ||
} | ||
/** | ||
* @param {boolean} value | ||
*/ | ||
async setRequestInterception(value) { | ||
@@ -155,5 +123,2 @@ this._userRequestInterceptionEnabled = value; | ||
} | ||
/** | ||
* @param {!Protocol.Network.requestWillBeSentPayload} event | ||
*/ | ||
_onRequestWillBeSent(event) { | ||
@@ -179,3 +144,2 @@ // Request interception doesn't happen for data URLs with Network Service. | ||
_onAuthRequired(event) { | ||
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */ | ||
let response = 'Default'; | ||
@@ -193,7 +157,4 @@ if (this._attemptedAuthentications.has(event.requestId)) { | ||
authChallengeResponse: { response, username, password }, | ||
}).catch(debugError); | ||
}).catch(helper_1.debugError); | ||
} | ||
/** | ||
* @param {!Protocol.Fetch.requestPausedPayload} event | ||
*/ | ||
_onRequestPaused(event) { | ||
@@ -203,3 +164,3 @@ if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) { | ||
requestId: event.requestId | ||
}).catch(debugError); | ||
}).catch(helper_1.debugError); | ||
} | ||
@@ -217,6 +178,2 @@ const requestId = event.networkId; | ||
} | ||
/** | ||
* @param {!Protocol.Network.requestWillBeSentPayload} event | ||
* @param {?string} interceptionId | ||
*/ | ||
_onRequest(event, interceptionId) { | ||
@@ -235,7 +192,4 @@ let redirectChain = []; | ||
this._requestIdToRequest.set(event.requestId, request); | ||
this.emit(Events.NetworkManager.Request, request); | ||
this.emit(Events_1.Events.NetworkManager.Request, request); | ||
} | ||
/** | ||
* @param {!Protocol.Network.requestServedFromCachePayload} event | ||
*/ | ||
_onRequestServedFromCache(event) { | ||
@@ -246,6 +200,2 @@ const request = this._requestIdToRequest.get(event.requestId); | ||
} | ||
/** | ||
* @param {!Request} request | ||
* @param {!Protocol.Network.Response} responsePayload | ||
*/ | ||
_handleRequestRedirect(request, responsePayload) { | ||
@@ -258,8 +208,5 @@ const response = new Response(this._client, request, responsePayload); | ||
this._attemptedAuthentications.delete(request._interceptionId); | ||
this.emit(Events.NetworkManager.Response, response); | ||
this.emit(Events.NetworkManager.RequestFinished, request); | ||
this.emit(Events_1.Events.NetworkManager.Response, response); | ||
this.emit(Events_1.Events.NetworkManager.RequestFinished, request); | ||
} | ||
/** | ||
* @param {!Protocol.Network.responseReceivedPayload} event | ||
*/ | ||
_onResponseReceived(event) { | ||
@@ -272,7 +219,4 @@ const request = this._requestIdToRequest.get(event.requestId); | ||
request._response = response; | ||
this.emit(Events.NetworkManager.Response, response); | ||
this.emit(Events_1.Events.NetworkManager.Response, response); | ||
} | ||
/** | ||
* @param {!Protocol.Network.loadingFinishedPayload} event | ||
*/ | ||
_onLoadingFinished(event) { | ||
@@ -290,7 +234,4 @@ const request = this._requestIdToRequest.get(event.requestId); | ||
this._attemptedAuthentications.delete(request._interceptionId); | ||
this.emit(Events.NetworkManager.RequestFinished, request); | ||
this.emit(Events_1.Events.NetworkManager.RequestFinished, request); | ||
} | ||
/** | ||
* @param {!Protocol.Network.loadingFailedPayload} event | ||
*/ | ||
_onLoadingFailed(event) { | ||
@@ -308,15 +249,13 @@ const request = this._requestIdToRequest.get(event.requestId); | ||
this._attemptedAuthentications.delete(request._interceptionId); | ||
this.emit(Events.NetworkManager.RequestFailed, request); | ||
this.emit(Events_1.Events.NetworkManager.RequestFailed, request); | ||
} | ||
} | ||
exports.NetworkManager = NetworkManager; | ||
class Request { | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {?Puppeteer.Frame} frame | ||
* @param {string} interceptionId | ||
* @param {boolean} allowInterception | ||
* @param {!Protocol.Network.requestWillBeSentPayload} event | ||
* @param {!Array<!Request>} redirectChain | ||
*/ | ||
constructor(client, frame, interceptionId, allowInterception, event, redirectChain) { | ||
this._interceptionHandled = false; | ||
this._response = null; | ||
this._failureText = null; | ||
this._headers = {}; | ||
this._fromMemoryCache = false; | ||
this._client = client; | ||
@@ -327,5 +266,2 @@ this._requestId = event.requestId; | ||
this._allowInterception = allowInterception; | ||
this._interceptionHandled = false; | ||
this._response = null; | ||
this._failureText = null; | ||
this._url = event.request.url; | ||
@@ -335,3 +271,2 @@ this._resourceType = event.type.toLowerCase(); | ||
this._postData = event.request.postData; | ||
this._headers = {}; | ||
this._frame = frame; | ||
@@ -341,55 +276,27 @@ this._redirectChain = redirectChain; | ||
this._headers[key.toLowerCase()] = event.request.headers[key]; | ||
this._fromMemoryCache = false; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
url() { | ||
return this._url; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
resourceType() { | ||
return this._resourceType; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
method() { | ||
return this._method; | ||
} | ||
/** | ||
* @return {string|undefined} | ||
*/ | ||
postData() { | ||
return this._postData; | ||
} | ||
/** | ||
* @return {!Object} | ||
*/ | ||
headers() { | ||
return this._headers; | ||
} | ||
/** | ||
* @return {?Response} | ||
*/ | ||
response() { | ||
return this._response; | ||
} | ||
/** | ||
* @return {?Puppeteer.Frame} | ||
*/ | ||
frame() { | ||
return this._frame; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isNavigationRequest() { | ||
return this._isNavigationRequest; | ||
} | ||
/** | ||
* @return {!Array<!Request>} | ||
*/ | ||
redirectChain() { | ||
@@ -408,5 +315,2 @@ return this._redirectChain.slice(); | ||
} | ||
/** | ||
* @param {!{url?: string, method?:string, postData?: string, headers?: !Object}} overrides | ||
*/ | ||
async continue(overrides = {}) { | ||
@@ -416,4 +320,4 @@ // Request interception is not supported for data: urls. | ||
return; | ||
assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
assert(!this._interceptionHandled, 'Request is already handled!'); | ||
helper_1.assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
helper_1.assert(!this._interceptionHandled, 'Request is already handled!'); | ||
const { url, method, postData, headers } = overrides; | ||
@@ -430,8 +334,5 @@ this._interceptionHandled = true; | ||
// or the page was closed. We should tolerate these errors. | ||
debugError(error); | ||
helper_1.debugError(error); | ||
}); | ||
} | ||
/** | ||
* @param {!{status: number, headers: Object, contentType: string, body: (string|Buffer)}} response | ||
*/ | ||
async respond(response) { | ||
@@ -441,7 +342,6 @@ // Mocking responses for dataURL requests is not currently supported. | ||
return; | ||
assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
assert(!this._interceptionHandled, 'Request is already handled!'); | ||
helper_1.assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
helper_1.assert(!this._interceptionHandled, 'Request is already handled!'); | ||
this._interceptionHandled = true; | ||
const responseBody = response.body && helper.isString(response.body) ? Buffer.from(/** @type {string} */ (response.body)) : /** @type {?Buffer} */ (response.body || null); | ||
/** @type {!Object<string, string>} */ | ||
const responseBody = response.body && helper_1.helper.isString(response.body) ? Buffer.from(response.body) : response.body || null; | ||
const responseHeaders = {}; | ||
@@ -465,8 +365,5 @@ if (response.headers) { | ||
// or the page was closed. We should tolerate these errors. | ||
debugError(error); | ||
helper_1.debugError(error); | ||
}); | ||
} | ||
/** | ||
* @param {string=} errorCode | ||
*/ | ||
async abort(errorCode = 'failed') { | ||
@@ -477,5 +374,5 @@ // Request interception is not supported for data: urls. | ||
const errorReason = errorReasons[errorCode]; | ||
assert(errorReason, 'Unknown error code: ' + errorCode); | ||
assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
assert(!this._interceptionHandled, 'Request is already handled!'); | ||
helper_1.assert(errorReason, 'Unknown error code: ' + errorCode); | ||
helper_1.assert(this._allowInterception, 'Request Interception is not enabled!'); | ||
helper_1.assert(!this._interceptionHandled, 'Request is already handled!'); | ||
this._interceptionHandled = true; | ||
@@ -488,6 +385,7 @@ await this._client.send('Fetch.failRequest', { | ||
// or the page was closed. We should tolerate these errors. | ||
debugError(error); | ||
helper_1.debugError(error); | ||
}); | ||
} | ||
} | ||
exports.Request = Request; | ||
const errorReasons = { | ||
@@ -510,11 +408,7 @@ 'aborted': 'Aborted', | ||
class Response { | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {!Request} request | ||
* @param {!Protocol.Network.Response} responsePayload | ||
*/ | ||
constructor(client, request, responsePayload) { | ||
this._contentPromise = null; | ||
this._headers = {}; | ||
this._client = client; | ||
this._request = request; | ||
this._contentPromise = null; | ||
this._bodyLoadedPromise = new Promise(fulfill => { | ||
@@ -532,3 +426,2 @@ this._bodyLoadedPromiseFulfill = fulfill; | ||
this._fromServiceWorker = !!responsePayload.fromServiceWorker; | ||
this._headers = {}; | ||
for (const key of Object.keys(responsePayload.headers)) | ||
@@ -538,47 +431,23 @@ this._headers[key.toLowerCase()] = responsePayload.headers[key]; | ||
} | ||
/** | ||
* @return {{ip: string, port: number}} | ||
*/ | ||
remoteAddress() { | ||
return this._remoteAddress; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
url() { | ||
return this._url; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
ok() { | ||
return this._status === 0 || (this._status >= 200 && this._status <= 299); | ||
} | ||
/** | ||
* @return {number} | ||
*/ | ||
status() { | ||
return this._status; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
statusText() { | ||
return this._statusText; | ||
} | ||
/** | ||
* @return {!Object} | ||
*/ | ||
headers() { | ||
return this._headers; | ||
} | ||
/** | ||
* @return {?SecurityDetails} | ||
*/ | ||
securityDetails() { | ||
return this._securityDetails; | ||
} | ||
/** | ||
* @return {!Promise<!Buffer>} | ||
*/ | ||
buffer() { | ||
@@ -597,5 +466,2 @@ if (!this._contentPromise) { | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async text() { | ||
@@ -605,5 +471,2 @@ const content = await this.buffer(); | ||
} | ||
/** | ||
* @return {!Promise<!Object>} | ||
*/ | ||
async json() { | ||
@@ -613,23 +476,11 @@ const content = await this.text(); | ||
} | ||
/** | ||
* @return {!Request} | ||
*/ | ||
request() { | ||
return this._request; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
fromCache() { | ||
return this._fromDiskCache || this._request._fromMemoryCache; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
fromServiceWorker() { | ||
return this._fromServiceWorker; | ||
} | ||
/** | ||
* @return {?Puppeteer.Frame} | ||
*/ | ||
frame() { | ||
@@ -639,40 +490,23 @@ return this._request.frame(); | ||
} | ||
exports.Response = Response; | ||
class SecurityDetails { | ||
/** | ||
* @param {!Protocol.Network.SecurityDetails} securityPayload | ||
*/ | ||
constructor(securityPayload) { | ||
this._subjectName = securityPayload['subjectName']; | ||
this._issuer = securityPayload['issuer']; | ||
this._validFrom = securityPayload['validFrom']; | ||
this._validTo = securityPayload['validTo']; | ||
this._protocol = securityPayload['protocol']; | ||
this._subjectName = securityPayload.subjectName; | ||
this._issuer = securityPayload.issuer; | ||
this._validFrom = securityPayload.validFrom; | ||
this._validTo = securityPayload.validTo; | ||
this._protocol = securityPayload.protocol; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
subjectName() { | ||
return this._subjectName; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
issuer() { | ||
return this._issuer; | ||
} | ||
/** | ||
* @return {number} | ||
*/ | ||
validFrom() { | ||
return this._validFrom; | ||
} | ||
/** | ||
* @return {number} | ||
*/ | ||
validTo() { | ||
return this._validTo; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
protocol() { | ||
@@ -682,6 +516,3 @@ return this._protocol; | ||
} | ||
/** | ||
* @param {Object<string, string>} headers | ||
* @return {!Array<{name: string, value: string}>} | ||
*/ | ||
exports.SecurityDetails = SecurityDetails; | ||
function headersArray(headers) { | ||
@@ -761,2 +592,1 @@ const result = []; | ||
}; | ||
module.exports = { Request, Response, NetworkManager, SecurityDetails }; |
732
lib/Page.js
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
/** | ||
@@ -16,72 +17,55 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const fs = require('fs'); | ||
const EventEmitter = require('events'); | ||
const mime = require('mime'); | ||
const { Events } = require('./Events'); | ||
// CDPSession is used only as a typedef | ||
// eslint-disable-next-line no-unused-vars | ||
const { Connection, CDPSession } = require('./Connection'); | ||
const { Dialog } = require('./Dialog'); | ||
const { EmulationManager } = require('./EmulationManager'); | ||
const { FrameManager } = require('./FrameManager'); | ||
const { Keyboard, Mouse, Touchscreen } = require('./Input'); | ||
const { Tracing } = require('./Tracing'); | ||
const { helper, debugError, assert } = require('./helper'); | ||
const { Coverage } = require('./Coverage'); | ||
const { Worker: PuppeteerWorker } = require('./Worker'); | ||
// Import used as typedef | ||
// eslint-disable-next-line no-unused-vars | ||
const { createJSHandle, JSHandle, ElementHandle } = require('./JSHandle'); | ||
const { Accessibility } = require('./Accessibility'); | ||
const { TimeoutSettings } = require('./TimeoutSettings'); | ||
// This import is used as a TypeDef, but ESLint's rule doesn't | ||
// understand that unfortunately. | ||
// eslint-disable-next-line no-unused-vars | ||
const { TaskQueue } = require('./TaskQueue'); | ||
const writeFileAsync = helper.promisify(fs.writeFile); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs = require("fs"); | ||
const EventEmitter = require("events"); | ||
const mime = require("mime"); | ||
const Events_1 = require("./Events"); | ||
const Connection_1 = require("./Connection"); | ||
const Dialog_1 = require("./Dialog"); | ||
const EmulationManager_1 = require("./EmulationManager"); | ||
const FrameManager_1 = require("./FrameManager"); | ||
const Input_1 = require("./Input"); | ||
const Tracing_1 = require("./Tracing"); | ||
const helper_1 = require("./helper"); | ||
const Coverage_1 = require("./Coverage"); | ||
const Worker_1 = require("./Worker"); | ||
const JSHandle_1 = require("./JSHandle"); | ||
const Accessibility_1 = require("./Accessibility"); | ||
const TimeoutSettings_1 = require("./TimeoutSettings"); | ||
const writeFileAsync = helper_1.helper.promisify(fs.writeFile); | ||
const paperFormats = { | ||
letter: { width: 8.5, height: 11 }, | ||
legal: { width: 8.5, height: 14 }, | ||
tabloid: { width: 11, height: 17 }, | ||
ledger: { width: 17, height: 11 }, | ||
a0: { width: 33.1, height: 46.8 }, | ||
a1: { width: 23.4, height: 33.1 }, | ||
a2: { width: 16.54, height: 23.4 }, | ||
a3: { width: 11.7, height: 16.54 }, | ||
a4: { width: 8.27, height: 11.7 }, | ||
a5: { width: 5.83, height: 8.27 }, | ||
a6: { width: 4.13, height: 5.83 }, | ||
}; | ||
class Page extends EventEmitter { | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {!Puppeteer.Target} target | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {?Puppeteer.Viewport} defaultViewport | ||
* @param {!TaskQueue} screenshotTaskQueue | ||
* @return {!Promise<!Page>} | ||
*/ | ||
static async create(client, target, ignoreHTTPSErrors, defaultViewport, screenshotTaskQueue) { | ||
const page = new Page(client, target, ignoreHTTPSErrors, screenshotTaskQueue); | ||
await page._initialize(); | ||
if (defaultViewport) | ||
await page.setViewport(defaultViewport); | ||
return page; | ||
} | ||
/** | ||
* @param {!CDPSession} client | ||
* @param {!Puppeteer.Target} target | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {!TaskQueue} screenshotTaskQueue | ||
*/ | ||
constructor(client, target, ignoreHTTPSErrors, screenshotTaskQueue) { | ||
super(); | ||
this._closed = false; | ||
this._timeoutSettings = new TimeoutSettings_1.TimeoutSettings(); | ||
this._pageBindings = new Map(); | ||
this._javascriptEnabled = true; | ||
this._workers = new Map(); | ||
// TODO: improve this typedef - it's a function that takes a file chooser or something? | ||
this._fileChooserInterceptors = new Set(); | ||
this._client = client; | ||
this._target = target; | ||
this._keyboard = new Keyboard(client); | ||
this._mouse = new Mouse(client, this._keyboard); | ||
this._timeoutSettings = new TimeoutSettings(); | ||
this._touchscreen = new Touchscreen(client, this._keyboard); | ||
this._accessibility = new Accessibility(client); | ||
/** @type {!FrameManager} */ | ||
this._frameManager = new FrameManager(client, this, ignoreHTTPSErrors, this._timeoutSettings); | ||
this._emulationManager = new EmulationManager(client); | ||
this._tracing = new Tracing(client); | ||
/** @type {!Map<string, Function>} */ | ||
this._pageBindings = new Map(); | ||
this._coverage = new Coverage(client); | ||
this._javascriptEnabled = true; | ||
/** @type {?Puppeteer.Viewport} */ | ||
this._keyboard = new Input_1.Keyboard(client); | ||
this._mouse = new Input_1.Mouse(client, this._keyboard); | ||
this._touchscreen = new Input_1.Touchscreen(client, this._keyboard); | ||
this._accessibility = new Accessibility_1.Accessibility(client); | ||
this._frameManager = new FrameManager_1.FrameManager(client, this, ignoreHTTPSErrors, this._timeoutSettings); | ||
this._emulationManager = new EmulationManager_1.EmulationManager(client); | ||
this._tracing = new Tracing_1.Tracing(client); | ||
this._coverage = new Coverage_1.Coverage(client); | ||
this._screenshotTaskQueue = screenshotTaskQueue; | ||
this._viewport = null; | ||
this._screenshotTaskQueue = screenshotTaskQueue; | ||
/** @type {!Map<string, PuppeteerWorker>} */ | ||
this._workers = new Map(); | ||
client.on('Target.attachedToTarget', event => { | ||
@@ -92,9 +76,9 @@ if (event.targetInfo.type !== 'worker') { | ||
sessionId: event.sessionId | ||
}).catch(debugError); | ||
}).catch(helper_1.debugError); | ||
return; | ||
} | ||
const session = Connection.fromSession(client).session(event.sessionId); | ||
const worker = new PuppeteerWorker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this)); | ||
const session = Connection_1.Connection.fromSession(client).session(event.sessionId); | ||
const worker = new Worker_1.Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this)); | ||
this._workers.set(event.sessionId, worker); | ||
this.emit(Events.Page.WorkerCreated, worker); | ||
this.emit(Events_1.Events.Page.WorkerCreated, worker); | ||
}); | ||
@@ -105,16 +89,16 @@ client.on('Target.detachedFromTarget', event => { | ||
return; | ||
this.emit(Events.Page.WorkerDestroyed, worker); | ||
this.emit(Events_1.Events.Page.WorkerDestroyed, worker); | ||
this._workers.delete(event.sessionId); | ||
}); | ||
this._frameManager.on(Events.FrameManager.FrameAttached, event => this.emit(Events.Page.FrameAttached, event)); | ||
this._frameManager.on(Events.FrameManager.FrameDetached, event => this.emit(Events.Page.FrameDetached, event)); | ||
this._frameManager.on(Events.FrameManager.FrameNavigated, event => this.emit(Events.Page.FrameNavigated, event)); | ||
this._frameManager.on(Events_1.Events.FrameManager.FrameAttached, event => this.emit(Events_1.Events.Page.FrameAttached, event)); | ||
this._frameManager.on(Events_1.Events.FrameManager.FrameDetached, event => this.emit(Events_1.Events.Page.FrameDetached, event)); | ||
this._frameManager.on(Events_1.Events.FrameManager.FrameNavigated, event => this.emit(Events_1.Events.Page.FrameNavigated, event)); | ||
const networkManager = this._frameManager.networkManager(); | ||
networkManager.on(Events.NetworkManager.Request, event => this.emit(Events.Page.Request, event)); | ||
networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event)); | ||
networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event)); | ||
networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event)); | ||
networkManager.on(Events_1.Events.NetworkManager.Request, event => this.emit(Events_1.Events.Page.Request, event)); | ||
networkManager.on(Events_1.Events.NetworkManager.Response, event => this.emit(Events_1.Events.Page.Response, event)); | ||
networkManager.on(Events_1.Events.NetworkManager.RequestFailed, event => this.emit(Events_1.Events.Page.RequestFailed, event)); | ||
networkManager.on(Events_1.Events.NetworkManager.RequestFinished, event => this.emit(Events_1.Events.Page.RequestFinished, event)); | ||
this._fileChooserInterceptors = new Set(); | ||
client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded)); | ||
client.on('Page.loadEventFired', event => this.emit(Events.Page.Load)); | ||
client.on('Page.domContentEventFired', () => this.emit(Events_1.Events.Page.DOMContentLoaded)); | ||
client.on('Page.loadEventFired', () => this.emit(Events_1.Events.Page.Load)); | ||
client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event)); | ||
@@ -124,3 +108,3 @@ client.on('Runtime.bindingCalled', event => this._onBindingCalled(event)); | ||
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails)); | ||
client.on('Inspector.targetCrashed', event => this._onTargetCrashed()); | ||
client.on('Inspector.targetCrashed', () => this._onTargetCrashed()); | ||
client.on('Performance.metrics', event => this._emitMetrics(event)); | ||
@@ -130,6 +114,13 @@ client.on('Log.entryAdded', event => this._onLogEntryAdded(event)); | ||
this._target._isClosedPromise.then(() => { | ||
this.emit(Events.Page.Close); | ||
this.emit(Events_1.Events.Page.Close); | ||
this._closed = true; | ||
}); | ||
} | ||
static async create(client, target, ignoreHTTPSErrors, defaultViewport, screenshotTaskQueue) { | ||
const page = new Page(client, target, ignoreHTTPSErrors, screenshotTaskQueue); | ||
await page._initialize(); | ||
if (defaultViewport) | ||
await page.setViewport(defaultViewport); | ||
return page; | ||
} | ||
async _initialize() { | ||
@@ -143,5 +134,2 @@ await Promise.all([ | ||
} | ||
/** | ||
* @param {!Protocol.Page.fileChooserOpenedPayload} event | ||
*/ | ||
async _onFileChooser(event) { | ||
@@ -159,6 +147,2 @@ if (!this._fileChooserInterceptors.size) | ||
} | ||
/** | ||
* @param {!{timeout?: number}=} options | ||
* @return !Promise<!FileChooser>} | ||
*/ | ||
async waitForFileChooser(options = {}) { | ||
@@ -171,10 +155,7 @@ if (!this._fileChooserInterceptors.size) | ||
this._fileChooserInterceptors.add(callback); | ||
return helper.waitWithTimeout(promise, 'waiting for file chooser', timeout).catch(e => { | ||
return helper_1.helper.waitWithTimeout(promise, 'waiting for file chooser', timeout).catch(error => { | ||
this._fileChooserInterceptors.delete(callback); | ||
throw e; | ||
throw error; | ||
}); | ||
} | ||
/** | ||
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options | ||
*/ | ||
async setGeolocation(options) { | ||
@@ -190,17 +171,8 @@ const { longitude, latitude, accuracy = 0 } = options; | ||
} | ||
/** | ||
* @return {!Puppeteer.Target} | ||
*/ | ||
target() { | ||
return this._target; | ||
} | ||
/** | ||
* @return {!Puppeteer.Browser} | ||
*/ | ||
browser() { | ||
return this._target.browser(); | ||
} | ||
/** | ||
* @return {!Puppeteer.BrowserContext} | ||
*/ | ||
browserContext() { | ||
@@ -212,96 +184,48 @@ return this._target.browserContext(); | ||
} | ||
/** | ||
* @param {!Protocol.Log.entryAddedPayload} event | ||
*/ | ||
_onLogEntryAdded(event) { | ||
const { level, text, args, source, url, lineNumber } = event.entry; | ||
if (args) | ||
args.map(arg => helper.releaseObject(this._client, arg)); | ||
args.map(arg => helper_1.helper.releaseObject(this._client, arg)); | ||
if (source !== 'worker') | ||
this.emit(Events.Page.Console, new ConsoleMessage(level, text, [], { url, lineNumber })); | ||
this.emit(Events_1.Events.Page.Console, new ConsoleMessage(level, text, [], { url, lineNumber })); | ||
} | ||
/** | ||
* @return {!Puppeteer.Frame} | ||
*/ | ||
mainFrame() { | ||
return this._frameManager.mainFrame(); | ||
} | ||
/** | ||
* @return {!Keyboard} | ||
*/ | ||
get keyboard() { | ||
return this._keyboard; | ||
} | ||
/** | ||
* @return {!Touchscreen} | ||
*/ | ||
get touchscreen() { | ||
return this._touchscreen; | ||
} | ||
/** | ||
* @return {!Coverage} | ||
*/ | ||
get coverage() { | ||
return this._coverage; | ||
} | ||
/** | ||
* @return {!Tracing} | ||
*/ | ||
get tracing() { | ||
return this._tracing; | ||
} | ||
/** | ||
* @return {!Accessibility} | ||
*/ | ||
get accessibility() { | ||
return this._accessibility; | ||
} | ||
/** | ||
* @return {!Array<Puppeteer.Frame>} | ||
*/ | ||
frames() { | ||
return this._frameManager.frames(); | ||
} | ||
/** | ||
* @return {!Array<!PuppeteerWorker>} | ||
*/ | ||
workers() { | ||
return Array.from(this._workers.values()); | ||
} | ||
/** | ||
* @param {boolean} value | ||
*/ | ||
async setRequestInterception(value) { | ||
return this._frameManager.networkManager().setRequestInterception(value); | ||
} | ||
/** | ||
* @param {boolean} enabled | ||
*/ | ||
setOfflineMode(enabled) { | ||
return this._frameManager.networkManager().setOfflineMode(enabled); | ||
} | ||
/** | ||
* @param {number} timeout | ||
*/ | ||
setDefaultNavigationTimeout(timeout) { | ||
this._timeoutSettings.setDefaultNavigationTimeout(timeout); | ||
} | ||
/** | ||
* @param {number} timeout | ||
*/ | ||
setDefaultTimeout(timeout) { | ||
this._timeoutSettings.setDefaultTimeout(timeout); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
async $(selector) { | ||
return this.mainFrame().$(selector); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
async evaluateHandle(pageFunction, ...args) { | ||
@@ -311,6 +235,2 @@ const context = await this.mainFrame().executionContext(); | ||
} | ||
/** | ||
* @param {!JSHandle} prototypeHandle | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
async queryObjects(prototypeHandle) { | ||
@@ -320,38 +240,14 @@ const context = await this.mainFrame().executionContext(); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $eval(selector, pageFunction, ...args) { | ||
return this.mainFrame().$eval(selector, pageFunction, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<(!Object|undefined)>} | ||
*/ | ||
async $$eval(selector, pageFunction, ...args) { | ||
return this.mainFrame().$$eval(selector, pageFunction, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $$(selector) { | ||
return this.mainFrame().$$(selector); | ||
} | ||
/** | ||
* @param {string} expression | ||
* @return {!Promise<!Array<!ElementHandle>>} | ||
*/ | ||
async $x(expression) { | ||
return this.mainFrame().$x(expression); | ||
} | ||
/** | ||
* @param {!Array<string>} urls | ||
* @return {!Promise<!Array<Network.Cookie>>} | ||
*/ | ||
async cookies(...urls) { | ||
@@ -362,3 +258,3 @@ const originalCookies = (await this._client.send('Network.getCookies', { | ||
const unsupportedCookieAttributes = ['priority']; | ||
const filterUnsupportedAttributes = cookie => { | ||
const filterUnsupportedAttributes = (cookie) => { | ||
for (const attr of unsupportedCookieAttributes) | ||
@@ -370,5 +266,2 @@ delete cookie[attr]; | ||
} | ||
/** | ||
* @param {Array<Protocol.Network.deleteCookiesParameters>} cookies | ||
*/ | ||
async deleteCookie(...cookies) { | ||
@@ -383,5 +276,2 @@ const pageURL = this.url(); | ||
} | ||
/** | ||
* @param {Array<Network.CookieParam>} cookies | ||
*/ | ||
async setCookie(...cookies) { | ||
@@ -394,4 +284,4 @@ const pageURL = this.url(); | ||
item.url = pageURL; | ||
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`); | ||
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`); | ||
helper_1.assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`); | ||
helper_1.assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`); | ||
return item; | ||
@@ -403,20 +293,8 @@ }); | ||
} | ||
/** | ||
* @param {!{url?: string, path?: string, content?: string, type?: string}} options | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async addScriptTag(options) { | ||
return this.mainFrame().addScriptTag(options); | ||
} | ||
/** | ||
* @param {!{url?: string, path?: string, content?: string}} options | ||
* @return {!Promise<!ElementHandle>} | ||
*/ | ||
async addStyleTag(options) { | ||
return this.mainFrame().addStyleTag(options); | ||
} | ||
/** | ||
* @param {string} name | ||
* @param {Function} puppeteerFunction | ||
*/ | ||
async exposeFunction(name, puppeteerFunction) { | ||
@@ -426,9 +304,12 @@ if (this._pageBindings.has(name)) | ||
this._pageBindings.set(name, puppeteerFunction); | ||
const expression = helper.evaluationString(addPageBinding, name); | ||
const expression = helper_1.helper.evaluationString(addPageBinding, name); | ||
await this._client.send('Runtime.addBinding', { name: name }); | ||
await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source: expression }); | ||
await Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(debugError))); | ||
await Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(helper_1.debugError))); | ||
function addPageBinding(bindingName) { | ||
const win = /** @type * */ (window); | ||
const binding = /** @type function(string):* */ (win[bindingName]); | ||
/* Cast window to any here as we're about to add properties to it | ||
* via win[bindingName] which TypeScript doesn't like. | ||
*/ | ||
const win = window; | ||
const binding = win[bindingName]; | ||
win[bindingName] = (...args) => { | ||
@@ -449,23 +330,11 @@ const me = window[bindingName]; | ||
} | ||
/** | ||
* @param {?{username: string, password: string}} credentials | ||
*/ | ||
async authenticate(credentials) { | ||
return this._frameManager.networkManager().authenticate(credentials); | ||
} | ||
/** | ||
* @param {!Object<string, string>} headers | ||
*/ | ||
async setExtraHTTPHeaders(headers) { | ||
return this._frameManager.networkManager().setExtraHTTPHeaders(headers); | ||
} | ||
/** | ||
* @param {string} userAgent | ||
*/ | ||
async setUserAgent(userAgent) { | ||
return this._frameManager.networkManager().setUserAgent(userAgent); | ||
} | ||
/** | ||
* @return {!Promise<!Metrics>} | ||
*/ | ||
async metrics() { | ||
@@ -475,7 +344,4 @@ const response = await this._client.send('Performance.getMetrics'); | ||
} | ||
/** | ||
* @param {!Protocol.Performance.metricsPayload} event | ||
*/ | ||
_emitMetrics(event) { | ||
this.emit(Events.Page.Metrics, { | ||
this.emit(Events_1.Events.Page.Metrics, { | ||
title: event.title, | ||
@@ -485,6 +351,2 @@ metrics: this._buildMetricsObject(event.metrics) | ||
} | ||
/** | ||
* @param {?Array<!Protocol.Performance.Metric>} metrics | ||
* @return {!Metrics} | ||
*/ | ||
_buildMetricsObject(metrics) { | ||
@@ -498,14 +360,8 @@ const result = {}; | ||
} | ||
/** | ||
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails | ||
*/ | ||
_handleException(exceptionDetails) { | ||
const message = helper.getExceptionMessage(exceptionDetails); | ||
const message = helper_1.helper.getExceptionMessage(exceptionDetails); | ||
const err = new Error(message); | ||
err.stack = ''; // Don't report clientside error with a node stack attached | ||
this.emit(Events.Page.PageError, err); | ||
this.emit(Events_1.Events.Page.PageError, err); | ||
} | ||
/** | ||
* @param {!Protocol.Runtime.consoleAPICalledPayload} event | ||
*/ | ||
async _onConsoleAPI(event) { | ||
@@ -529,8 +385,5 @@ if (event.executionContextId === 0) { | ||
const context = this._frameManager.executionContextById(event.executionContextId); | ||
const values = event.args.map(arg => createJSHandle(context, arg)); | ||
const values = event.args.map(arg => JSHandle_1.createJSHandle(context, arg)); | ||
this._addConsoleMessage(event.type, values, event.stackTrace); | ||
} | ||
/** | ||
* @param {!Protocol.Runtime.bindingCalledPayload} event | ||
*/ | ||
async _onBindingCalled(event) { | ||
@@ -541,16 +394,11 @@ const { name, seq, args } = JSON.parse(event.payload); | ||
const result = await this._pageBindings.get(name)(...args); | ||
expression = helper.evaluationString(deliverResult, name, seq, result); | ||
expression = helper_1.helper.evaluationString(deliverResult, name, seq, result); | ||
} | ||
catch (error) { | ||
if (error instanceof Error) | ||
expression = helper.evaluationString(deliverError, name, seq, error.message, error.stack); | ||
expression = helper_1.helper.evaluationString(deliverError, name, seq, error.message, error.stack); | ||
else | ||
expression = helper.evaluationString(deliverErrorValue, name, seq, error); | ||
expression = helper_1.helper.evaluationString(deliverErrorValue, name, seq, error); | ||
} | ||
this._client.send('Runtime.evaluate', { expression, contextId: event.executionContextId }).catch(debugError); | ||
/** | ||
* @param {string} name | ||
* @param {number} seq | ||
* @param {*} result | ||
*/ | ||
this._client.send('Runtime.evaluate', { expression, contextId: event.executionContextId }).catch(helper_1.debugError); | ||
function deliverResult(name, seq, result) { | ||
@@ -560,8 +408,2 @@ window[name]['callbacks'].get(seq).resolve(result); | ||
} | ||
/** | ||
* @param {string} name | ||
* @param {number} seq | ||
* @param {string} message | ||
* @param {string} stack | ||
*/ | ||
function deliverError(name, seq, message, stack) { | ||
@@ -573,7 +415,2 @@ const error = new Error(message); | ||
} | ||
/** | ||
* @param {string} name | ||
* @param {number} seq | ||
* @param {*} value | ||
*/ | ||
function deliverErrorValue(name, seq, value) { | ||
@@ -584,9 +421,4 @@ window[name]['callbacks'].get(seq).reject(value); | ||
} | ||
/** | ||
* @param {string} type | ||
* @param {!Array<!JSHandle>} args | ||
* @param {Protocol.Runtime.StackTrace=} stackTrace | ||
*/ | ||
_addConsoleMessage(type, args, stackTrace) { | ||
if (!this.listenerCount(Events.Page.Console)) { | ||
if (!this.listenerCount(Events_1.Events.Page.Console)) { | ||
args.forEach(arg => arg.dispose()); | ||
@@ -601,3 +433,3 @@ return; | ||
else | ||
textTokens.push(helper.valueFromRemoteObject(remoteObject)); | ||
textTokens.push(helper_1.helper.valueFromRemoteObject(remoteObject)); | ||
} | ||
@@ -610,3 +442,3 @@ const location = stackTrace && stackTrace.callFrames.length ? { | ||
const message = new ConsoleMessage(type, textTokens.join(' '), args, location); | ||
this.emit(Events.Page.Console, message); | ||
this.emit(Events_1.Events.Page.Console, message); | ||
} | ||
@@ -616,44 +448,25 @@ _onDialog(event) { | ||
if (event.type === 'alert') | ||
dialogType = Dialog.Type.Alert; | ||
dialogType = Dialog_1.Dialog.Type.Alert; | ||
else if (event.type === 'confirm') | ||
dialogType = Dialog.Type.Confirm; | ||
dialogType = Dialog_1.Dialog.Type.Confirm; | ||
else if (event.type === 'prompt') | ||
dialogType = Dialog.Type.Prompt; | ||
dialogType = Dialog_1.Dialog.Type.Prompt; | ||
else if (event.type === 'beforeunload') | ||
dialogType = Dialog.Type.BeforeUnload; | ||
assert(dialogType, 'Unknown javascript dialog type: ' + event.type); | ||
const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt); | ||
this.emit(Events.Page.Dialog, dialog); | ||
dialogType = Dialog_1.Dialog.Type.BeforeUnload; | ||
helper_1.assert(dialogType, 'Unknown javascript dialog type: ' + event.type); | ||
const dialog = new Dialog_1.Dialog(this._client, dialogType, event.message, event.defaultPrompt); | ||
this.emit(Events_1.Events.Page.Dialog, dialog); | ||
} | ||
/** | ||
* @return {!string} | ||
*/ | ||
url() { | ||
return this.mainFrame().url(); | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async content() { | ||
return await this._frameManager.mainFrame().content(); | ||
} | ||
/** | ||
* @param {string} html | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
*/ | ||
async setContent(html, options) { | ||
await this._frameManager.mainFrame().setContent(html, options); | ||
} | ||
/** | ||
* @param {string} url | ||
* @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async goto(url, options) { | ||
return await this._frameManager.mainFrame().goto(url, options); | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async reload(options) { | ||
@@ -664,9 +477,4 @@ const result = await Promise.all([ | ||
]); | ||
const response = /** @type Puppeteer.Response */ (result[0]); | ||
return response; | ||
return result[0]; | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async waitForNavigation(options = {}) { | ||
@@ -677,14 +485,9 @@ return await this._frameManager.mainFrame().waitForNavigation(options); | ||
if (!this._disconnectPromise) | ||
this._disconnectPromise = new Promise(fulfill => this._client.once(Events.CDPSession.Disconnected, () => fulfill(new Error('Target closed')))); | ||
this._disconnectPromise = new Promise(fulfill => this._client.once(Events_1.Events.CDPSession.Disconnected, () => fulfill(new Error('Target closed')))); | ||
return this._disconnectPromise; | ||
} | ||
/** | ||
* @param {(string|Function)} urlOrPredicate | ||
* @param {!{timeout?: number}=} options | ||
* @return {!Promise<!Puppeteer.Request>} | ||
*/ | ||
async waitForRequest(urlOrPredicate, options = {}) { | ||
const { timeout = this._timeoutSettings.timeout(), } = options; | ||
return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Request, request => { | ||
if (helper.isString(urlOrPredicate)) | ||
return helper_1.helper.waitForEvent(this._frameManager.networkManager(), Events_1.Events.NetworkManager.Request, request => { | ||
if (helper_1.helper.isString(urlOrPredicate)) | ||
return (urlOrPredicate === request.url()); | ||
@@ -696,11 +499,6 @@ if (typeof urlOrPredicate === 'function') | ||
} | ||
/** | ||
* @param {(string|Function)} urlOrPredicate | ||
* @param {!{timeout?: number}=} options | ||
* @return {!Promise<!Puppeteer.Response>} | ||
*/ | ||
async waitForResponse(urlOrPredicate, options = {}) { | ||
const { timeout = this._timeoutSettings.timeout(), } = options; | ||
return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Response, response => { | ||
if (helper.isString(urlOrPredicate)) | ||
return helper_1.helper.waitForEvent(this._frameManager.networkManager(), Events_1.Events.NetworkManager.Response, response => { | ||
if (helper_1.helper.isString(urlOrPredicate)) | ||
return (urlOrPredicate === response.url()); | ||
@@ -712,20 +510,8 @@ if (typeof urlOrPredicate === 'function') | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async goBack(options) { | ||
return this._go(-1, options); | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async goForward(options) { | ||
return this._go(+1, options); | ||
} | ||
/** | ||
* @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array<!Puppeteer.PuppeteerLifeCycleEvent>}=} options | ||
* @return {!Promise<?Puppeteer.Response>} | ||
*/ | ||
async _go(delta, options) { | ||
@@ -740,4 +526,3 @@ const history = await this._client.send('Page.getNavigationHistory'); | ||
]); | ||
const response = /** @type Puppeteer.Response */ (result[0]); | ||
return response; | ||
return result[0]; | ||
} | ||
@@ -747,5 +532,2 @@ async bringToFront() { | ||
} | ||
/** | ||
* @param {!{viewport: !Puppeteer.Viewport, userAgent: string}} options | ||
*/ | ||
async emulate(options) { | ||
@@ -757,5 +539,2 @@ await Promise.all([ | ||
} | ||
/** | ||
* @param {boolean} enabled | ||
*/ | ||
async setJavaScriptEnabled(enabled) { | ||
@@ -767,18 +546,9 @@ if (this._javascriptEnabled === enabled) | ||
} | ||
/** | ||
* @param {boolean} enabled | ||
*/ | ||
async setBypassCSP(enabled) { | ||
await this._client.send('Page.setBypassCSP', { enabled }); | ||
} | ||
/** | ||
* @param {?string} type | ||
*/ | ||
async emulateMediaType(type) { | ||
assert(type === 'screen' || type === 'print' || type === null, 'Unsupported media type: ' + type); | ||
helper_1.assert(type === 'screen' || type === 'print' || type === null, 'Unsupported media type: ' + type); | ||
await this._client.send('Emulation.setEmulatedMedia', { media: type || '' }); | ||
} | ||
/** | ||
* @param {?Array<MediaFeature>} features | ||
*/ | ||
async emulateMediaFeatures(features) { | ||
@@ -790,3 +560,3 @@ if (features === null) | ||
const name = mediaFeature.name; | ||
assert(/^prefers-(?:color-scheme|reduced-motion)$/.test(name), 'Unsupported media feature: ' + name); | ||
helper_1.assert(/^prefers-(?:color-scheme|reduced-motion)$/.test(name), 'Unsupported media feature: ' + name); | ||
return true; | ||
@@ -797,5 +567,2 @@ }); | ||
} | ||
/** | ||
* @param {?string} timezoneId | ||
*/ | ||
async emulateTimezone(timezoneId) { | ||
@@ -805,11 +572,8 @@ try { | ||
} | ||
catch (exception) { | ||
if (exception.message.includes('Invalid timezone')) | ||
catch (error) { | ||
if (error.message.includes('Invalid timezone')) | ||
throw new Error(`Invalid timezone ID: ${timezoneId}`); | ||
throw exception; | ||
throw error; | ||
} | ||
} | ||
/** | ||
* @param {!Puppeteer.Viewport} viewport | ||
*/ | ||
async setViewport(viewport) { | ||
@@ -821,34 +585,15 @@ const needsReload = await this._emulationManager.emulateViewport(viewport); | ||
} | ||
/** | ||
* @return {?Puppeteer.Viewport} | ||
*/ | ||
viewport() { | ||
return this._viewport; | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
* @return {!Promise<*>} | ||
*/ | ||
async evaluate(pageFunction, ...args) { | ||
return this._frameManager.mainFrame().evaluate(pageFunction, ...args); | ||
} | ||
/** | ||
* @param {Function|string} pageFunction | ||
* @param {!Array<*>} args | ||
*/ | ||
async evaluateOnNewDocument(pageFunction, ...args) { | ||
const source = helper.evaluationString(pageFunction, ...args); | ||
const source = helper_1.helper.evaluationString(pageFunction, ...args); | ||
await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source }); | ||
} | ||
/** | ||
* @param {boolean} enabled | ||
*/ | ||
async setCacheEnabled(enabled = true) { | ||
await this._frameManager.networkManager().setCacheEnabled(enabled); | ||
} | ||
/** | ||
* @param {!ScreenshotOptions=} options | ||
* @return {!Promise<!Buffer|!String>} | ||
*/ | ||
async screenshot(options = {}) { | ||
@@ -859,3 +604,3 @@ let screenshotType = null; | ||
if (options.type) { | ||
assert(options.type === 'png' || options.type === 'jpeg', 'Unknown options.type value: ' + options.type); | ||
helper_1.assert(options.type === 'png' || options.type === 'jpeg', 'Unknown options.type value: ' + options.type); | ||
screenshotType = options.type; | ||
@@ -869,3 +614,3 @@ } | ||
screenshotType = 'jpeg'; | ||
assert(screenshotType, 'Unsupported screenshot mime type: ' + mimeType); | ||
helper_1.assert(screenshotType, 'Unsupported screenshot mime type: ' + mimeType); | ||
} | ||
@@ -875,23 +620,18 @@ if (!screenshotType) | ||
if (options.quality) { | ||
assert(screenshotType === 'jpeg', 'options.quality is unsupported for the ' + screenshotType + ' screenshots'); | ||
assert(typeof options.quality === 'number', 'Expected options.quality to be a number but found ' + (typeof options.quality)); | ||
assert(Number.isInteger(options.quality), 'Expected options.quality to be an integer'); | ||
assert(options.quality >= 0 && options.quality <= 100, 'Expected options.quality to be between 0 and 100 (inclusive), got ' + options.quality); | ||
helper_1.assert(screenshotType === 'jpeg', 'options.quality is unsupported for the ' + screenshotType + ' screenshots'); | ||
helper_1.assert(typeof options.quality === 'number', 'Expected options.quality to be a number but found ' + (typeof options.quality)); | ||
helper_1.assert(Number.isInteger(options.quality), 'Expected options.quality to be an integer'); | ||
helper_1.assert(options.quality >= 0 && options.quality <= 100, 'Expected options.quality to be between 0 and 100 (inclusive), got ' + options.quality); | ||
} | ||
assert(!options.clip || !options.fullPage, 'options.clip and options.fullPage are exclusive'); | ||
helper_1.assert(!options.clip || !options.fullPage, 'options.clip and options.fullPage are exclusive'); | ||
if (options.clip) { | ||
assert(typeof options.clip.x === 'number', 'Expected options.clip.x to be a number but found ' + (typeof options.clip.x)); | ||
assert(typeof options.clip.y === 'number', 'Expected options.clip.y to be a number but found ' + (typeof options.clip.y)); | ||
assert(typeof options.clip.width === 'number', 'Expected options.clip.width to be a number but found ' + (typeof options.clip.width)); | ||
assert(typeof options.clip.height === 'number', 'Expected options.clip.height to be a number but found ' + (typeof options.clip.height)); | ||
assert(options.clip.width !== 0, 'Expected options.clip.width not to be 0.'); | ||
assert(options.clip.height !== 0, 'Expected options.clip.height not to be 0.'); | ||
helper_1.assert(typeof options.clip.x === 'number', 'Expected options.clip.x to be a number but found ' + (typeof options.clip.x)); | ||
helper_1.assert(typeof options.clip.y === 'number', 'Expected options.clip.y to be a number but found ' + (typeof options.clip.y)); | ||
helper_1.assert(typeof options.clip.width === 'number', 'Expected options.clip.width to be a number but found ' + (typeof options.clip.width)); | ||
helper_1.assert(typeof options.clip.height === 'number', 'Expected options.clip.height to be a number but found ' + (typeof options.clip.height)); | ||
helper_1.assert(options.clip.width !== 0, 'Expected options.clip.width not to be 0.'); | ||
helper_1.assert(options.clip.height !== 0, 'Expected options.clip.height not to be 0.'); | ||
} | ||
return this._screenshotTaskQueue.postTask(this._screenshotTask.bind(this, screenshotType, options)); | ||
} | ||
/** | ||
* @param {"png"|"jpeg"} format | ||
* @param {!ScreenshotOptions=} options | ||
* @return {!Promise<!Buffer|!String>} | ||
*/ | ||
async _screenshotTask(format, options) { | ||
@@ -907,3 +647,2 @@ await this._client.send('Target.activateTarget', { targetId: this._target._targetId }); | ||
const { isMobile = false, deviceScaleFactor = 1, isLandscape = false } = this._viewport || {}; | ||
/** @type {!Protocol.Emulation.ScreenOrientation} */ | ||
const screenOrientation = isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' }; | ||
@@ -932,6 +671,2 @@ await this._client.send('Emulation.setDeviceMetricsOverride', { mobile: isMobile, width, height, deviceScaleFactor, screenOrientation }); | ||
} | ||
/** | ||
* @param {!PDFOptions=} options | ||
* @return {!Promise<!Buffer>} | ||
*/ | ||
async pdf(options = {}) { | ||
@@ -942,4 +677,4 @@ const { scale = 1, displayHeaderFooter = false, headerTemplate = '', footerTemplate = '', printBackground = false, landscape = false, pageRanges = '', preferCSSPageSize = false, margin = {}, path = null } = options; | ||
if (options.format) { | ||
const format = Page.PaperFormats[options.format.toLowerCase()]; | ||
assert(format, 'Unknown paper format: ' + options.format); | ||
const format = paperFormats[options.format.toLowerCase()]; | ||
helper_1.assert(format, 'Unknown paper format: ' + options.format); | ||
paperWidth = format.width; | ||
@@ -973,15 +708,9 @@ paperHeight = format.height; | ||
}); | ||
return await helper.readProtocolStream(this._client, result.stream, path); | ||
return await helper_1.helper.readProtocolStream(this._client, result.stream, path); | ||
} | ||
/** | ||
* @return {!Promise<string>} | ||
*/ | ||
async title() { | ||
return this.mainFrame().title(); | ||
} | ||
/** | ||
* @param {!{runBeforeUnload: (boolean|undefined)}=} options | ||
*/ | ||
async close(options = { runBeforeUnload: undefined }) { | ||
assert(!!this._client._connection, 'Protocol error: Connection closed. Most likely the page has been closed.'); | ||
helper_1.assert(!!this._client._connection, 'Protocol error: Connection closed. Most likely the page has been closed.'); | ||
const runBeforeUnload = !!options.runBeforeUnload; | ||
@@ -996,86 +725,35 @@ if (runBeforeUnload) { | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isClosed() { | ||
return this._closed; | ||
} | ||
/** | ||
* @return {!Mouse} | ||
*/ | ||
get mouse() { | ||
return this._mouse; | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options | ||
*/ | ||
click(selector, options = {}) { | ||
return this.mainFrame().click(selector, options); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
focus(selector) { | ||
return this.mainFrame().focus(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
hover(selector) { | ||
return this.mainFrame().hover(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!Array<string>} values | ||
* @return {!Promise<!Array<string>>} | ||
*/ | ||
select(selector, ...values) { | ||
return this.mainFrame().select(selector, ...values); | ||
} | ||
/** | ||
* @param {string} selector | ||
*/ | ||
tap(selector) { | ||
return this.mainFrame().tap(selector); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {string} text | ||
* @param {{delay: (number|undefined)}=} options | ||
*/ | ||
type(selector, text, options) { | ||
return this.mainFrame().type(selector, text, options); | ||
} | ||
/** | ||
* @param {(string|number|Function)} selectorOrFunctionOrTimeout | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number, polling?: string|number}=} options | ||
* @param {!Array<*>} args | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) { | ||
return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
waitForSelector(selector, options = {}) { | ||
return this.mainFrame().waitForSelector(selector, options); | ||
} | ||
/** | ||
* @param {string} xpath | ||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options | ||
* @return {!Promise<?ElementHandle>} | ||
*/ | ||
waitForXPath(xpath, options = {}) { | ||
return this.mainFrame().waitForXPath(xpath, options); | ||
} | ||
/** | ||
* @param {Function} pageFunction | ||
* @param {!{polling?: string|number, timeout?: number}=} options | ||
* @param {!Array<*>} args | ||
* @return {!Promise<!JSHandle>} | ||
*/ | ||
waitForFunction(pageFunction, options = {}, ...args) { | ||
@@ -1085,50 +763,3 @@ return this.mainFrame().waitForFunction(pageFunction, options, ...args); | ||
} | ||
/** | ||
* @typedef {Object} PDFOptions | ||
* @property {number=} scale | ||
* @property {boolean=} displayHeaderFooter | ||
* @property {string=} headerTemplate | ||
* @property {string=} footerTemplate | ||
* @property {boolean=} printBackground | ||
* @property {boolean=} landscape | ||
* @property {string=} pageRanges | ||
* @property {string=} format | ||
* @property {string|number=} width | ||
* @property {string|number=} height | ||
* @property {boolean=} preferCSSPageSize | ||
* @property {!{top?: string|number, bottom?: string|number, left?: string|number, right?: string|number}=} margin | ||
* @property {string=} path | ||
*/ | ||
/** | ||
* @typedef {Object} Metrics | ||
* @property {number=} Timestamp | ||
* @property {number=} Documents | ||
* @property {number=} Frames | ||
* @property {number=} JSEventListeners | ||
* @property {number=} Nodes | ||
* @property {number=} LayoutCount | ||
* @property {number=} RecalcStyleCount | ||
* @property {number=} LayoutDuration | ||
* @property {number=} RecalcStyleDuration | ||
* @property {number=} ScriptDuration | ||
* @property {number=} TaskDuration | ||
* @property {number=} JSHeapUsedSize | ||
* @property {number=} JSHeapTotalSize | ||
*/ | ||
/** | ||
* @typedef {Object} ScreenshotOptions | ||
* @property {string=} type | ||
* @property {string=} path | ||
* @property {boolean=} fullPage | ||
* @property {{x: number, y: number, width: number, height: number}=} clip | ||
* @property {number=} quality | ||
* @property {boolean=} omitBackground | ||
* @property {string=} encoding | ||
*/ | ||
/** | ||
* @typedef {Object} MediaFeature | ||
* @property {string} name | ||
* @property {string} value | ||
*/ | ||
/** @type {!Set<string>} */ | ||
exports.Page = Page; | ||
const supportedMetrics = new Set([ | ||
@@ -1149,16 +780,2 @@ 'Timestamp', | ||
]); | ||
/** @enum {!{width: number, height: number}} */ | ||
Page.PaperFormats = { | ||
letter: { width: 8.5, height: 11 }, | ||
legal: { width: 8.5, height: 14 }, | ||
tabloid: { width: 11, height: 17 }, | ||
ledger: { width: 17, height: 11 }, | ||
a0: { width: 33.1, height: 46.8 }, | ||
a1: { width: 23.4, height: 33.1 }, | ||
a2: { width: 16.54, height: 23.4 }, | ||
a3: { width: 11.7, height: 16.54 }, | ||
a4: { width: 8.27, height: 11.7 }, | ||
a5: { width: 5.83, height: 8.27 }, | ||
a6: { width: 4.13, height: 5.83 }, | ||
}; | ||
const unitToPixels = { | ||
@@ -1170,6 +787,2 @@ 'px': 1, | ||
}; | ||
/** | ||
* @param {(string|number|undefined)} parameter | ||
* @return {(number|undefined)} | ||
*/ | ||
function convertPrintParameterToInches(parameter) { | ||
@@ -1179,7 +792,7 @@ if (typeof parameter === 'undefined') | ||
let pixels; | ||
if (helper.isNumber(parameter)) { | ||
if (helper_1.helper.isNumber(parameter)) { | ||
// Treat numbers as pixel values to be aligned with phantom's paperSize. | ||
pixels = /** @type {number} */ (parameter); | ||
} | ||
else if (helper.isString(parameter)) { | ||
else if (helper_1.helper.isString(parameter)) { | ||
const text = /** @type {string} */ (parameter); | ||
@@ -1198,3 +811,3 @@ let unit = text.substring(text.length - 2).toLowerCase(); | ||
const value = Number(valueText); | ||
assert(!isNaN(value), 'Failed to parse parameter value: ' + text); | ||
helper_1.assert(!isNaN(value), 'Failed to parse parameter value: ' + text); | ||
pixels = value * unitToPixels[unit]; | ||
@@ -1207,40 +820,3 @@ } | ||
} | ||
/** | ||
* @typedef {Object} Network.Cookie | ||
* @property {string} name | ||
* @property {string} value | ||
* @property {string} domain | ||
* @property {string} path | ||
* @property {number} expires | ||
* @property {number} size | ||
* @property {boolean} httpOnly | ||
* @property {boolean} secure | ||
* @property {boolean} session | ||
* @property {("Strict"|"Lax"|"Extended"|"None")=} sameSite | ||
*/ | ||
/** | ||
* @typedef {Object} Network.CookieParam | ||
* @property {string} name | ||
* @property {string} value | ||
* @property {string=} url | ||
* @property {string=} domain | ||
* @property {string=} path | ||
* @property {number=} expires | ||
* @property {boolean=} httpOnly | ||
* @property {boolean=} secure | ||
* @property {("Strict"|"Lax")=} sameSite | ||
*/ | ||
/** | ||
* @typedef {Object} ConsoleMessage.Location | ||
* @property {string=} url | ||
* @property {number=} lineNumber | ||
* @property {number=} columnNumber | ||
*/ | ||
class ConsoleMessage { | ||
/** | ||
* @param {string} type | ||
* @param {string} text | ||
* @param {!Array<!JSHandle>} args | ||
* @param {ConsoleMessage.Location} location | ||
*/ | ||
constructor(type, text, args, location = {}) { | ||
@@ -1252,23 +828,11 @@ this._type = type; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
type() { | ||
return this._type; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
text() { | ||
return this._text; | ||
} | ||
/** | ||
* @return {!Array<!JSHandle>} | ||
*/ | ||
args() { | ||
return this._args; | ||
} | ||
/** | ||
* @return {Object} | ||
*/ | ||
location() { | ||
@@ -1278,37 +842,23 @@ return this._location; | ||
} | ||
exports.ConsoleMessage = ConsoleMessage; | ||
class FileChooser { | ||
/** | ||
* @param {CDPSession} client | ||
* @param {ElementHandle} element | ||
* @param {!Protocol.Page.fileChooserOpenedPayload} event | ||
*/ | ||
constructor(client, element, event) { | ||
this._handled = false; | ||
this._client = client; | ||
this._element = element; | ||
this._multiple = event.mode !== 'selectSingle'; | ||
this._handled = false; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isMultiple() { | ||
return this._multiple; | ||
} | ||
/** | ||
* @param {!Array<string>} filePaths | ||
* @return {!Promise} | ||
*/ | ||
async accept(filePaths) { | ||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!'); | ||
helper_1.assert(!this._handled, 'Cannot accept FileChooser which is already handled!'); | ||
this._handled = true; | ||
await this._element.uploadFile(...filePaths); | ||
} | ||
/** | ||
* @return {!Promise} | ||
*/ | ||
async cancel() { | ||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!'); | ||
helper_1.assert(!this._handled, 'Cannot cancel FileChooser which is already handled!'); | ||
this._handled = true; | ||
} | ||
} | ||
module.exports = { Page, ConsoleMessage, FileChooser }; | ||
exports.FileChooser = FileChooser; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
@@ -62,2 +63,2 @@ * Copyright 2018 Google Inc. All rights reserved. | ||
} | ||
module.exports = { PipeTransport }; | ||
exports.PipeTransport = PipeTransport; |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
@@ -16,14 +18,10 @@ * Copyright 2017 Google Inc. All rights reserved. | ||
*/ | ||
const Launcher = require('./Launcher'); | ||
const { BrowserFetcher } = require('./BrowserFetcher'); | ||
const Errors = require('./Errors'); | ||
const DeviceDescriptors = require('./DeviceDescriptors'); | ||
module.exports = class { | ||
/** | ||
* @param {string} projectRoot | ||
* @param {string} preferredRevision | ||
* @param {boolean} isPuppeteerCore | ||
* @param {string} productName | ||
*/ | ||
const Launcher_1 = require("./Launcher"); | ||
const BrowserFetcher_1 = require("./BrowserFetcher"); | ||
const Errors_1 = require("./Errors"); | ||
const DeviceDescriptors_1 = require("./DeviceDescriptors"); | ||
const QueryHandler = require("./QueryHandler"); | ||
class Puppeteer { | ||
constructor(projectRoot, preferredRevision, isPuppeteerCore, productName) { | ||
this._changedProduct = false; | ||
this._projectRoot = projectRoot; | ||
@@ -35,6 +33,2 @@ this._preferredRevision = preferredRevision; | ||
} | ||
/** | ||
* @param {!(Launcher.LaunchOptions & Launcher.ChromeArgOptions & Launcher.BrowserOptions & {product?: string, extraPrefsFirefox?: !object})=} options | ||
* @return {!Promise<!Puppeteer.Browser>} | ||
*/ | ||
launch(options = {}) { | ||
@@ -45,6 +39,2 @@ if (options.product) | ||
} | ||
/** | ||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserURL?: string, transport?: !Puppeteer.ConnectionTransport}) & {product?: string}=} options | ||
* @return {!Promise<!Puppeteer.Browser>} | ||
*/ | ||
connect(options) { | ||
@@ -55,5 +45,2 @@ if (options.product) | ||
} | ||
/** | ||
* @param {string} name | ||
*/ | ||
set _productName(name) { | ||
@@ -64,20 +51,12 @@ if (this.__productName !== name) | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
get _productName() { | ||
return this.__productName; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
executablePath() { | ||
return this._launcher.executablePath(); | ||
} | ||
/** | ||
* @return {!Puppeteer.ProductLauncher} | ||
*/ | ||
get _launcher() { | ||
if (!this._lazyLauncher || this._lazyLauncher.product !== this._productName || this._changedProduct) { | ||
// @ts-ignore | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const packageJson = require('../package.json'); | ||
@@ -93,48 +72,38 @@ switch (this._productName) { | ||
this._changedProduct = false; | ||
this._lazyLauncher = Launcher(this._projectRoot, this._preferredRevision, this._isPuppeteerCore, this._productName); | ||
this._lazyLauncher = Launcher_1.default(this._projectRoot, this._preferredRevision, this._isPuppeteerCore, this._productName); | ||
} | ||
return this._lazyLauncher; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
get product() { | ||
return this._launcher.product; | ||
} | ||
/** | ||
* @return {Object} | ||
*/ | ||
get devices() { | ||
return DeviceDescriptors; | ||
return DeviceDescriptors_1.devicesMap; | ||
} | ||
/** | ||
* @return {Object} | ||
*/ | ||
get errors() { | ||
return Errors; | ||
return Errors_1.puppeteerErrors; | ||
} | ||
/** | ||
* @param {!Launcher.ChromeArgOptions=} options | ||
* @return {!Array<string>} | ||
*/ | ||
defaultArgs(options) { | ||
return this._launcher.defaultArgs(options); | ||
} | ||
/** TODO(jacktfranklin@): Once this file is TS we can type this | ||
* using the BrowserFectcherOptions interface. | ||
*/ | ||
/** | ||
* @typedef {Object} BrowserFetcherOptions | ||
* @property {('linux'|'mac'|'win32'|'win64')=} platform | ||
* @property {('chrome'|'firefox')=} product | ||
* @property {string=} path | ||
* @property {string=} host | ||
*/ | ||
/** | ||
* @param {!BrowserFetcherOptions} options | ||
* @return {!BrowserFetcher} | ||
*/ | ||
createBrowserFetcher(options) { | ||
return new BrowserFetcher(this._projectRoot, options); | ||
return new BrowserFetcher_1.BrowserFetcher(this._projectRoot, options); | ||
} | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/camelcase | ||
__experimental_registerCustomQueryHandler(name, queryHandler) { | ||
QueryHandler.registerCustomQueryHandler(name, queryHandler); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/camelcase | ||
__experimental_unregisterCustomQueryHandler(name) { | ||
QueryHandler.unregisterCustomQueryHandler(name); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/camelcase | ||
__experimental_customQueryHandlers() { | ||
return QueryHandler.customQueryHandlers(); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/camelcase | ||
__experimental_clearQueryHandlers() { | ||
QueryHandler.clearQueryHandlers(); | ||
} | ||
} | ||
exports.Puppeteer = Puppeteer; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
/** | ||
@@ -16,21 +17,7 @@ * Copyright 2019 Google Inc. All rights reserved. | ||
*/ | ||
const { Events } = require('./Events'); | ||
const { Page } = require('./Page'); | ||
const { Worker: PuppeteerWorker } = require('./Worker'); | ||
// CDPSession is used only as a typedef | ||
// eslint-disable-next-line no-unused-vars | ||
const { CDPSession } = require('./Connection'); | ||
// This import is used as a TypeDef, but ESLint's rule doesn't | ||
// understand that unfortunately. | ||
// eslint-disable-next-line no-unused-vars | ||
const { TaskQueue } = require('./TaskQueue'); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Events_1 = require("./Events"); | ||
const Page_1 = require("./Page"); | ||
const Worker_1 = require("./Worker"); | ||
class Target { | ||
/** | ||
* @param {!Protocol.Target.TargetInfo} targetInfo | ||
* @param {!Puppeteer.BrowserContext} browserContext | ||
* @param {!function():!Promise<!CDPSession>} sessionFactory | ||
* @param {boolean} ignoreHTTPSErrors | ||
* @param {?Puppeteer.Viewport} defaultViewport | ||
* @param {!TaskQueue} screenshotTaskQueue | ||
*/ | ||
constructor(targetInfo, browserContext, sessionFactory, ignoreHTTPSErrors, defaultViewport, screenshotTaskQueue) { | ||
@@ -55,6 +42,6 @@ this._targetInfo = targetInfo; | ||
const openerPage = await opener._pagePromise; | ||
if (!openerPage.listenerCount(Events.Page.Popup)) | ||
if (!openerPage.listenerCount(Events_1.Events.Page.Popup)) | ||
return true; | ||
const popupPage = await this.page(); | ||
openerPage.emit(Events.Page.Popup, popupPage); | ||
openerPage.emit(Events_1.Events.Page.Popup, popupPage); | ||
return true; | ||
@@ -67,21 +54,12 @@ }); | ||
} | ||
/** | ||
* @return {!Promise<!CDPSession>} | ||
*/ | ||
createCDPSession() { | ||
return this._sessionFactory(); | ||
} | ||
/** | ||
* @return {!Promise<?Page>} | ||
*/ | ||
async page() { | ||
if ((this._targetInfo.type === 'page' || this._targetInfo.type === 'background_page') && !this._pagePromise) { | ||
this._pagePromise = this._sessionFactory() | ||
.then(client => Page.create(client, this, this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue)); | ||
.then(client => Page_1.Page.create(client, this, this._ignoreHTTPSErrors, this._defaultViewport, this._screenshotTaskQueue)); | ||
} | ||
return this._pagePromise; | ||
} | ||
/** | ||
* @return {!Promise<?PuppeteerWorker>} | ||
*/ | ||
async worker() { | ||
@@ -93,15 +71,9 @@ if (this._targetInfo.type !== 'service_worker' && this._targetInfo.type !== 'shared_worker') | ||
this._workerPromise = this._sessionFactory() | ||
.then(client => new PuppeteerWorker(client, this._targetInfo.url, () => { } /* consoleAPICalled */, () => { } /* exceptionThrown */)); | ||
.then(client => new Worker_1.Worker(client, this._targetInfo.url, () => { } /* consoleAPICalled */, () => { } /* exceptionThrown */)); | ||
} | ||
return this._workerPromise; | ||
} | ||
/** | ||
* @return {string} | ||
*/ | ||
url() { | ||
return this._targetInfo.url; | ||
} | ||
/** | ||
* @return {"page"|"background_page"|"service_worker"|"shared_worker"|"other"|"browser"} | ||
*/ | ||
type() { | ||
@@ -113,17 +85,8 @@ const type = this._targetInfo.type; | ||
} | ||
/** | ||
* @return {!Puppeteer.Browser} | ||
*/ | ||
browser() { | ||
return this._browserContext.browser(); | ||
} | ||
/** | ||
* @return {!Puppeteer.BrowserContext} | ||
*/ | ||
browserContext() { | ||
return this._browserContext; | ||
} | ||
/** | ||
* @return {?Puppeteer.Target} | ||
*/ | ||
opener() { | ||
@@ -135,5 +98,2 @@ const { openerId } = this._targetInfo; | ||
} | ||
/** | ||
* @param {!Protocol.Target.TargetInfo} targetInfo | ||
*/ | ||
_targetInfoChanged(targetInfo) { | ||
@@ -148,2 +108,2 @@ this._targetInfo = targetInfo; | ||
} | ||
module.exports = { Target }; | ||
exports.Target = Target; |
@@ -17,2 +17,3 @@ "use strict"; | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* TODO(jacktfranklin@): once we are calling this from TS files we can | ||
@@ -33,2 +34,2 @@ * avoid the horrible void | any type and instead make use of generics | ||
} | ||
module.exports = { TaskQueue }; | ||
exports.TaskQueue = TaskQueue; |
@@ -17,2 +17,3 @@ "use strict"; | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const DEFAULT_TIMEOUT = 30000; | ||
@@ -46,2 +47,2 @@ class TimeoutSettings { | ||
} | ||
module.exports = { TimeoutSettings }; | ||
exports.TimeoutSettings = TimeoutSettings; |
{ | ||
"name": "puppeteer-core", | ||
"version": "3.0.2", | ||
"version": "3.0.3", | ||
"description": "A high-level API to control headless Chrome over the DevTools Protocol", | ||
@@ -16,3 +16,4 @@ "main": "index.js", | ||
"unit": "mocha --config mocha-config/puppeteer-unit-tests.js", | ||
"coverage": "cross-env COVERAGE=1 npm run unit", | ||
"unit-with-coverage": "cross-env COVERAGE=1 npm run unit", | ||
"assert-unit-coverage": "cross-env COVERAGE=1 mocha --config mocha-config/coverage-tests.js", | ||
"funit": "PUPPETEER_PRODUCT=firefox npm run unit", | ||
@@ -28,6 +29,7 @@ "debug-unit": "node --inspect-brk test/test.js", | ||
"doc": "node utils/doclint/cli.js", | ||
"tsc": "tsc --version && tsc -p . && cp src/protocol.d.ts lib/ && cp src/externs.d.ts lib/", | ||
"tsc": "tsc --version && tsc -p . && cp src/protocol.d.ts lib/", | ||
"apply-next-version": "node utils/apply_next_version.js", | ||
"test-types": "node utils/doclint/generate_types && tsc --version && tsc -p utils/doclint/generate_types/test/", | ||
"update-protocol-d-ts": "node utils/protocol-types-generator", | ||
"update-protocol-d-ts": "node utils/protocol-types-generator update", | ||
"compare-protocol-d-ts": "node utils/protocol-types-generator compare", | ||
"test-install": "scripts/test-install.sh" | ||
@@ -72,2 +74,3 @@ }, | ||
"eslint-plugin-mocha": "^6.3.0", | ||
"eslint-plugin-unicorn": "^19.0.1", | ||
"esprima": "^4.0.0", | ||
@@ -74,0 +77,0 @@ "expect": "^25.2.7", |
@@ -9,3 +9,3 @@ # Puppeteer | ||
###### [API](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/master/docs/troubleshooting.md) | ||
###### [API](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/master/docs/troubleshooting.md) | ||
@@ -41,3 +41,3 @@ > Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium. | ||
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#environment-variables). | ||
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#environment-variables). | ||
@@ -68,3 +68,3 @@ | ||
Puppeteer will be familiar to people using other browser testing frameworks. You create an instance | ||
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#). | ||
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#). | ||
@@ -94,3 +94,3 @@ **Example** - navigating to https://example.com and saving a screenshot as *example.png*: | ||
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#pagesetviewportviewport). | ||
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#pagesetviewportviewport). | ||
@@ -120,3 +120,3 @@ **Example** - create a PDF. | ||
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#pagepdfoptions) for more information about creating pdfs. | ||
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#pagepdfoptions) for more information about creating pdfs. | ||
@@ -156,3 +156,3 @@ **Example** - evaluate script in the context of the page | ||
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`. | ||
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`. | ||
@@ -166,3 +166,3 @@ <!-- [END getstarted] --> | ||
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#puppeteerlaunchoptions) when launching a browser: | ||
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#puppeteerlaunchoptions) when launching a browser: | ||
@@ -183,3 +183,3 @@ ```js | ||
You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#puppeteerlaunchoptions) for more information. | ||
You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#puppeteerlaunchoptions) for more information. | ||
@@ -196,3 +196,3 @@ 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/+/master/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users. | ||
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md) | ||
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md) | ||
- [Examples](https://github.com/puppeteer/puppeteer/tree/master/examples/) | ||
@@ -210,3 +210,5 @@ - [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer) | ||
const browser = await puppeteer.launch({headless: false}); | ||
```js | ||
const browser = await puppeteer.launch({headless: false}); | ||
``` | ||
@@ -216,6 +218,8 @@ 2. Slow it down - the `slowMo` option slows down Puppeteer operations by the | ||
const browser = await puppeteer.launch({ | ||
headless: false, | ||
slowMo: 250 // slow down by 250ms | ||
}); | ||
```js | ||
const browser = await puppeteer.launch({ | ||
headless: false, | ||
slowMo: 250 // slow down by 250ms | ||
}); | ||
``` | ||
@@ -225,5 +229,7 @@ 3. Capture console output - You can listen for the `console` event. | ||
page.on('console', msg => console.log('PAGE LOG:', msg.text())); | ||
```js | ||
page.on('console', msg => console.log('PAGE LOG:', msg.text())); | ||
await page.evaluate(() => console.log(`url is ${location.href}`)); | ||
await page.evaluate(() => console.log(`url is ${location.href}`)); | ||
``` | ||
@@ -238,3 +244,5 @@ 4. Use debugger in application code browser | ||
`const browser = await puppeteer.launch({devtools: true});` | ||
```js | ||
const browser = await puppeteer.launch({devtools: true}); | ||
``` | ||
@@ -251,3 +259,5 @@ - Change default test timeout: | ||
`await page.evaluate(() => {debugger;});` | ||
```js | ||
await page.evaluate(() => {debugger;}); | ||
``` | ||
@@ -265,6 +275,8 @@ The test will now stop executing in the above evaluate statement, and chromium will stop in debug mode. | ||
- Add `debugger;` to your test, eg: | ||
``` | ||
```js | ||
debugger; | ||
await page.click('a[target=_blank]'); | ||
``` | ||
- Set `headless` to `false` | ||
@@ -318,3 +330,3 @@ - Run `node --inspect-brk`, eg `node --inspect-brk node_modules/.bin/jest tests` | ||
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox. | ||
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox. | ||
@@ -415,3 +427,3 @@ We will continue to collaborate with other browser vendors to bring Puppeteer support to browsers such as Safari. | ||
* Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v3.0.2/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.) | ||
* Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v3.0.3/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.) | ||
* Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming). | ||
@@ -418,0 +430,0 @@ |
@@ -40,4 +40,4 @@ /** | ||
async function compileTypeScript() { | ||
return exec('npm run tsc').catch(err => { | ||
console.error('Error running TypeScript', err); | ||
return exec('npm run tsc').catch(error => { | ||
console.error('Error running TypeScript', error); | ||
process.exit(1); | ||
@@ -44,0 +44,0 @@ }); |
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
43
438
12
888443
23
22913