react-h2p-puppeteer
Version:
just the puppeteer package used in react-h2p
1,910 lines (1,829 loc) • 64.8 kB
JavaScript
/**
* 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.
*/
const fs = require('fs');
const EventEmitter = require('events');
const mime = require('mime');
const {NetworkManager} = require('./NetworkManager');
const {NavigatorWatcher} = require('./NavigatorWatcher');
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} = require('./Worker');
const writeFileAsync = helper.promisify(fs.writeFile);
class Page extends EventEmitter {
/**
* @param {!Puppeteer.CDPSession} client
* @param {!Puppeteer.Target} target
* @param {boolean} ignoreHTTPSErrors
* @param {?Puppeteer.Viewport} defaultViewport
* @param {!Puppeteer.TaskQueue} screenshotTaskQueue
* @return {!Promise<!Page>}
*/
static /* async */ create(client, target, ignoreHTTPSErrors, defaultViewport, screenshotTaskQueue) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield client.send('Page.enable'));
const {frameTree} = (yield client.send('Page.getFrameTree'));
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
(yield Promise.all([
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false}),
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
client.send('Network.enable', {}),
client.send('Runtime.enable', {}),
client.send('Security.enable', {}),
client.send('Performance.enable', {}),
client.send('Log.enable', {}),
]));
if (ignoreHTTPSErrors)
(yield client.send('Security.setOverrideCertificateErrors', {override: true}));
// Initialize default page size.
if (defaultViewport)
(yield page.setViewport(defaultViewport));
return page;
});}
/**
* @param {!Puppeteer.CDPSession} client
* @param {!Puppeteer.Target} target
* @param {!Protocol.Page.FrameTree} frameTree
* @param {boolean} ignoreHTTPSErrors
* @param {!Puppeteer.TaskQueue} screenshotTaskQueue
*/
constructor(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue) {
super();
this._closed = false;
this._client = client;
this._target = target;
this._keyboard = new Keyboard(client);
this._mouse = new Mouse(client, this._keyboard);
this._touchscreen = new Touchscreen(client, this._keyboard);
/** @type {!FrameManager} */
this._frameManager = new FrameManager(client, frameTree, this);
this._networkManager = new NetworkManager(client, this._frameManager);
this._emulationManager = new EmulationManager(client);
this._tracing = new Tracing(client);
/** @type {!Map<string, Function>} */
this._pageBindings = new Map();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._coverage = new Coverage(client);
this._defaultNavigationTimeout = 30000;
this._javascriptEnabled = true;
/** @type {?Puppeteer.Viewport} */
this._viewport = null;
this._screenshotTaskQueue = screenshotTaskQueue;
/** @type {!Map<string, Worker>} */
this._workers = new Map();
client.on('Target.attachedToTarget', event => {
if (event.targetInfo.type !== 'worker') {
// If we don't detach from service workers, they will never die.
client.send('Target.detachFromTarget', {
sessionId: event.sessionId
}).catch(debugError);
return;
}
const session = client._createSession(event.targetInfo.type, event.sessionId);
const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this._workers.set(event.sessionId, worker);
this.emit(Page.Events.WorkerCreated, worker);
});
client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId);
if (!worker)
return;
this.emit(Page.Events.WorkerDestroyed, worker);
this._workers.delete(event.sessionId);
});
this._frameManager.on(FrameManager.Events.FrameAttached, event => this.emit(Page.Events.FrameAttached, event));
this._frameManager.on(FrameManager.Events.FrameDetached, event => this.emit(Page.Events.FrameDetached, event));
this._frameManager.on(FrameManager.Events.FrameNavigated, event => this.emit(Page.Events.FrameNavigated, event));
this._networkManager.on(NetworkManager.Events.Request, event => this.emit(Page.Events.Request, event));
this._networkManager.on(NetworkManager.Events.Response, event => this.emit(Page.Events.Response, event));
this._networkManager.on(NetworkManager.Events.RequestFailed, event => this.emit(Page.Events.RequestFailed, event));
this._networkManager.on(NetworkManager.Events.RequestFinished, event => this.emit(Page.Events.RequestFinished, event));
client.on('Page.domContentEventFired', event => this.emit(Page.Events.DOMContentLoaded));
client.on('Page.loadEventFired', event => this.emit(Page.Events.Load));
client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
client.on('Security.certificateError', event => this._onCertificateError(event));
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
client.on('Performance.metrics', event => this._emitMetrics(event));
client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
this._target._isClosedPromise.then(() => {
this.emit(Page.Events.Close);
this._closed = true;
});
}
/**
* @return {!Puppeteer.Target}
*/
target() {
return this._target;
}
/**
* @return {!Puppeteer.Browser}
*/
browser() {
return this._target.browser();
}
_onTargetCrashed() {
this.emit('error', new Error('Page crashed!'));
}
/**
* @param {!Protocol.Log.entryAddedPayload} event
*/
_onLogEntryAdded(event) {
const {level, text, args, source} = event.entry;
if (args)
args.map(arg => helper.releaseObject(this._client, arg));
if (source !== 'worker')
this.emit(Page.Events.Console, new ConsoleMessage(level, text));
}
/**
* @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 {!Array<Puppeteer.Frame>}
*/
frames() {
return this._frameManager.frames();
}
/**
* @return {!Array<!Worker>}
*/
workers() {
return Array.from(this._workers.values());
}
/**
* @param {boolean} value
*/
/* async */ setRequestInterception(value) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._networkManager.setRequestInterception(value);
});}
/**
* @param {boolean} enabled
*/
setOfflineMode(enabled) {
return this._networkManager.setOfflineMode(enabled);
}
/**
* @param {number} timeout
*/
setDefaultNavigationTimeout(timeout) {
this._defaultNavigationTimeout = timeout;
}
/**
* @param {!Protocol.Security.certificateErrorPayload} event
*/
_onCertificateError(event) {
if (!this._ignoreHTTPSErrors)
return;
this._client.send('Security.handleCertificateError', {
eventId: event.eventId,
action: 'continue'
}).catch(debugError);
}
/**
* @param {string} selector
* @return {!Promise<?Puppeteer.ElementHandle>}
*/
/* async */ $(selector) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().$(selector);
});}
/**
* @param {function()|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<!Puppeteer.JSHandle>}
*/
/* async */ evaluateHandle(pageFunction, ...args) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const context = (yield this.mainFrame().executionContext());
return context.evaluateHandle(pageFunction, ...args);
});}
/**
* @param {!Puppeteer.JSHandle} prototypeHandle
* @return {!Promise<!Puppeteer.JSHandle>}
*/
/* async */ queryObjects(prototypeHandle) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const context = (yield this.mainFrame().executionContext());
return context.queryObjects(prototypeHandle);
});}
/**
* @param {string} selector
* @param {function()|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<(!Object|undefined)>}
*/
/* async */ $eval(selector, pageFunction, ...args) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
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 (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().$$eval(selector, pageFunction, ...args);
});}
/**
* @param {string} selector
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
*/
/* async */ $$(selector) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().$$(selector);
});}
/**
* @param {string} expression
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
*/
/* async */ $x(expression) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().$x(expression);
});}
/**
* @param {!Array<string>} urls
* @return {!Promise<!Array<Network.Cookie>>}
*/
/* async */ cookies(...urls) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return ((yield this._client.send('Network.getCookies', {
urls: urls.length ? urls : [this.url()]
}))).cookies;
});}
/**
* @param {Array<Network.CookieParam>} cookies
*/
/* async */ deleteCookie(...cookies) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const pageURL = this.url();
for (const cookie of cookies) {
const item = Object.assign({}, cookie);
if (!cookie.url && pageURL.startsWith('http'))
item.url = pageURL;
(yield this._client.send('Network.deleteCookies', item));
}
});}
/**
* @param {Array<Network.CookieParam>} cookies
*/
/* async */ setCookie(...cookies) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const pageURL = this.url();
const startsWithHTTP = pageURL.startsWith('http');
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
if (!item.url && startsWithHTTP)
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}"`
);
return item;
});
(yield this.deleteCookie(...items));
if (items.length)
(yield this._client.send('Network.setCookies', { cookies: items }));
});}
/**
* @param {Object} options
* @return {!Promise<!Puppeteer.ElementHandle>}
*/
/* async */ addScriptTag(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().addScriptTag(options);
});}
/**
* @param {Object} options
* @return {!Promise<!Puppeteer.ElementHandle>}
*/
/* async */ addStyleTag(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this.mainFrame().addStyleTag(options);
});}
/**
* @param {string} name
* @param {function(?)} puppeteerFunction
*/
/* async */ exposeFunction(name, puppeteerFunction) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
if (this._pageBindings.has(name))
throw new Error(`Failed to add page binding with name ${name}: window['${name}'] already exists!`);
this._pageBindings.set(name, puppeteerFunction);
const expression = helper.evaluationString(addPageBinding, name);
(yield this._client.send('Runtime.addBinding', {name: name}));
(yield this._client.send('Page.addScriptToEvaluateOnNewDocument', {source: expression}));
(yield Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(debugError))));
function addPageBinding(bindingName) {
const binding = window[bindingName];
window[bindingName] = /* async */(...args) => {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const me = window[bindingName];
let callbacks = me['callbacks'];
if (!callbacks) {
callbacks = new Map();
me['callbacks'] = callbacks;
}
const seq = (me['lastSeq'] || 0) + 1;
me['lastSeq'] = seq;
const promise = new Promise(fulfill => callbacks.set(seq, fulfill));
binding(JSON.stringify({name: bindingName, seq, args}));
return promise;
});};
}
});}
/**
* @param {?{username: string, password: string}} credentials
*/
/* async */ authenticate(credentials) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._networkManager.authenticate(credentials);
});}
/**
* @param {!Object<string, string>} headers
*/
/* async */ setExtraHTTPHeaders(headers) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._networkManager.setExtraHTTPHeaders(headers);
});}
/**
* @param {string} userAgent
*/
/* async */ setUserAgent(userAgent) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._networkManager.setUserAgent(userAgent);
});}
/**
* @return {!Promise<!Object>}
*/
/* async */ metrics() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const response = (yield this._client.send('Performance.getMetrics'));
return this._buildMetricsObject(response.metrics);
});}
/**
* @param {*} event
*/
_emitMetrics(event) {
this.emit(Page.Events.Metrics, {
title: event.title,
metrics: this._buildMetricsObject(event.metrics)
});
}
/**
* @param {?Array<!Protocol.Performance.Metric>} metrics
* @return {!Object}
*/
_buildMetricsObject(metrics) {
const result = {};
for (const metric of metrics || []) {
if (supportedMetrics.has(metric.name))
result[metric.name] = metric.value;
}
return result;
}
/**
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
*/
_handleException(exceptionDetails) {
const message = helper.getExceptionMessage(exceptionDetails);
const err = new Error(message);
err.stack = ''; // Don't report clientside error with a node stack attached
this.emit(Page.Events.PageError, err);
}
/**
* @param {!Protocol.Runtime.consoleAPICalledPayload} event
*/
/* async */ _onConsoleAPI(event) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const context = this._frameManager.executionContextById(event.executionContextId);
const values = event.args.map(arg => this._frameManager.createJSHandle(context, arg));
this._addConsoleMessage(event.type, values);
});}
/**
* @param {!Protocol.Runtime.bindingCalledPayload} event
*/
/* async */ _onBindingCalled(event) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const {name, seq, args} = JSON.parse(event.payload);
const result = (yield this._pageBindings.get(name)(...args));
const expression = helper.evaluationString(deliverResult, name, seq, result);
this._client.send('Runtime.evaluate', { expression, contextId: event.executionContextId }).catch(debugError);
function deliverResult(name, seq, result) {
window[name]['callbacks'].get(seq)(result);
window[name]['callbacks'].delete(seq);
}
});}
/**
* @param {string} type
* @param {!Array<!Puppeteer.JSHandle>} args
*/
_addConsoleMessage(type, args) {
if (!this.listenerCount(Page.Events.Console)) {
args.forEach(arg => arg.dispose());
return;
}
const textTokens = [];
for (const arg of args) {
const remoteObject = arg._remoteObject;
if (remoteObject.objectId)
textTokens.push(arg.toString());
else
textTokens.push(helper.valueFromRemoteObject(remoteObject));
}
const message = new ConsoleMessage(type, textTokens.join(' '), args);
this.emit(Page.Events.Console, message);
}
_onDialog(event) {
let dialogType = null;
if (event.type === 'alert')
dialogType = Dialog.Type.Alert;
else if (event.type === 'confirm')
dialogType = Dialog.Type.Confirm;
else if (event.type === 'prompt')
dialogType = 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(Page.Events.Dialog, dialog);
}
/**
* @return {!string}
*/
url() {
return this.mainFrame().url();
}
/**
* @return {!Promise<String>}
*/
/* async */ content() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return (yield this._frameManager.mainFrame().content());
});}
/**
* @param {string} html
*/
/* async */ setContent(html) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._frameManager.mainFrame().setContent(html));
});}
/**
* @param {string} url
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ goto(url, options = {}) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const referrer = this._networkManager.extraHTTPHeaders()['referer'];
/** @type {Map<string, !Puppeteer.Request>} */
const requests = new Map();
const eventListeners = [
helper.addEventListener(this._networkManager, NetworkManager.Events.Request, request => {
if (!requests.get(request.url()))
requests.set(request.url(), request);
})
];
const mainFrame = this._frameManager.mainFrame();
const timeout = typeof options.timeout === 'number' ? options.timeout : this._defaultNavigationTimeout;
const watcher = new NavigatorWatcher(this._frameManager, mainFrame, timeout, options);
const navigationPromise = watcher.navigationPromise();
let error = (yield Promise.race([
navigate(this._client, url, referrer),
navigationPromise,
]));
if (!error)
error = (yield navigationPromise);
watcher.cancel();
helper.removeEventListeners(eventListeners);
if (error)
throw error;
const request = requests.get(mainFrame._navigationURL);
return request ? request.response() : null;
/**
* @param {!Puppeteer.CDPSession} client
* @param {string} url
* @param {string} referrer
* @return {!Promise<?Error>}
*/
/* async */ function navigate(client, url, referrer) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
try {
const response = (yield client.send('Page.navigate', {url, referrer}));
return response.errorText ? new Error(`${response.errorText} at ${url}`) : null;
} catch (error) {
return error;
}
});}
});}
/**
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ reload(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const [response] = (yield Promise.all([
this.waitForNavigation(options),
this._client.send('Page.reload')
]));
return response;
});}
/**
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ waitForNavigation(options = {}) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const mainFrame = this._frameManager.mainFrame();
const timeout = typeof options.timeout === 'number' ? options.timeout : this._defaultNavigationTimeout;
const watcher = new NavigatorWatcher(this._frameManager, mainFrame, timeout, options);
const responses = new Map();
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url(), response));
const error = (yield watcher.navigationPromise());
helper.removeEventListeners([listener]);
if (error)
throw error;
return responses.get(this.mainFrame().url()) || null;
});}
/**
* @param {(string|Function)} urlOrPredicate
* @param {!Object=} options
* @return {!Promise<!Puppeteer.Request>}
*/
/* async */ waitForRequest(urlOrPredicate, options = {}) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const timeout = typeof options.timeout === 'number' ? options.timeout : 30000;
return helper.waitForEvent(this._networkManager, NetworkManager.Events.Request, request => {
if (helper.isString(urlOrPredicate))
return (urlOrPredicate === request.url());
if (typeof urlOrPredicate === 'function')
return !!(urlOrPredicate(request));
return false;
}, timeout);
});}
/**
* @param {(string|Function)} urlOrPredicate
* @param {!Object=} options
* @return {!Promise<!Puppeteer.Response>}
*/
/* async */ waitForResponse(urlOrPredicate, options = {}) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const timeout = typeof options.timeout === 'number' ? options.timeout : 30000;
return helper.waitForEvent(this._networkManager, NetworkManager.Events.Response, response => {
if (helper.isString(urlOrPredicate))
return (urlOrPredicate === response.url());
if (typeof urlOrPredicate === 'function')
return !!(urlOrPredicate(response));
return false;
}, timeout);
});}
/**
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ goBack(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._go(-1, options);
});}
/**
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ goForward(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._go(+1, options);
});}
/**
* @param {!Object=} options
* @return {!Promise<?Puppeteer.Response>}
*/
/* async */ _go(delta, options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const history = (yield this._client.send('Page.getNavigationHistory'));
const entry = history.entries[history.currentIndex + delta];
if (!entry)
return null;
const [response] = (yield Promise.all([
this.waitForNavigation(options),
this._client.send('Page.navigateToHistoryEntry', {entryId: entry.id}),
]));
return response;
});}
/* async */ bringToFront() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._client.send('Page.bringToFront'));
});}
/**
* @param {!Object} options
*/
/* async */ emulate(options) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return Promise.all([
this.setViewport(options.viewport),
this.setUserAgent(options.userAgent)
]);
});}
/**
* @param {boolean} enabled
*/
/* async */ setJavaScriptEnabled(enabled) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
if (this._javascriptEnabled === enabled)
return;
this._javascriptEnabled = enabled;
(yield this._client.send('Emulation.setScriptExecutionDisabled', { value: !enabled }));
});}
/**
* @param {boolean} enabled
*/
/* async */ setBypassCSP(enabled) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._client.send('Page.setBypassCSP', { enabled }));
});}
/**
* @param {?string} mediaType
*/
/* async */ emulateMedia(mediaType) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
assert(mediaType === 'screen' || mediaType === 'print' || mediaType === null, 'Unsupported media type: ' + mediaType);
(yield this._client.send('Emulation.setEmulatedMedia', {media: mediaType || ''}));
});}
/**
* @param {!Puppeteer.Viewport} viewport
*/
/* async */ setViewport(viewport) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const needsReload = (yield this._emulationManager.emulateViewport(viewport));
this._viewport = viewport;
if (needsReload)
(yield this.reload());
});}
/**
* @return {?Puppeteer.Viewport}
*/
viewport() {
return this._viewport;
}
/**
* @param {function()|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<*>}
*/
/* async */ evaluate(pageFunction, ...args) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
return this._frameManager.mainFrame().evaluate(pageFunction, ...args);
});}
/**
* @param {function()|string} pageFunction
* @param {!Array<*>} args
*/
/* async */ evaluateOnNewDocument(pageFunction, ...args) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const source = helper.evaluationString(pageFunction, ...args);
(yield this._client.send('Page.addScriptToEvaluateOnNewDocument', { source }));
});}
/**
* @param {Boolean} enabled
* @returns {!Promise}
*/
/* async */ setCacheEnabled(enabled = true) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._client.send('Network.setCacheDisabled', {cacheDisabled: !enabled}));
});}
/**
* @param {!Object=} options
* @return {!Promise<!Buffer|!String>}
*/
/* async */ screenshot(options = {}) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
let screenshotType = null;
// options.type takes precedence over inferring the type from options.path
// b