487 lines
16 KiB
JavaScript
487 lines
16 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.prepareBrowserContextParams = prepareBrowserContextParams;
|
|
exports.BrowserContext = void 0;
|
|
|
|
var _page = require("./page");
|
|
|
|
var _frame = require("./frame");
|
|
|
|
var network = _interopRequireWildcard(require("./network"));
|
|
|
|
var _fs = _interopRequireDefault(require("fs"));
|
|
|
|
var _channelOwner = require("./channelOwner");
|
|
|
|
var _clientHelper = require("./clientHelper");
|
|
|
|
var _browser = require("./browser");
|
|
|
|
var _worker = require("./worker");
|
|
|
|
var _events = require("./events");
|
|
|
|
var _timeoutSettings = require("../utils/timeoutSettings");
|
|
|
|
var _waiter = require("./waiter");
|
|
|
|
var _utils = require("../utils/utils");
|
|
|
|
var _errors = require("../utils/errors");
|
|
|
|
var _cdpSession = require("./cdpSession");
|
|
|
|
var _tracing = require("./tracing");
|
|
|
|
var _artifact = require("./artifact");
|
|
|
|
var _fetch = require("./fetch");
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
|
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
|
|
/**
|
|
* Copyright 2017 Google Inc. All rights reserved.
|
|
* Modifications copyright (c) Microsoft Corporation.
|
|
*
|
|
* 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.
|
|
*/
|
|
class BrowserContext extends _channelOwner.ChannelOwner {
|
|
static from(context) {
|
|
return context._object;
|
|
}
|
|
|
|
static fromNullable(context) {
|
|
return context ? BrowserContext.from(context) : null;
|
|
}
|
|
|
|
constructor(parent, type, guid, initializer) {
|
|
var _this$_browser;
|
|
|
|
super(parent, type, guid, initializer);
|
|
this._pages = new Set();
|
|
this._routes = [];
|
|
this._browser = null;
|
|
this._browserType = void 0;
|
|
this._bindings = new Map();
|
|
this._timeoutSettings = new _timeoutSettings.TimeoutSettings();
|
|
this._ownerPage = void 0;
|
|
this._closedPromise = void 0;
|
|
this._options = {};
|
|
this._request = void 0;
|
|
this.tracing = void 0;
|
|
this._backgroundPages = new Set();
|
|
this._serviceWorkers = new Set();
|
|
this._isChromium = void 0;
|
|
if (parent instanceof _browser.Browser) this._browser = parent;
|
|
this._isChromium = ((_this$_browser = this._browser) === null || _this$_browser === void 0 ? void 0 : _this$_browser._name) === 'chromium';
|
|
this.tracing = new _tracing.Tracing(this);
|
|
this._request = _fetch.FetchRequest.from(initializer.fetchRequest);
|
|
|
|
this._channel.on('bindingCall', ({
|
|
binding
|
|
}) => this._onBinding(_page.BindingCall.from(binding)));
|
|
|
|
this._channel.on('close', () => this._onClose());
|
|
|
|
this._channel.on('page', ({
|
|
page
|
|
}) => this._onPage(_page.Page.from(page)));
|
|
|
|
this._channel.on('route', ({
|
|
route,
|
|
request
|
|
}) => this._onRoute(network.Route.from(route), network.Request.from(request)));
|
|
|
|
this._channel.on('backgroundPage', ({
|
|
page
|
|
}) => {
|
|
const backgroundPage = _page.Page.from(page);
|
|
|
|
this._backgroundPages.add(backgroundPage);
|
|
|
|
this.emit(_events.Events.BrowserContext.BackgroundPage, backgroundPage);
|
|
});
|
|
|
|
this._channel.on('serviceWorker', ({
|
|
worker
|
|
}) => {
|
|
const serviceWorker = _worker.Worker.from(worker);
|
|
|
|
serviceWorker._context = this;
|
|
|
|
this._serviceWorkers.add(serviceWorker);
|
|
|
|
this.emit(_events.Events.BrowserContext.ServiceWorker, serviceWorker);
|
|
});
|
|
|
|
this._channel.on('request', ({
|
|
request,
|
|
page
|
|
}) => this._onRequest(network.Request.from(request), _page.Page.fromNullable(page)));
|
|
|
|
this._channel.on('requestFailed', ({
|
|
request,
|
|
failureText,
|
|
responseEndTiming,
|
|
page
|
|
}) => this._onRequestFailed(network.Request.from(request), responseEndTiming, failureText, _page.Page.fromNullable(page)));
|
|
|
|
this._channel.on('requestFinished', params => this._onRequestFinished(params));
|
|
|
|
this._channel.on('response', ({
|
|
response,
|
|
page
|
|
}) => this._onResponse(network.Response.from(response), _page.Page.fromNullable(page)));
|
|
|
|
this._closedPromise = new Promise(f => this.once(_events.Events.BrowserContext.Close, f));
|
|
}
|
|
|
|
_setBrowserType(browserType) {
|
|
this._browserType = browserType;
|
|
|
|
browserType._contexts.add(this);
|
|
}
|
|
|
|
_onPage(page) {
|
|
this._pages.add(page);
|
|
|
|
this.emit(_events.Events.BrowserContext.Page, page);
|
|
if (page._opener && !page._opener.isClosed()) page._opener.emit(_events.Events.Page.Popup, page);
|
|
}
|
|
|
|
_onRequest(request, page) {
|
|
this.emit(_events.Events.BrowserContext.Request, request);
|
|
if (page) page.emit(_events.Events.Page.Request, request);
|
|
}
|
|
|
|
_onResponse(response, page) {
|
|
this.emit(_events.Events.BrowserContext.Response, response);
|
|
if (page) page.emit(_events.Events.Page.Response, response);
|
|
}
|
|
|
|
_onRequestFailed(request, responseEndTiming, failureText, page) {
|
|
request._failureText = failureText || null;
|
|
if (request._timing) request._timing.responseEnd = responseEndTiming;
|
|
this.emit(_events.Events.BrowserContext.RequestFailed, request);
|
|
if (page) page.emit(_events.Events.Page.RequestFailed, request);
|
|
}
|
|
|
|
_onRequestFinished(params) {
|
|
const {
|
|
responseEndTiming
|
|
} = params;
|
|
const request = network.Request.from(params.request);
|
|
const response = network.Response.fromNullable(params.response);
|
|
|
|
const page = _page.Page.fromNullable(params.page);
|
|
|
|
if (request._timing) request._timing.responseEnd = responseEndTiming;
|
|
this.emit(_events.Events.BrowserContext.RequestFinished, request);
|
|
if (page) page.emit(_events.Events.Page.RequestFinished, request);
|
|
if (response) response._finishedPromise.resolve();
|
|
}
|
|
|
|
_onRoute(route, request) {
|
|
for (const routeHandler of this._routes) {
|
|
if (routeHandler.matches(request.url())) {
|
|
routeHandler.handle(route, request);
|
|
return;
|
|
}
|
|
} // it can race with BrowserContext.close() which then throws since its closed
|
|
|
|
|
|
route.continue().catch(() => {});
|
|
}
|
|
|
|
async _onBinding(bindingCall) {
|
|
const func = this._bindings.get(bindingCall._initializer.name);
|
|
|
|
if (!func) return;
|
|
await bindingCall.call(func);
|
|
}
|
|
|
|
setDefaultNavigationTimeout(timeout) {
|
|
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
|
|
|
this._channel.setDefaultNavigationTimeoutNoReply({
|
|
timeout
|
|
});
|
|
}
|
|
|
|
setDefaultTimeout(timeout) {
|
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
|
|
|
this._channel.setDefaultTimeoutNoReply({
|
|
timeout
|
|
});
|
|
}
|
|
|
|
browser() {
|
|
return this._browser;
|
|
}
|
|
|
|
pages() {
|
|
return [...this._pages];
|
|
}
|
|
|
|
async newPage() {
|
|
return this._wrapApiCall(async channel => {
|
|
if (this._ownerPage) throw new Error('Please use browser.newContext()');
|
|
return _page.Page.from((await channel.newPage()).page);
|
|
});
|
|
}
|
|
|
|
async cookies(urls) {
|
|
if (!urls) urls = [];
|
|
if (urls && typeof urls === 'string') urls = [urls];
|
|
return this._wrapApiCall(async channel => {
|
|
return (await channel.cookies({
|
|
urls: urls
|
|
})).cookies;
|
|
});
|
|
}
|
|
|
|
async addCookies(cookies) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.addCookies({
|
|
cookies
|
|
});
|
|
});
|
|
}
|
|
|
|
async clearCookies() {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.clearCookies();
|
|
});
|
|
}
|
|
|
|
async grantPermissions(permissions, options) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.grantPermissions({
|
|
permissions,
|
|
...options
|
|
});
|
|
});
|
|
}
|
|
|
|
async clearPermissions() {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.clearPermissions();
|
|
});
|
|
}
|
|
|
|
async setGeolocation(geolocation) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.setGeolocation({
|
|
geolocation: geolocation || undefined
|
|
});
|
|
});
|
|
}
|
|
|
|
async setExtraHTTPHeaders(headers) {
|
|
return this._wrapApiCall(async channel => {
|
|
network.validateHeaders(headers);
|
|
await channel.setExtraHTTPHeaders({
|
|
headers: (0, _utils.headersObjectToArray)(headers)
|
|
});
|
|
});
|
|
}
|
|
|
|
async setOffline(offline) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.setOffline({
|
|
offline
|
|
});
|
|
});
|
|
}
|
|
|
|
async setHTTPCredentials(httpCredentials) {
|
|
if (!(0, _utils.isUnderTest)()) (0, _clientHelper.deprecate)(`context.setHTTPCredentials`, `warning: method |context.setHTTPCredentials()| is deprecated. Instead of changing credentials, create another browser context with new credentials.`);
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.setHTTPCredentials({
|
|
httpCredentials: httpCredentials || undefined
|
|
});
|
|
});
|
|
}
|
|
|
|
async addInitScript(script, arg) {
|
|
return this._wrapApiCall(async channel => {
|
|
const source = await (0, _clientHelper.evaluationScript)(script, arg);
|
|
await channel.addInitScript({
|
|
source
|
|
});
|
|
});
|
|
}
|
|
|
|
async exposeBinding(name, callback, options = {}) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.exposeBinding({
|
|
name,
|
|
needsHandle: options.handle
|
|
});
|
|
|
|
this._bindings.set(name, callback);
|
|
});
|
|
}
|
|
|
|
async exposeFunction(name, callback) {
|
|
return this._wrapApiCall(async channel => {
|
|
await channel.exposeBinding({
|
|
name
|
|
});
|
|
|
|
const binding = (source, ...args) => callback(...args);
|
|
|
|
this._bindings.set(name, binding);
|
|
});
|
|
}
|
|
|
|
async route(url, handler, options = {}) {
|
|
return this._wrapApiCall(async channel => {
|
|
this._routes.unshift(new network.RouteHandler(this._options.baseURL, url, handler, options.times));
|
|
|
|
if (this._routes.length === 1) await channel.setNetworkInterceptionEnabled({
|
|
enabled: true
|
|
});
|
|
});
|
|
}
|
|
|
|
async unroute(url, handler) {
|
|
return this._wrapApiCall(async channel => {
|
|
this._routes = this._routes.filter(route => route.url !== url || handler && route.handler !== handler);
|
|
if (this._routes.length === 0) await channel.setNetworkInterceptionEnabled({
|
|
enabled: false
|
|
});
|
|
});
|
|
}
|
|
|
|
async waitForEvent(event, optionsOrPredicate = {}) {
|
|
return this._wrapApiCall(async channel => {
|
|
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
|
|
|
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
|
|
|
const waiter = _waiter.Waiter.createForEvent(this, event);
|
|
|
|
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
|
if (event !== _events.Events.BrowserContext.Close) waiter.rejectOnEvent(this, _events.Events.BrowserContext.Close, new Error('Context closed'));
|
|
const result = await waiter.waitForEvent(this, event, predicate);
|
|
waiter.dispose();
|
|
return result;
|
|
});
|
|
}
|
|
|
|
async storageState(options = {}) {
|
|
return await this._wrapApiCall(async channel => {
|
|
const state = await channel.storageState();
|
|
|
|
if (options.path) {
|
|
await (0, _utils.mkdirIfNeeded)(options.path);
|
|
await _fs.default.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
|
}
|
|
|
|
return state;
|
|
});
|
|
}
|
|
|
|
backgroundPages() {
|
|
return [...this._backgroundPages];
|
|
}
|
|
|
|
serviceWorkers() {
|
|
return [...this._serviceWorkers];
|
|
}
|
|
|
|
async newCDPSession(page) {
|
|
// channelOwner.ts's validation messages don't handle the pseudo-union type, so we're explicit here
|
|
if (!(page instanceof _page.Page) && !(page instanceof _frame.Frame)) throw new Error('page: expected Page or Frame');
|
|
return this._wrapApiCall(async channel => {
|
|
const result = await channel.newCDPSession(page instanceof _page.Page ? {
|
|
page: page._channel
|
|
} : {
|
|
frame: page._channel
|
|
});
|
|
return _cdpSession.CDPSession.from(result.session);
|
|
});
|
|
}
|
|
|
|
_onClose() {
|
|
var _this$_browserType, _this$_browserType$_c;
|
|
|
|
if (this._browser) this._browser._contexts.delete(this);
|
|
(_this$_browserType = this._browserType) === null || _this$_browserType === void 0 ? void 0 : (_this$_browserType$_c = _this$_browserType._contexts) === null || _this$_browserType$_c === void 0 ? void 0 : _this$_browserType$_c.delete(this);
|
|
this.emit(_events.Events.BrowserContext.Close, this);
|
|
}
|
|
|
|
async close() {
|
|
try {
|
|
await this._wrapApiCall(async channel => {
|
|
var _this$_browserType2, _this$_browserType2$_;
|
|
|
|
await ((_this$_browserType2 = this._browserType) === null || _this$_browserType2 === void 0 ? void 0 : (_this$_browserType2$_ = _this$_browserType2._onWillCloseContext) === null || _this$_browserType2$_ === void 0 ? void 0 : _this$_browserType2$_.call(_this$_browserType2, this));
|
|
|
|
if (this._options.recordHar) {
|
|
var _this$browser;
|
|
|
|
const har = await this._channel.harExport();
|
|
|
|
const artifact = _artifact.Artifact.from(har.artifact);
|
|
|
|
if ((_this$browser = this.browser()) !== null && _this$browser !== void 0 && _this$browser._remoteType) artifact._isRemote = true;
|
|
await artifact.saveAs(this._options.recordHar.path);
|
|
await artifact.delete();
|
|
}
|
|
|
|
await channel.close();
|
|
await this._closedPromise;
|
|
});
|
|
} catch (e) {
|
|
if ((0, _errors.isSafeCloseError)(e)) return;
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async _enableRecorder(params) {
|
|
await this._channel.recorderSupplementEnable(params);
|
|
}
|
|
|
|
}
|
|
|
|
exports.BrowserContext = BrowserContext;
|
|
|
|
async function prepareBrowserContextParams(options) {
|
|
if (options.videoSize && !options.videosPath) throw new Error(`"videoSize" option requires "videosPath" to be specified`);
|
|
if (options.extraHTTPHeaders) network.validateHeaders(options.extraHTTPHeaders);
|
|
const contextParams = { ...options,
|
|
viewport: options.viewport === null ? undefined : options.viewport,
|
|
noDefaultViewport: options.viewport === null,
|
|
extraHTTPHeaders: options.extraHTTPHeaders ? (0, _utils.headersObjectToArray)(options.extraHTTPHeaders) : undefined,
|
|
storageState: typeof options.storageState === 'string' ? JSON.parse(await _fs.default.promises.readFile(options.storageState, 'utf8')) : options.storageState
|
|
};
|
|
|
|
if (!contextParams.recordVideo && options.videosPath) {
|
|
contextParams.recordVideo = {
|
|
dir: options.videosPath,
|
|
size: options.videoSize
|
|
};
|
|
}
|
|
|
|
return contextParams;
|
|
} |