/** * 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. */ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } function next() { while (env.stack.length) { var rec = env.stack.pop(); try { var result = rec.dispose && rec.dispose.call(rec.value); if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } catch (e) { fail(e); } } if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); import { delay, filter, filterAsync, first, firstValueFrom, from, fromEvent, map, merge, of, raceWith, startWith, switchMap, } from '../../third_party/rxjs/rxjs.js'; import { NetworkManagerEvent, } from '../cdp/NetworkManager.js'; import { TargetCloseError } from '../common/Errors.js'; import { EventEmitter, } from '../common/EventEmitter.js'; import { paperFormats, } from '../common/PDFOptions.js'; import { debugError, importFSPromises, isNumber, isString, timeout, withSourcePuppeteerURLIfNone, } from '../common/util.js'; import { assert } from '../util/assert.js'; import { guarded } from '../util/decorators.js'; import { AsyncDisposableStack, asyncDisposeSymbol, disposeSymbol, } from '../util/disposable.js'; import { FunctionLocator, Locator, NodeLocator, } from './locators/locators.js'; /** * @internal */ export function setDefaultScreenshotOptions(options) { options.optimizeForSpeed ??= false; options.type ??= 'png'; options.fromSurface ??= true; options.fullPage ??= false; options.omitBackground ??= false; options.encoding ??= 'binary'; options.captureBeyondViewport ??= true; options.allowViewportExpansion ??= options.captureBeyondViewport; } /** * Page provides methods to interact with a single tab or * {@link https://developer.chrome.com/extensions/background_pages | extension background page} * in the browser. * * :::note * * One Browser instance might have multiple Page instances. * * ::: * * @example * This example creates a page, navigates it to a URL, and then saves a screenshot: * * ```ts * import puppeteer from 'puppeteer'; * * (async () => { * const browser = await puppeteer.launch(); * const page = await browser.newPage(); * await page.goto('https://example.com'); * await page.screenshot({path: 'screenshot.png'}); * await browser.close(); * })(); * ``` * * The Page class extends from Puppeteer's {@link EventEmitter} class and will * emit various events which are documented in the {@link PageEvent} enum. * * @example * This example logs a message for a single page `load` event: * * ```ts * page.once('load', () => console.log('Page loaded!')); * ``` * * To unsubscribe from events use the {@link EventEmitter.off} method: * * ```ts * function logRequest(interceptedRequest) { * console.log('A request was made:', interceptedRequest.url()); * } * page.on('request', logRequest); * // Sometime later... * page.off('request', logRequest); * ``` * * @public */ let Page = (() => { let _classSuper = EventEmitter; let _instanceExtraInitializers = []; let _screenshot_decorators; return class Page extends _classSuper { static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(this, null, _screenshot_decorators, { kind: "method", name: "screenshot", static: false, private: false, access: { has: obj => "screenshot" in obj, get: obj => obj.screenshot }, metadata: _metadata }, null, _instanceExtraInitializers); if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); } /** * @internal */ _isDragging = (__runInitializers(this, _instanceExtraInitializers), false); #requestHandlers = new WeakMap(); /** * @internal */ constructor() { super(); } /** * `true` if the service worker are being bypassed, `false` otherwise. */ isServiceWorkerBypassed() { throw new Error('Not implemented'); } /** * `true` if drag events are being intercepted, `false` otherwise. * * @deprecated We no longer support intercepting drag payloads. Use the new * drag APIs found on {@link ElementHandle} to drag (or just use the * {@link Page.mouse}). */ isDragInterceptionEnabled() { throw new Error('Not implemented'); } /** * `true` if the page has JavaScript enabled, `false` otherwise. */ isJavaScriptEnabled() { throw new Error('Not implemented'); } /** * Listen to page events. * * @remarks * This method exists to define event typings and handle proper wireup of * cooperative request interception. Actual event listening and dispatching is * delegated to {@link EventEmitter}. * * @internal */ on(type, handler) { if (type !== "request" /* PageEvent.Request */) { return super.on(type, handler); } let wrapper = this.#requestHandlers.get(handler); if (wrapper === undefined) { wrapper = (event) => { event.enqueueInterceptAction(() => { return handler(event); }); }; this.#requestHandlers.set(handler, wrapper); } return super.on(type, wrapper); } /** * @internal */ off(type, handler) { if (type === "request" /* PageEvent.Request */) { handler = this.#requestHandlers.get(handler) || handler; } return super.off(type, handler); } waitForFileChooser() { throw new Error('Not implemented'); } async setGeolocation() { throw new Error('Not implemented'); } /** * A target this page was created from. */ target() { throw new Error('Not implemented'); } /** * Creates a Chrome Devtools Protocol session attached to the page. */ createCDPSession() { throw new Error('Not implemented'); } /** * {@inheritDoc Touchscreen} */ get touchscreen() { throw new Error('Not implemented'); } /** * All of the dedicated {@link * https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | * WebWorkers} associated with the page. * * @remarks * This does not contain ServiceWorkers */ workers() { throw new Error('Not implemented'); } async setRequestInterception() { throw new Error('Not implemented'); } async setBypassServiceWorker() { throw new Error('Not implemented'); } async setDragInterception() { throw new Error('Not implemented'); } setOfflineMode() { throw new Error('Not implemented'); } emulateNetworkConditions() { throw new Error('Not implemented'); } locator(selectorOrFunc) { if (typeof selectorOrFunc === 'string') { return NodeLocator.create(this, selectorOrFunc); } else { return FunctionLocator.create(this, selectorOrFunc); } } /** * A shortcut for {@link Locator.race} that does not require static imports. * * @internal */ locatorRace(locators) { return Locator.race(locators); } /** * Runs `document.querySelector` within the page. If no element matches the * selector, the return value resolves to `null`. * * @param selector - A `selector` to query page for * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector} * to query page for. */ async $(selector) { return await this.mainFrame().$(selector); } /** * The method runs `document.querySelectorAll` within the page. If no elements * match the selector, the return value resolves to `[]`. * @remarks * Shortcut for {@link Frame.$$ | Page.mainFrame().$$(selector) }. * @param selector - A `selector` to query page for */ async $$(selector) { return await this.mainFrame().$$(selector); } /** * @remarks * * The only difference between {@link Page.evaluate | page.evaluate} and * `page.evaluateHandle` is that `evaluateHandle` will return the value * wrapped in an in-page object. * * If the function passed to `page.evaluateHandle` returns a Promise, the * function will wait for the promise to resolve and return its value. * * You can pass a string instead of a function (although functions are * recommended as they are easier to debug and use with TypeScript): * * @example * * ```ts * const aHandle = await page.evaluateHandle('document'); * ``` * * @example * {@link JSHandle} instances can be passed as arguments to the `pageFunction`: * * ```ts * const aHandle = await page.evaluateHandle(() => document.body); * const resultHandle = await page.evaluateHandle( * body => body.innerHTML, * aHandle * ); * console.log(await resultHandle.jsonValue()); * await resultHandle.dispose(); * ``` * * Most of the time this function returns a {@link JSHandle}, * but if `pageFunction` returns a reference to an element, * you instead get an {@link ElementHandle} back: * * @example * * ```ts * const button = await page.evaluateHandle(() => * document.querySelector('button') * ); * // can call `click` because `button` is an `ElementHandle` * await button.click(); * ``` * * The TypeScript definitions assume that `evaluateHandle` returns * a `JSHandle`, but if you know it's going to return an * `ElementHandle`, pass it as the generic argument: * * ```ts * const button = await page.evaluateHandle(...); * ``` * * @param pageFunction - a function that is run within the page * @param args - arguments to be passed to the pageFunction */ async evaluateHandle(pageFunction, ...args) { pageFunction = withSourcePuppeteerURLIfNone(this.evaluateHandle.name, pageFunction); return await this.mainFrame().evaluateHandle(pageFunction, ...args); } /** * This method runs `document.querySelector` within the page and passes the * result as the first argument to the `pageFunction`. * * @remarks * * If no element is found matching `selector`, the method will throw an error. * * If `pageFunction` returns a promise `$eval` will wait for the promise to * resolve and then return its value. * * @example * * ```ts * const searchValue = await page.$eval('#search', el => el.value); * const preloadHref = await page.$eval('link[rel=preload]', el => el.href); * const html = await page.$eval('.main-container', el => el.outerHTML); * ``` * * If you are using TypeScript, you may have to provide an explicit type to the * first argument of the `pageFunction`. * By default it is typed as `Element`, but you may need to provide a more * specific sub-type: * * @example * * ```ts * // if you don't provide HTMLInputElement here, TS will error * // as `value` is not on `Element` * const searchValue = await page.$eval( * '#search', * (el: HTMLInputElement) => el.value * ); * ``` * * The compiler should be able to infer the return type * from the `pageFunction` you provide. If it is unable to, you can use the generic * type to tell the compiler what return type you expect from `$eval`: * * @example * * ```ts * // The compiler can infer the return type in this case, but if it can't * // or if you want to be more explicit, provide it as the generic type. * const searchValue = await page.$eval( * '#search', * (el: HTMLInputElement) => el.value * ); * ``` * * @param selector - the * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector} * to query for * @param pageFunction - the function to be evaluated in the page context. * Will be passed the result of `document.querySelector(selector)` as its * first argument. * @param args - any additional arguments to pass through to `pageFunction`. * * @returns The result of calling `pageFunction`. If it returns an element it * is wrapped in an {@link ElementHandle}, else the raw value itself is * returned. */ async $eval(selector, pageFunction, ...args) { pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction); return await this.mainFrame().$eval(selector, pageFunction, ...args); } /** * This method runs `Array.from(document.querySelectorAll(selector))` within * the page and passes the result as the first argument to the `pageFunction`. * * @remarks * If `pageFunction` returns a promise `$$eval` will wait for the promise to * resolve and then return its value. * * @example * * ```ts * // get the amount of divs on the page * const divCount = await page.$$eval('div', divs => divs.length); * * // get the text content of all the `.options` elements: * const options = await page.$$eval('div > span.options', options => { * return options.map(option => option.textContent); * }); * ``` * * If you are using TypeScript, you may have to provide an explicit type to the * first argument of the `pageFunction`. * By default it is typed as `Element[]`, but you may need to provide a more * specific sub-type: * * @example * * ```ts * // if you don't provide HTMLInputElement here, TS will error * // as `value` is not on `Element` * await page.$$eval('input', (elements: HTMLInputElement[]) => { * return elements.map(e => e.value); * }); * ``` * * The compiler should be able to infer the return type * from the `pageFunction` you provide. If it is unable to, you can use the generic * type to tell the compiler what return type you expect from `$$eval`: * * @example * * ```ts * // The compiler can infer the return type in this case, but if it can't * // or if you want to be more explicit, provide it as the generic type. * const allInputValues = await page.$$eval( * 'input', * (elements: HTMLInputElement[]) => elements.map(e => e.textContent) * ); * ``` * * @param selector - the * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector} * to query for * @param pageFunction - the function to be evaluated in the page context. * Will be passed the result of * `Array.from(document.querySelectorAll(selector))` as its first argument. * @param args - any additional arguments to pass through to `pageFunction`. * * @returns The result of calling `pageFunction`. If it returns an element it * is wrapped in an {@link ElementHandle}, else the raw value itself is * returned. */ async $$eval(selector, pageFunction, ...args) { pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction); return await this.mainFrame().$$eval(selector, pageFunction, ...args); } /** * The method evaluates the XPath expression relative to the page document as * its context node. If there are no such elements, the method resolves to an * empty array. * * @remarks * Shortcut for {@link Frame.$x | Page.mainFrame().$x(expression) }. * * @param expression - Expression to evaluate */ async $x(expression) { return await this.mainFrame().$x(expression); } async cookies() { throw new Error('Not implemented'); } async deleteCookie() { throw new Error('Not implemented'); } async setCookie() { throw new Error('Not implemented'); } /** * Adds a `