UNPKG

playwright-core

Version:

A high-level API to automate web browsers

423 lines • 20.1 kB
"use strict"; /** * 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. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyLoadState = exports.Frame = void 0; const utils_1 = require("../utils/utils"); const channelOwner_1 = require("./channelOwner"); const elementHandle_1 = require("./elementHandle"); const jsHandle_1 = require("./jsHandle"); const fs_1 = __importDefault(require("fs")); const network = __importStar(require("./network")); const util = __importStar(require("util")); const events_1 = require("events"); const waiter_1 = require("./waiter"); const events_2 = require("./events"); const types_1 = require("./types"); const clientHelper_1 = require("./clientHelper"); const fsReadFileAsync = util.promisify(fs_1.default.readFile.bind(fs_1.default)); class Frame extends channelOwner_1.ChannelOwner { constructor(parent, type, guid, initializer) { super(parent, type, guid, initializer); this._parentFrame = null; this._url = ''; this._name = ''; this._detached = false; this._childFrames = new Set(); this._eventEmitter = new events_1.EventEmitter(); this._eventEmitter.setMaxListeners(0); this._parentFrame = Frame.fromNullable(initializer.parentFrame); if (this._parentFrame) this._parentFrame._childFrames.add(this); this._name = initializer.name; this._url = initializer.url; this._loadStates = new Set(initializer.loadStates); this._channel.on('loadstate', event => { if (event.add) { this._loadStates.add(event.add); this._eventEmitter.emit('loadstate', event.add); } if (event.remove) this._loadStates.delete(event.remove); }); this._channel.on('navigated', event => { this._url = event.url; this._name = event.name; this._eventEmitter.emit('navigated', event); if (!event.error && this._page) this._page.emit(events_2.Events.Page.FrameNavigated, this); }); } static from(frame) { return frame._object; } static fromNullable(frame) { return frame ? Frame.from(frame) : null; } _apiName(method) { return this._page._isPageCall ? 'page.' + method : 'frame.' + method; } page() { return this._page; } async goto(url, options = {}) { return this._wrapApiCall(this._apiName('goto'), async (channel) => { const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); return network.Response.fromNullable((await channel.goto({ url, ...options, waitUntil })).response); }); } _setupNavigationWaiter(name, options) { const waiter = new waiter_1.Waiter(this, name); waiter.rejectOnEvent(this._page, events_2.Events.Page.Close, new Error('Navigation failed because page was closed!')); waiter.rejectOnEvent(this._page, events_2.Events.Page.Crash, new Error('Navigation failed because page crashed!')); waiter.rejectOnEvent(this._page, events_2.Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this); const timeout = this._page._timeoutSettings.navigationTimeout(options); waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded.`); return waiter; } async waitForNavigation(options = {}) { return this._wrapApiCall(this._apiName('waitForNavigation'), async (channel) => { const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); const waiter = this._setupNavigationWaiter(this._apiName('waitForNavigation'), options); const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : ''; waiter.log(`waiting for navigation${toUrl} until "${waitUntil}"`); const navigatedEvent = await waiter.waitForEvent(this._eventEmitter, 'navigated', event => { // Any failed navigation results in a rejection. if (event.error) return true; waiter.log(` navigated to "${event.url}"`); return clientHelper_1.urlMatches(event.url, options.url); }); if (navigatedEvent.error) { const e = new Error(navigatedEvent.error); e.stack = ''; await waiter.waitForPromise(Promise.reject(e)); } if (!this._loadStates.has(waitUntil)) { await waiter.waitForEvent(this._eventEmitter, 'loadstate', s => { waiter.log(` "${s}" event fired`); return s === waitUntil; }); } const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request) : null; const response = request ? await waiter.waitForPromise(request._finalRequest().response()) : null; waiter.dispose(); return response; }); } async waitForLoadState(state = 'load', options = {}) { state = verifyLoadState('state', state); if (this._loadStates.has(state)) return; return this._wrapApiCall(this._apiName('waitForLoadState'), async (channel) => { const waiter = this._setupNavigationWaiter(this._apiName('waitForLoadState'), options); await waiter.waitForEvent(this._eventEmitter, 'loadstate', s => { waiter.log(` "${s}" event fired`); return s === state; }); waiter.dispose(); }); } async frameElement() { return this._wrapApiCall(this._apiName('frameElement'), async (channel) => { return elementHandle_1.ElementHandle.from((await channel.frameElement()).element); }); } async evaluateHandle(pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 2); return this._wrapApiCall(this._apiName('evaluateHandle'), async (channel) => { const result = await channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg) }); return jsHandle_1.JSHandle.from(result.handle); }); } async _evaluateHandleInUtility(pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 2); return this._wrapApiCall(this._apiName('_evaluateHandleInUtility'), async (channel) => { const result = await channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg), world: 'utility' }); return jsHandle_1.JSHandle.from(result.handle); }); } async evaluate(pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 2); return this._wrapApiCall(this._apiName('evaluate'), async (channel) => { const result = await channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg) }); return jsHandle_1.parseResult(result.value); }); } async _evaluateInUtility(pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 2); return this._wrapApiCall(this._apiName('evaluate'), async (channel) => { const result = await channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg), world: 'utility' }); return jsHandle_1.parseResult(result.value); }); } async $(selector) { return this._wrapApiCall(this._apiName('$'), async (channel) => { const result = await channel.querySelector({ selector }); return elementHandle_1.ElementHandle.fromNullable(result.element); }); } async waitForSelector(selector, options = {}) { return this._wrapApiCall(this._apiName('waitForSelector'), async (channel) => { if (options.visibility) throw new Error('options.visibility is not supported, did you mean options.state?'); if (options.waitFor && options.waitFor !== 'visible') throw new Error('options.waitFor is not supported, did you mean options.state?'); const result = await channel.waitForSelector({ selector, ...options }); return elementHandle_1.ElementHandle.fromNullable(result.element); }); } async dispatchEvent(selector, type, eventInit, options = {}) { return this._wrapApiCall(this._apiName('dispatchEvent'), async (channel) => { await channel.dispatchEvent({ selector, type, eventInit: jsHandle_1.serializeArgument(eventInit), ...options }); }); } async $eval(selector, pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 3); return this._wrapApiCall(this._apiName('$eval'), async (channel) => { const result = await channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg) }); return jsHandle_1.parseResult(result.value); }); } async $$eval(selector, pageFunction, arg) { jsHandle_1.assertMaxArguments(arguments.length, 3); return this._wrapApiCall(this._apiName('$$eval'), async (channel) => { const result = await channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg) }); return jsHandle_1.parseResult(result.value); }); } async $$(selector) { return this._wrapApiCall(this._apiName('$$'), async (channel) => { const result = await channel.querySelectorAll({ selector }); return result.elements.map(e => elementHandle_1.ElementHandle.from(e)); }); } async content() { return this._wrapApiCall(this._apiName('content'), async (channel) => { return (await channel.content()).value; }); } async setContent(html, options = {}) { return this._wrapApiCall(this._apiName('setContent'), async (channel) => { const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); await channel.setContent({ html, ...options, waitUntil }); }); } name() { return this._name || ''; } url() { return this._url; } parentFrame() { return this._parentFrame; } childFrames() { return Array.from(this._childFrames); } isDetached() { return this._detached; } async addScriptTag(options = {}) { return this._wrapApiCall(this._apiName('addScriptTag'), async (channel) => { const copy = { ...options }; if (copy.path) { copy.content = (await fsReadFileAsync(copy.path)).toString(); copy.content += '//# sourceURL=' + copy.path.replace(/\n/g, ''); } return elementHandle_1.ElementHandle.from((await channel.addScriptTag({ ...copy })).element); }); } async addStyleTag(options = {}) { return this._wrapApiCall(this._apiName('addStyleTag'), async (channel) => { const copy = { ...options }; if (copy.path) { copy.content = (await fsReadFileAsync(copy.path)).toString(); copy.content += '/*# sourceURL=' + copy.path.replace(/\n/g, '') + '*/'; } return elementHandle_1.ElementHandle.from((await channel.addStyleTag({ ...copy })).element); }); } async click(selector, options = {}) { return this._wrapApiCall(this._apiName('click'), async (channel) => { return await channel.click({ selector, ...options }); }); } async dblclick(selector, options = {}) { return this._wrapApiCall(this._apiName('dblclick'), async (channel) => { return await channel.dblclick({ selector, ...options }); }); } async tap(selector, options = {}) { return this._wrapApiCall(this._apiName('tap'), async (channel) => { return await channel.tap({ selector, ...options }); }); } async fill(selector, value, options = {}) { return this._wrapApiCall(this._apiName('fill'), async (channel) => { return await channel.fill({ selector, value, ...options }); }); } async focus(selector, options = {}) { return this._wrapApiCall(this._apiName('focus'), async (channel) => { await channel.focus({ selector, ...options }); }); } async textContent(selector, options = {}) { return this._wrapApiCall(this._apiName('textContent'), async (channel) => { const value = (await channel.textContent({ selector, ...options })).value; return value === undefined ? null : value; }); } async innerText(selector, options = {}) { return this._wrapApiCall(this._apiName('innerText'), async (channel) => { return (await channel.innerText({ selector, ...options })).value; }); } async innerHTML(selector, options = {}) { return this._wrapApiCall(this._apiName('innerHTML'), async (channel) => { return (await channel.innerHTML({ selector, ...options })).value; }); } async getAttribute(selector, name, options = {}) { return this._wrapApiCall(this._apiName('getAttribute'), async (channel) => { const value = (await channel.getAttribute({ selector, name, ...options })).value; return value === undefined ? null : value; }); } async isChecked(selector, options = {}) { return this._wrapApiCall(this._apiName('isChecked'), async (channel) => { return (await channel.isChecked({ selector, ...options })).value; }); } async isDisabled(selector, options = {}) { return this._wrapApiCall(this._apiName('isDisabled'), async (channel) => { return (await channel.isDisabled({ selector, ...options })).value; }); } async isEditable(selector, options = {}) { return this._wrapApiCall(this._apiName('isEditable'), async (channel) => { return (await channel.isEditable({ selector, ...options })).value; }); } async isEnabled(selector, options = {}) { return this._wrapApiCall(this._apiName('isEnabled'), async (channel) => { return (await channel.isEnabled({ selector, ...options })).value; }); } async isHidden(selector, options = {}) { return this._wrapApiCall(this._apiName('isHidden'), async (channel) => { return (await channel.isHidden({ selector, ...options })).value; }); } async isVisible(selector, options = {}) { return this._wrapApiCall(this._apiName('isVisible'), async (channel) => { return (await channel.isVisible({ selector, ...options })).value; }); } async hover(selector, options = {}) { return this._wrapApiCall(this._apiName('hover'), async (channel) => { await channel.hover({ selector, ...options }); }); } async selectOption(selector, values, options = {}) { return this._wrapApiCall(this._apiName('selectOption'), async (channel) => { return (await channel.selectOption({ selector, ...elementHandle_1.convertSelectOptionValues(values), ...options })).values; }); } async setInputFiles(selector, files, options = {}) { return this._wrapApiCall(this._apiName('setInputFiles'), async (channel) => { await channel.setInputFiles({ selector, files: await elementHandle_1.convertInputFiles(files), ...options }); }); } async type(selector, text, options = {}) { return this._wrapApiCall(this._apiName('type'), async (channel) => { await channel.type({ selector, text, ...options }); }); } async press(selector, key, options = {}) { return this._wrapApiCall(this._apiName('press'), async (channel) => { await channel.press({ selector, key, ...options }); }); } async check(selector, options = {}) { return this._wrapApiCall(this._apiName('check'), async (channel) => { await channel.check({ selector, ...options }); }); } async uncheck(selector, options = {}) { return this._wrapApiCall(this._apiName('uncheck'), async (channel) => { await channel.uncheck({ selector, ...options }); }); } async waitForTimeout(timeout) { return this._wrapApiCall(this._apiName('waitForTimeout'), async (channel) => { await new Promise(fulfill => setTimeout(fulfill, timeout)); }); } async waitForFunction(pageFunction, arg, options = {}) { return this._wrapApiCall(this._apiName('waitForFunction'), async (channel) => { if (typeof options.polling === 'string') utils_1.assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling); const result = await channel.waitForFunction({ ...options, pollingInterval: options.polling === 'raf' ? undefined : options.polling, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: jsHandle_1.serializeArgument(arg), }); return jsHandle_1.JSHandle.from(result.handle); }); } async title() { return this._wrapApiCall(this._apiName('title'), async (channel) => { return (await channel.title()).value; }); } } exports.Frame = Frame; function verifyLoadState(name, waitUntil) { if (waitUntil === 'networkidle0') waitUntil = 'networkidle'; if (!types_1.kLifecycleEvents.has(waitUntil)) throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle)`); return waitUntil; } exports.verifyLoadState = verifyLoadState; //# sourceMappingURL=frame.js.map