Best JavaScript code snippet using playwright-internal
frames.js
Source:frames.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5exports.FrameManager = exports.Frame = void 0;6var dom = _interopRequireWildcard(require("./dom"));7var _helper = require("./helper");8var _eventsHelper = require("../utils/eventsHelper");9var js = _interopRequireWildcard(require("./javascript"));10var network = _interopRequireWildcard(require("./network"));11var _page = require("./page");12var types = _interopRequireWildcard(require("./types"));13var _browserContext = require("./browserContext");14var _progress = require("./progress");15var _utils = require("../utils/utils");16var _async = require("../utils/async");17var _debugLogger = require("../utils/debugLogger");18var _instrumentation = require("./instrumentation");19var _protocolError = require("./common/protocolError");20var _selectorParser = require("./common/selectorParser");21var _selectorErrors = require("./common/selectorErrors");22function _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); }23function _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; }24/**25 * Copyright 2017 Google Inc. All rights reserved.26 * Modifications copyright (c) Microsoft Corporation.27 *28 * Licensed under the Apache License, Version 2.0 (the "License");29 * you may not use this file except in compliance with the License.30 * You may obtain a copy of the License at31 *32 * http://www.apache.org/licenses/LICENSE-2.033 *34 * Unless required by applicable law or agreed to in writing, software35 * distributed under the License is distributed on an "AS IS" BASIS,36 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.37 * See the License for the specific language governing permissions and38 * limitations under the License.39 */40class FrameManager {41 constructor(page) {42 this._page = void 0;43 this._frames = new Map();44 this._mainFrame = void 0;45 this._consoleMessageTags = new Map();46 this._signalBarriers = new Set();47 this._webSockets = new Map();48 this._dialogCounter = 0;49 this._page = page;50 this._mainFrame = undefined;51 }52 dispose() {53 for (const frame of this._frames.values()) frame._stopNetworkIdleTimer();54 }55 mainFrame() {56 return this._mainFrame;57 }58 frames() {59 const frames = [];60 collect(this._mainFrame);61 return frames;62 function collect(frame) {63 frames.push(frame);64 for (const subframe of frame.childFrames()) collect(subframe);65 }66 }67 frame(frameId) {68 return this._frames.get(frameId) || null;69 }70 frameAttached(frameId, parentFrameId) {71 const parentFrame = parentFrameId ? this._frames.get(parentFrameId) : null;72 if (!parentFrame) {73 if (this._mainFrame) {74 // Update frame id to retain frame identity on cross-process navigation.75 this._frames.delete(this._mainFrame._id);76 this._mainFrame._id = frameId;77 } else {78 (0, _utils.assert)(!this._frames.has(frameId));79 this._mainFrame = new Frame(this._page, frameId, parentFrame);80 }81 this._frames.set(frameId, this._mainFrame);82 return this._mainFrame;83 } else {84 (0, _utils.assert)(!this._frames.has(frameId));85 const frame = new Frame(this._page, frameId, parentFrame);86 this._frames.set(frameId, frame);87 this._page.emit(_page.Page.Events.FrameAttached, frame);88 return frame;89 }90 }91 async waitForSignalsCreatedBy(progress, noWaitAfter, action, source) {92 if (noWaitAfter) return action();93 const barrier = new SignalBarrier(progress);94 this._signalBarriers.add(barrier);95 if (progress) progress.cleanupWhenAborted(() => this._signalBarriers.delete(barrier));96 const result = await action();97 if (source === 'input') await this._page._delegate.inputActionEpilogue();98 await barrier.waitFor();99 this._signalBarriers.delete(barrier); // Resolve in the next task, after all waitForNavigations.100 await new Promise((0, _utils.makeWaitForNextTask)());101 return result;102 }103 frameWillPotentiallyRequestNavigation() {104 for (const barrier of this._signalBarriers) barrier.retain();105 }106 frameDidPotentiallyRequestNavigation() {107 for (const barrier of this._signalBarriers) barrier.release();108 }109 frameRequestedNavigation(frameId, documentId) {110 const frame = this._frames.get(frameId);111 if (!frame) return;112 for (const barrier of this._signalBarriers) barrier.addFrameNavigation(frame);113 if (frame.pendingDocument() && frame.pendingDocument().documentId === documentId) {114 // Do not override request with undefined.115 return;116 }117 frame.setPendingDocument({118 documentId,119 request: undefined120 });121 }122 frameCommittedNewDocumentNavigation(frameId, url, name, documentId, initial) {123 const frame = this._frames.get(frameId);124 this.removeChildFramesRecursively(frame);125 this.clearWebSockets(frame);126 frame._url = url;127 frame._name = name;128 let keepPending;129 const pendingDocument = frame.pendingDocument();130 if (pendingDocument) {131 if (pendingDocument.documentId === undefined) {132 // Pending with unknown documentId - assume it is the one being committed.133 pendingDocument.documentId = documentId;134 }135 if (pendingDocument.documentId === documentId) {136 // Committing a pending document.137 frame._currentDocument = pendingDocument;138 } else {139 // Sometimes, we already have a new pending when the old one commits.140 // An example would be Chromium error page followed by a new navigation request,141 // where the error page commit arrives after Network.requestWillBeSent for the142 // new navigation.143 // We commit, but keep the pending request since it's not done yet.144 keepPending = pendingDocument;145 frame._currentDocument = {146 documentId,147 request: undefined148 };149 }150 frame.setPendingDocument(undefined);151 } else {152 // No pending - just commit a new document.153 frame._currentDocument = {154 documentId,155 request: undefined156 };157 }158 frame._onClearLifecycle();159 const navigationEvent = {160 url,161 name,162 newDocument: frame._currentDocument163 };164 frame.emit(Frame.Events.Navigation, navigationEvent);165 if (!initial) {166 _debugLogger.debugLogger.log('api', ` navigated to "${url}"`);167 this._page.frameNavigatedToNewDocument(frame);168 } // Restore pending if any - see comments above about keepPending.169 frame.setPendingDocument(keepPending);170 }171 frameCommittedSameDocumentNavigation(frameId, url) {172 const frame = this._frames.get(frameId);173 if (!frame) return;174 frame._url = url;175 const navigationEvent = {176 url,177 name: frame._name178 };179 frame.emit(Frame.Events.Navigation, navigationEvent);180 _debugLogger.debugLogger.log('api', ` navigated to "${url}"`);181 }182 frameAbortedNavigation(frameId, errorText, documentId) {183 const frame = this._frames.get(frameId);184 if (!frame || !frame.pendingDocument()) return;185 if (documentId !== undefined && frame.pendingDocument().documentId !== documentId) return;186 const navigationEvent = {187 url: frame._url,188 name: frame._name,189 newDocument: frame.pendingDocument(),190 error: new Error(errorText)191 };192 frame.setPendingDocument(undefined);193 frame.emit(Frame.Events.Navigation, navigationEvent);194 }195 frameDetached(frameId) {196 const frame = this._frames.get(frameId);197 if (frame) this._removeFramesRecursively(frame);198 }199 frameStoppedLoading(frameId) {200 this.frameLifecycleEvent(frameId, 'domcontentloaded');201 this.frameLifecycleEvent(frameId, 'load');202 }203 frameLifecycleEvent(frameId, event) {204 const frame = this._frames.get(frameId);205 if (frame) frame._onLifecycleEvent(event);206 }207 requestStarted(request, route) {208 const frame = request.frame();209 this._inflightRequestStarted(request);210 if (request._documentId) frame.setPendingDocument({211 documentId: request._documentId,212 request213 });214 if (request._isFavicon) {215 if (route) route.continue(request, {});216 return;217 }218 this._page._browserContext.emit(_browserContext.BrowserContext.Events.Request, request);219 if (route) this._page._requestStarted(request, route);220 }221 requestReceivedResponse(response) {222 if (response.request()._isFavicon) return;223 this._page._browserContext.emit(_browserContext.BrowserContext.Events.Response, response);224 }225 reportRequestFinished(request, response) {226 this._inflightRequestFinished(request);227 if (request._isFavicon) return;228 this._page._browserContext.emit(_browserContext.BrowserContext.Events.RequestFinished, {229 request,230 response231 });232 }233 requestFailed(request, canceled) {234 const frame = request.frame();235 this._inflightRequestFinished(request);236 if (frame.pendingDocument() && frame.pendingDocument().request === request) {237 let errorText = request.failure().errorText;238 if (canceled) errorText += '; maybe frame was detached?';239 this.frameAbortedNavigation(frame._id, errorText, frame.pendingDocument().documentId);240 }241 if (request._isFavicon) return;242 this._page._browserContext.emit(_browserContext.BrowserContext.Events.RequestFailed, request);243 }244 dialogDidOpen() {245 // Any ongoing evaluations will be stalled until the dialog is closed.246 for (const frame of this._frames.values()) frame._invalidateNonStallingEvaluations('JavaScript dialog interrupted evaluation');247 this._dialogCounter++;248 }249 dialogWillClose() {250 this._dialogCounter--;251 }252 removeChildFramesRecursively(frame) {253 for (const child of frame.childFrames()) this._removeFramesRecursively(child);254 }255 _removeFramesRecursively(frame) {256 this.removeChildFramesRecursively(frame);257 frame._onDetached();258 this._frames.delete(frame._id);259 if (!this._page.isClosed()) this._page.emit(_page.Page.Events.FrameDetached, frame);260 }261 _inflightRequestFinished(request) {262 const frame = request.frame();263 if (request._isFavicon) return;264 if (!frame._inflightRequests.has(request)) return;265 frame._inflightRequests.delete(request);266 if (frame._inflightRequests.size === 0) frame._startNetworkIdleTimer();267 }268 _inflightRequestStarted(request) {269 const frame = request.frame();270 if (request._isFavicon) return;271 frame._inflightRequests.add(request);272 if (frame._inflightRequests.size === 1) frame._stopNetworkIdleTimer();273 }274 interceptConsoleMessage(message) {275 if (message.type() !== 'debug') return false;276 const tag = message.text();277 const handler = this._consoleMessageTags.get(tag);278 if (!handler) return false;279 this._consoleMessageTags.delete(tag);280 handler();281 return true;282 }283 clearWebSockets(frame) {284 // TODO: attribute sockets to frames.285 if (frame.parentFrame()) return;286 this._webSockets.clear();287 }288 onWebSocketCreated(requestId, url) {289 const ws = new network.WebSocket(this._page, url);290 this._webSockets.set(requestId, ws);291 }292 onWebSocketRequest(requestId) {293 const ws = this._webSockets.get(requestId);294 if (ws && ws.markAsNotified()) this._page.emit(_page.Page.Events.WebSocket, ws);295 }296 onWebSocketResponse(requestId, status, statusText) {297 const ws = this._webSockets.get(requestId);298 if (status < 400) return;299 if (ws) ws.error(`${statusText}: ${status}`);300 }301 onWebSocketFrameSent(requestId, opcode, data) {302 const ws = this._webSockets.get(requestId);303 if (ws) ws.frameSent(opcode, data);304 }305 webSocketFrameReceived(requestId, opcode, data) {306 const ws = this._webSockets.get(requestId);307 if (ws) ws.frameReceived(opcode, data);308 }309 webSocketClosed(requestId) {310 const ws = this._webSockets.get(requestId);311 if (ws) ws.closed();312 this._webSockets.delete(requestId);313 }314 webSocketError(requestId, errorMessage) {315 const ws = this._webSockets.get(requestId);316 if (ws) ws.error(errorMessage);317 }318}319exports.FrameManager = FrameManager;320class Frame extends _instrumentation.SdkObject {321 constructor(page, id, parentFrame) {322 super(page, 'frame');323 this._id = void 0;324 this._firedLifecycleEvents = new Set();325 this._subtreeLifecycleEvents = new Set();326 this._currentDocument = void 0;327 this._pendingDocument = void 0;328 this._page = void 0;329 this._parentFrame = void 0;330 this._url = '';331 this._detached = false;332 this._contextData = new Map();333 this._childFrames = new Set();334 this._name = '';335 this._inflightRequests = new Set();336 this._networkIdleTimer = void 0;337 this._setContentCounter = 0;338 this._detachedPromise = void 0;339 this._detachedCallback = () => {};340 this._nonStallingEvaluations = new Set();341 this.attribution.frame = this;342 this._id = id;343 this._page = page;344 this._parentFrame = parentFrame;345 this._currentDocument = {346 documentId: undefined,347 request: undefined348 };349 this._detachedPromise = new Promise(x => this._detachedCallback = x);350 this._contextData.set('main', {351 contextPromise: new _async.ManualPromise(),352 context: null,353 rerunnableTasks: new Set()354 });355 this._contextData.set('utility', {356 contextPromise: new _async.ManualPromise(),357 context: null,358 rerunnableTasks: new Set()359 });360 this._setContext('main', null);361 this._setContext('utility', null);362 if (this._parentFrame) this._parentFrame._childFrames.add(this);363 this._firedLifecycleEvents.add('commit');364 this._subtreeLifecycleEvents.add('commit');365 }366 isDetached() {367 return this._detached;368 }369 _onLifecycleEvent(event) {370 if (this._firedLifecycleEvents.has(event)) return;371 this._firedLifecycleEvents.add(event); // Recalculate subtree lifecycle for the whole tree - it should not be that big.372 this._page.mainFrame()._recalculateLifecycle();373 }374 _onClearLifecycle() {375 this._firedLifecycleEvents.clear(); // Recalculate subtree lifecycle for the whole tree - it should not be that big.376 this._page.mainFrame()._recalculateLifecycle(); // Keep the current navigation request if any.377 this._inflightRequests = new Set(Array.from(this._inflightRequests).filter(request => request === this._currentDocument.request));378 this._stopNetworkIdleTimer();379 if (this._inflightRequests.size === 0) this._startNetworkIdleTimer();380 this._onLifecycleEvent('commit');381 }382 setPendingDocument(documentInfo) {383 this._pendingDocument = documentInfo;384 if (documentInfo) this._invalidateNonStallingEvaluations('Navigation interrupted the evaluation');385 }386 pendingDocument() {387 return this._pendingDocument;388 }389 _invalidateNonStallingEvaluations(message) {390 if (!this._nonStallingEvaluations) return;391 const error = new Error(message);392 for (const callback of this._nonStallingEvaluations) callback(error);393 }394 async nonStallingRawEvaluateInExistingMainContext(expression) {395 if (this._pendingDocument) throw new Error('Frame is currently attempting a navigation');396 if (this._page._frameManager._dialogCounter) throw new Error('Open JavaScript dialog prevents evaluation');397 const context = this._existingMainContext();398 if (!context) throw new Error('Frame does not yet have a main execution context');399 let callback = () => {};400 const frameInvalidated = new Promise((f, r) => callback = r);401 this._nonStallingEvaluations.add(callback);402 try {403 return await Promise.race([context.rawEvaluateJSON(expression), frameInvalidated]);404 } finally {405 this._nonStallingEvaluations.delete(callback);406 }407 }408 async nonStallingEvaluateInExistingContext(expression, isFunction, world) {409 var _this$_contextData$ge;410 if (this._pendingDocument) throw new Error('Frame is currently attempting a navigation');411 const context = (_this$_contextData$ge = this._contextData.get(world)) === null || _this$_contextData$ge === void 0 ? void 0 : _this$_contextData$ge.context;412 if (!context) throw new Error('Frame does not yet have the execution context');413 let callback = () => {};414 const frameInvalidated = new Promise((f, r) => callback = r);415 this._nonStallingEvaluations.add(callback);416 try {417 return await Promise.race([context.evaluateExpression(expression, isFunction), frameInvalidated]);418 } finally {419 this._nonStallingEvaluations.delete(callback);420 }421 }422 _recalculateLifecycle() {423 const events = new Set(this._firedLifecycleEvents);424 for (const child of this._childFrames) {425 child._recalculateLifecycle(); // We require a particular lifecycle event to be fired in the whole426 // frame subtree, and then consider it done.427 for (const event of events) {428 if (!child._subtreeLifecycleEvents.has(event)) events.delete(event);429 }430 }431 const mainFrame = this._page.mainFrame();432 for (const event of events) {433 // Checking whether we have already notified about this event.434 if (!this._subtreeLifecycleEvents.has(event)) {435 this.emit(Frame.Events.AddLifecycle, event);436 if (this === mainFrame && this._url !== 'about:blank') _debugLogger.debugLogger.log('api', ` "${event}" event fired`);437 if (this === mainFrame && event === 'load') this._page.emit(_page.Page.Events.Load);438 if (this === mainFrame && event === 'domcontentloaded') this._page.emit(_page.Page.Events.DOMContentLoaded);439 }440 }441 for (const event of this._subtreeLifecycleEvents) {442 if (!events.has(event)) this.emit(Frame.Events.RemoveLifecycle, event);443 }444 this._subtreeLifecycleEvents = events;445 }446 async raceNavigationAction(action) {447 return Promise.race([this._page._disconnectedPromise.then(() => {448 throw new Error('Navigation failed because page was closed!');449 }), this._page._crashedPromise.then(() => {450 throw new Error('Navigation failed because page crashed!');451 }), this._detachedPromise.then(() => {452 throw new Error('Navigating frame was detached!');453 }), action()]);454 }455 async goto(metadata, url, options = {}) {456 const constructedNavigationURL = (0, _utils.constructURLBasedOnBaseURL)(this._page._browserContext._options.baseURL, url);457 const controller = new _progress.ProgressController(metadata, this);458 return controller.run(progress => this._goto(progress, constructedNavigationURL, options), this._page._timeoutSettings.navigationTimeout(options));459 }460 async _goto(progress, url, options) {461 return this.raceNavigationAction(async () => {462 const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);463 progress.log(`navigating to "${url}", waiting until "${waitUntil}"`);464 const headers = this._page._state.extraHTTPHeaders || [];465 const refererHeader = headers.find(h => h.name.toLowerCase() === 'referer');466 let referer = refererHeader ? refererHeader.value : undefined;467 if (options.referer !== undefined) {468 if (referer !== undefined && referer !== options.referer) throw new Error('"referer" is already specified as extra HTTP header');469 referer = options.referer;470 }471 url = _helper.helper.completeUserURL(url);472 const sameDocument = _helper.helper.waitForEvent(progress, this, Frame.Events.Navigation, e => !e.newDocument);473 const navigateResult = await this._page._delegate.navigateFrame(this, url, referer);474 let event;475 if (navigateResult.newDocumentId) {476 sameDocument.dispose();477 event = await _helper.helper.waitForEvent(progress, this, Frame.Events.Navigation, event => {478 // We are interested either in this specific document, or any other document that479 // did commit and replaced the expected document.480 return event.newDocument && (event.newDocument.documentId === navigateResult.newDocumentId || !event.error);481 }).promise;482 if (event.newDocument.documentId !== navigateResult.newDocumentId) {483 // This is just a sanity check. In practice, new navigation should484 // cancel the previous one and report "request cancelled"-like error.485 throw new Error('Navigation interrupted by another one');486 }487 if (event.error) throw event.error;488 } else {489 event = await sameDocument.promise;490 }491 if (!this._subtreeLifecycleEvents.has(waitUntil)) await _helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, e => e === waitUntil).promise;492 const request = event.newDocument ? event.newDocument.request : undefined;493 const response = request ? request._finalRequest().response() : null;494 await this._page._doSlowMo();495 return response;496 });497 }498 async _waitForNavigation(progress, options) {499 const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);500 progress.log(`waiting for navigation until "${waitUntil}"`);501 const navigationEvent = await _helper.helper.waitForEvent(progress, this, Frame.Events.Navigation, event => {502 // Any failed navigation results in a rejection.503 if (event.error) return true;504 progress.log(` navigated to "${this._url}"`);505 return true;506 }).promise;507 if (navigationEvent.error) throw navigationEvent.error;508 if (!this._subtreeLifecycleEvents.has(waitUntil)) await _helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, e => e === waitUntil).promise;509 const request = navigationEvent.newDocument ? navigationEvent.newDocument.request : undefined;510 return request ? request._finalRequest().response() : null;511 }512 async _waitForLoadState(progress, state) {513 const waitUntil = verifyLifecycle('state', state);514 if (!this._subtreeLifecycleEvents.has(waitUntil)) await _helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, e => e === waitUntil).promise;515 }516 async frameElement() {517 return this._page._delegate.getFrameElement(this);518 }519 _context(world) {520 return this._contextData.get(world).contextPromise.then(contextOrError => {521 if (contextOrError instanceof js.ExecutionContext) return contextOrError;522 throw contextOrError;523 });524 }525 _mainContext() {526 return this._context('main');527 }528 _existingMainContext() {529 var _this$_contextData$ge2;530 return ((_this$_contextData$ge2 = this._contextData.get('main')) === null || _this$_contextData$ge2 === void 0 ? void 0 : _this$_contextData$ge2.context) || null;531 }532 _utilityContext() {533 return this._context('utility');534 }535 async evaluateExpressionHandleAndWaitForSignals(expression, isFunction, arg, world = 'main') {536 const context = await this._context(world);537 const handle = await context.evaluateExpressionHandleAndWaitForSignals(expression, isFunction, arg);538 if (world === 'main') await this._page._doSlowMo();539 return handle;540 }541 async evaluateExpression(expression, isFunction, arg, world = 'main') {542 const context = await this._context(world);543 const value = await context.evaluateExpression(expression, isFunction, arg);544 if (world === 'main') await this._page._doSlowMo();545 return value;546 }547 async evaluateExpressionAndWaitForSignals(expression, isFunction, arg, world = 'main') {548 const context = await this._context(world);549 const value = await context.evaluateExpressionAndWaitForSignals(expression, isFunction, arg);550 if (world === 'main') await this._page._doSlowMo();551 return value;552 }553 async querySelector(selector, options) {554 _debugLogger.debugLogger.log('api', ` finding element using the selector "${selector}"`);555 const result = await this.resolveFrameForSelectorNoWait(selector, options);556 if (!result) return null;557 return this._page.selectors.query(result.frame, result.info);558 }559 async waitForSelector(metadata, selector, options, scope) {560 const controller = new _progress.ProgressController(metadata, this);561 if (options.visibility) throw new Error('options.visibility is not supported, did you mean options.state?');562 if (options.waitFor && options.waitFor !== 'visible') throw new Error('options.waitFor is not supported, did you mean options.state?');563 const {564 state = 'visible'565 } = options;566 if (!['attached', 'detached', 'visible', 'hidden'].includes(state)) throw new Error(`state: expected one of (attached|detached|visible|hidden)`);567 return controller.run(async progress => {568 progress.log(`waiting for selector "${selector}"${state === 'attached' ? '' : ' to be ' + state}`);569 return this.retryWithProgress(progress, selector, options, async (selectorInFrame, continuePolling) => {570 // Be careful, |this| can be different from |frame|.571 // We did not pass omitAttached, so it is non-null.572 const {573 frame,574 info575 } = selectorInFrame;576 const actualScope = this === frame ? scope : undefined;577 const task = dom.waitForSelectorTask(info, state, options.omitReturnValue, actualScope);578 const result = actualScope ? await frame._runWaitForSelectorTaskOnce(progress, (0, _selectorParser.stringifySelector)(info.parsed), info.world, task) : await frame._scheduleRerunnableHandleTask(progress, info.world, task);579 if (!result.asElement()) {580 result.dispose();581 return null;582 }583 if (options.__testHookBeforeAdoptNode) await options.__testHookBeforeAdoptNode();584 const handle = result.asElement();585 try {586 return await handle._adoptTo(await frame._mainContext());587 } catch (e) {588 return continuePolling;589 }590 }, scope);591 }, this._page._timeoutSettings.timeout(options));592 }593 async dispatchEvent(metadata, selector, type, eventInit = {}, options = {}) {594 await this._scheduleRerunnableTask(metadata, selector, (progress, element, data) => {595 progress.injectedScript.dispatchEvent(element, data.type, data.eventInit);596 }, {597 type,598 eventInit599 }, {600 mainWorld: true,601 ...options602 });603 await this._page._doSlowMo();604 }605 async evalOnSelectorAndWaitForSignals(selector, strict, expression, isFunction, arg) {606 const pair = await this.resolveFrameForSelectorNoWait(selector, {607 strict608 });609 const handle = pair ? await this._page.selectors.query(pair.frame, pair.info) : null;610 if (!handle) throw new Error(`Error: failed to find element matching selector "${selector}"`);611 const result = await handle.evaluateExpressionAndWaitForSignals(expression, isFunction, true, arg);612 handle.dispose();613 return result;614 }615 async evalOnSelectorAllAndWaitForSignals(selector, expression, isFunction, arg) {616 const pair = await this.resolveFrameForSelectorNoWait(selector, {});617 if (!pair) throw new Error(`Error: failed to find frame for selector "${selector}"`);618 const arrayHandle = await this._page.selectors._queryArrayInMainWorld(pair.frame, pair.info);619 const result = await arrayHandle.evaluateExpressionAndWaitForSignals(expression, isFunction, true, arg);620 arrayHandle.dispose();621 return result;622 }623 async querySelectorAll(selector) {624 const pair = await this.resolveFrameForSelectorNoWait(selector, {});625 if (!pair) return [];626 return this._page.selectors._queryAll(pair.frame, pair.info, undefined, true627 /* adoptToMain */628 );629 }630 async queryCount(selector) {631 const pair = await this.resolveFrameForSelectorNoWait(selector);632 if (!pair) throw new Error(`Error: failed to find frame for selector "${selector}"`);633 return await this._page.selectors._queryCount(pair.frame, pair.info);634 }635 async content() {636 try {637 const context = await this._utilityContext();638 return await context.evaluate(() => {639 let retVal = '';640 if (document.doctype) retVal = new XMLSerializer().serializeToString(document.doctype);641 if (document.documentElement) retVal += document.documentElement.outerHTML;642 return retVal;643 });644 } catch (e) {645 if (js.isJavaScriptErrorInEvaluate(e) || (0, _protocolError.isSessionClosedError)(e)) throw e;646 throw new Error(`Unable to retrieve content because the page is navigating and changing the content.`);647 }648 }649 async setContent(metadata, html, options = {}) {650 const controller = new _progress.ProgressController(metadata, this);651 return controller.run(progress => this.raceNavigationAction(async () => {652 const waitUntil = options.waitUntil === undefined ? 'load' : options.waitUntil;653 progress.log(`setting frame content, waiting until "${waitUntil}"`);654 const tag = `--playwright--set--content--${this._id}--${++this._setContentCounter}--`;655 const context = await this._utilityContext();656 const lifecyclePromise = new Promise((resolve, reject) => {657 this._page._frameManager._consoleMessageTags.set(tag, () => {658 // Clear lifecycle right after document.open() - see 'tag' below.659 this._onClearLifecycle();660 this._waitForLoadState(progress, waitUntil).then(resolve).catch(reject);661 });662 });663 const contentPromise = context.evaluate(({664 html,665 tag666 }) => {667 window.stop();668 document.open();669 console.debug(tag); // eslint-disable-line no-console670 document.write(html);671 document.close();672 }, {673 html,674 tag675 });676 await Promise.all([contentPromise, lifecyclePromise]);677 await this._page._doSlowMo();678 }), this._page._timeoutSettings.navigationTimeout(options));679 }680 name() {681 return this._name || '';682 }683 url() {684 return this._url;685 }686 parentFrame() {687 return this._parentFrame;688 }689 childFrames() {690 return Array.from(this._childFrames);691 }692 async addScriptTag(params) {693 const {694 url = null,695 content = null,696 type = ''697 } = params;698 if (!url && !content) throw new Error('Provide an object with a `url`, `path` or `content` property');699 const context = await this._mainContext();700 return this._raceWithCSPError(async () => {701 if (url !== null) return (await context.evaluateHandle(addScriptUrl, {702 url,703 type704 })).asElement();705 const result = (await context.evaluateHandle(addScriptContent, {706 content: content,707 type708 })).asElement(); // Another round trip to the browser to ensure that we receive CSP error messages709 // (if any) logged asynchronously in a separate task on the content main thread.710 if (this._page._delegate.cspErrorsAsynchronousForInlineScipts) await context.evaluate(() => true);711 return result;712 });713 async function addScriptUrl(params) {714 const script = document.createElement('script');715 script.src = params.url;716 if (params.type) script.type = params.type;717 const promise = new Promise((res, rej) => {718 script.onload = res;719 script.onerror = e => rej(typeof e === 'string' ? new Error(e) : new Error(`Failed to load script at ${script.src}`));720 });721 document.head.appendChild(script);722 await promise;723 return script;724 }725 function addScriptContent(params) {726 const script = document.createElement('script');727 script.type = params.type || 'text/javascript';728 script.text = params.content;729 let error = null;730 script.onerror = e => error = e;731 document.head.appendChild(script);732 if (error) throw error;733 return script;734 }735 }736 async addStyleTag(params) {737 const {738 url = null,739 content = null740 } = params;741 if (!url && !content) throw new Error('Provide an object with a `url`, `path` or `content` property');742 const context = await this._mainContext();743 return this._raceWithCSPError(async () => {744 if (url !== null) return (await context.evaluateHandle(addStyleUrl, url)).asElement();745 return (await context.evaluateHandle(addStyleContent, content)).asElement();746 });747 async function addStyleUrl(url) {748 const link = document.createElement('link');749 link.rel = 'stylesheet';750 link.href = url;751 const promise = new Promise((res, rej) => {752 link.onload = res;753 link.onerror = rej;754 });755 document.head.appendChild(link);756 await promise;757 return link;758 }759 async function addStyleContent(content) {760 const style = document.createElement('style');761 style.type = 'text/css';762 style.appendChild(document.createTextNode(content));763 const promise = new Promise((res, rej) => {764 style.onload = res;765 style.onerror = rej;766 });767 document.head.appendChild(style);768 await promise;769 return style;770 }771 }772 async _raceWithCSPError(func) {773 const listeners = [];774 let result;775 let error;776 let cspMessage;777 const actionPromise = func().then(r => result = r).catch(e => error = e);778 const errorPromise = new Promise(resolve => {779 listeners.push(_eventsHelper.eventsHelper.addEventListener(this._page, _page.Page.Events.Console, message => {780 if (message.type() === 'error' && message.text().includes('Content Security Policy')) {781 cspMessage = message;782 resolve();783 }784 }));785 });786 await Promise.race([actionPromise, errorPromise]);787 _eventsHelper.eventsHelper.removeEventListeners(listeners);788 if (cspMessage) throw new Error(cspMessage.text());789 if (error) throw error;790 return result;791 }792 async retryWithProgress(progress, selector, options, action, scope) {793 const continuePolling = Symbol('continuePolling');794 while (progress.isRunning()) {795 let selectorInFrame;796 if (options.omitAttached) {797 selectorInFrame = await this.resolveFrameForSelectorNoWait(selector, options, scope);798 } else {799 selectorInFrame = await this._resolveFrameForSelector(progress, selector, options, scope);800 if (!selectorInFrame) {801 // Missing content frame.802 await new Promise(f => setTimeout(f, 100));803 continue;804 }805 }806 try {807 const result = await action(selectorInFrame, continuePolling);808 if (result === continuePolling) continue;809 return result;810 } catch (e) {811 var _selectorInFrame;812 // Always fail on JavaScript errors or when the main connection is closed.813 if (js.isJavaScriptErrorInEvaluate(e) || (0, _protocolError.isSessionClosedError)(e)) throw e; // Certain error opt-out of the retries, throw.814 if (dom.isNonRecoverableDOMError(e)) throw e; // If the call is made on the detached frame - throw.815 if (this.isDetached()) throw e; // If there is scope, and scope is within the frame we use to select, assume context is destroyed and816 // operation is not recoverable.817 if (scope && scope._context.frame === ((_selectorInFrame = selectorInFrame) === null || _selectorInFrame === void 0 ? void 0 : _selectorInFrame.frame)) throw e; // Retry upon all other errors.818 continue;819 }820 }821 progress.throwIfAborted();822 return undefined;823 }824 async _retryWithProgressIfNotConnected(progress, selector, strict, action) {825 return this.retryWithProgress(progress, selector, {826 strict827 }, async (selectorInFrame, continuePolling) => {828 // We did not pass omitAttached, so selectorInFrame is not null.829 const {830 frame,831 info832 } = selectorInFrame; // Be careful, |this| can be different from |frame|.833 const task = dom.waitForSelectorTask(info, 'attached');834 progress.log(`waiting for selector "${selector}"`);835 const handle = await frame._scheduleRerunnableHandleTask(progress, info.world, task);836 const element = handle.asElement();837 try {838 const result = await action(element);839 if (result === 'error:notconnected') {840 progress.log('element was detached from the DOM, retrying');841 return continuePolling;842 }843 return result;844 } finally {845 element === null || element === void 0 ? void 0 : element.dispose();846 }847 });848 }849 async click(metadata, selector, options) {850 const controller = new _progress.ProgressController(metadata, this);851 return controller.run(async progress => {852 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._click(progress, options)));853 }, this._page._timeoutSettings.timeout(options));854 }855 async dblclick(metadata, selector, options = {}) {856 const controller = new _progress.ProgressController(metadata, this);857 return controller.run(async progress => {858 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._dblclick(progress, options)));859 }, this._page._timeoutSettings.timeout(options));860 }861 async dragAndDrop(metadata, source, target, options = {}) {862 const controller = new _progress.ProgressController(metadata, this);863 await controller.run(async progress => {864 dom.assertDone(await this._retryWithProgressIfNotConnected(progress, source, options.strict, async handle => {865 return handle._retryPointerAction(progress, 'move and down', false, async point => {866 await this._page.mouse.move(point.x, point.y);867 await this._page.mouse.down();868 }, { ...options,869 position: options.sourcePosition,870 timeout: progress.timeUntilDeadline()871 });872 }));873 dom.assertDone(await this._retryWithProgressIfNotConnected(progress, target, options.strict, async handle => {874 return handle._retryPointerAction(progress, 'move and up', false, async point => {875 await this._page.mouse.move(point.x, point.y);876 await this._page.mouse.up();877 }, { ...options,878 position: options.targetPosition,879 timeout: progress.timeUntilDeadline()880 });881 }));882 }, this._page._timeoutSettings.timeout(options));883 }884 async tap(metadata, selector, options) {885 const controller = new _progress.ProgressController(metadata, this);886 return controller.run(async progress => {887 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._tap(progress, options)));888 }, this._page._timeoutSettings.timeout(options));889 }890 async fill(metadata, selector, value, options) {891 const controller = new _progress.ProgressController(metadata, this);892 return controller.run(async progress => {893 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._fill(progress, value, options)));894 }, this._page._timeoutSettings.timeout(options));895 }896 async focus(metadata, selector, options = {}) {897 const controller = new _progress.ProgressController(metadata, this);898 await controller.run(async progress => {899 dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._focus(progress)));900 await this._page._doSlowMo();901 }, this._page._timeoutSettings.timeout(options));902 }903 async textContent(metadata, selector, options = {}) {904 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => element.textContent, undefined, options);905 }906 async innerText(metadata, selector, options = {}) {907 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => {908 if (element.namespaceURI !== 'http://www.w3.org/1999/xhtml') throw progress.injectedScript.createStacklessError('Node is not an HTMLElement');909 return element.innerText;910 }, undefined, options);911 }912 async innerHTML(metadata, selector, options = {}) {913 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => element.innerHTML, undefined, options);914 }915 async getAttribute(metadata, selector, name, options = {}) {916 return this._scheduleRerunnableTask(metadata, selector, (progress, element, data) => element.getAttribute(data.name), {917 name918 }, options);919 }920 async inputValue(metadata, selector, options = {}) {921 return this._scheduleRerunnableTask(metadata, selector, (progress, node) => {922 const element = progress.injectedScript.retarget(node, 'follow-label');923 if (!element || element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA' && element.nodeName !== 'SELECT') throw progress.injectedScript.createStacklessError('Node is not an <input>, <textarea> or <select> element');924 return element.value;925 }, undefined, options);926 }927 async highlight(selector) {928 const pair = await this.resolveFrameForSelectorNoWait(selector);929 if (!pair) return;930 const context = await this._utilityContext();931 const injectedScript = await context.injectedScript();932 return await injectedScript.evaluate((injected, {933 parsed934 }) => {935 return injected.highlight(parsed);936 }, {937 parsed: pair.info.parsed938 });939 }940 async hideHighlight() {941 const context = await this._utilityContext();942 const injectedScript = await context.injectedScript();943 return await injectedScript.evaluate(injected => {944 return injected.hideHighlight();945 });946 }947 async _elementState(metadata, selector, state, options = {}) {948 const result = await this._scheduleRerunnableTask(metadata, selector, (progress, element, data) => {949 const injected = progress.injectedScript;950 return injected.elementState(element, data.state);951 }, {952 state953 }, options);954 return dom.throwRetargetableDOMError(result);955 }956 async isVisible(metadata, selector, options = {}) {957 const controller = new _progress.ProgressController(metadata, this);958 return controller.run(async progress => {959 progress.log(` checking visibility of "${selector}"`);960 const pair = await this.resolveFrameForSelectorNoWait(selector, options);961 if (!pair) return false;962 const element = await this._page.selectors.query(pair.frame, pair.info);963 return element ? await element.isVisible() : false;964 }, this._page._timeoutSettings.timeout({}));965 }966 async isHidden(metadata, selector, options = {}) {967 return !(await this.isVisible(metadata, selector, options));968 }969 async isDisabled(metadata, selector, options = {}) {970 return this._elementState(metadata, selector, 'disabled', options);971 }972 async isEnabled(metadata, selector, options = {}) {973 return this._elementState(metadata, selector, 'enabled', options);974 }975 async isEditable(metadata, selector, options = {}) {976 return this._elementState(metadata, selector, 'editable', options);977 }978 async isChecked(metadata, selector, options = {}) {979 return this._elementState(metadata, selector, 'checked', options);980 }981 async hover(metadata, selector, options = {}) {982 const controller = new _progress.ProgressController(metadata, this);983 return controller.run(async progress => {984 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._hover(progress, options)));985 }, this._page._timeoutSettings.timeout(options));986 }987 async selectOption(metadata, selector, elements, values, options = {}) {988 const controller = new _progress.ProgressController(metadata, this);989 return controller.run(async progress => {990 return await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._selectOption(progress, elements, values, options));991 }, this._page._timeoutSettings.timeout(options));992 }993 async setInputFiles(metadata, selector, files, options = {}) {994 const controller = new _progress.ProgressController(metadata, this);995 return controller.run(async progress => {996 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._setInputFiles(progress, files, options)));997 }, this._page._timeoutSettings.timeout(options));998 }999 async type(metadata, selector, text, options = {}) {1000 const controller = new _progress.ProgressController(metadata, this);1001 return controller.run(async progress => {1002 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._type(progress, text, options)));1003 }, this._page._timeoutSettings.timeout(options));1004 }1005 async press(metadata, selector, key, options = {}) {1006 const controller = new _progress.ProgressController(metadata, this);1007 return controller.run(async progress => {1008 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._press(progress, key, options)));1009 }, this._page._timeoutSettings.timeout(options));1010 }1011 async check(metadata, selector, options = {}) {1012 const controller = new _progress.ProgressController(metadata, this);1013 return controller.run(async progress => {1014 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._setChecked(progress, true, options)));1015 }, this._page._timeoutSettings.timeout(options));1016 }1017 async uncheck(metadata, selector, options = {}) {1018 const controller = new _progress.ProgressController(metadata, this);1019 return controller.run(async progress => {1020 return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, handle => handle._setChecked(progress, false, options)));1021 }, this._page._timeoutSettings.timeout(options));1022 }1023 async waitForTimeout(metadata, timeout) {1024 const controller = new _progress.ProgressController(metadata, this);1025 return controller.run(async () => {1026 await new Promise(resolve => setTimeout(resolve, timeout));1027 });1028 }1029 async expect(metadata, selector, options) {1030 const controller = new _progress.ProgressController(metadata, this);1031 const isArray = options.expression === 'to.have.count' || options.expression.endsWith('.array');1032 const mainWorld = options.expression === 'to.have.property';1033 const timeout = this._page._timeoutSettings.timeout(options); // List all combinations that are satisfied with the detached node(s).1034 let omitAttached = false;1035 if (!options.isNot && options.expression === 'to.be.hidden') omitAttached = true;else if (options.isNot && options.expression === 'to.be.visible') omitAttached = true;else if (!options.isNot && options.expression === 'to.have.count' && options.expectedNumber === 0) omitAttached = true;else if (options.isNot && options.expression === 'to.have.count' && options.expectedNumber !== 0) omitAttached = true;else if (!options.isNot && options.expression.endsWith('.array') && options.expectedText.length === 0) omitAttached = true;else if (options.isNot && options.expression.endsWith('.array') && options.expectedText.length > 0) omitAttached = true;1036 return controller.run(async outerProgress => {1037 outerProgress.log(`${metadata.apiName}${timeout ? ` with timeout ${timeout}ms` : ''}`);1038 return await this._scheduleRerunnableTaskWithProgress(outerProgress, selector, (progress, element, options, elements) => {1039 let result;1040 if (options.isArray) {1041 result = progress.injectedScript.expectArray(elements, options);1042 } else {1043 if (!element) {1044 // expect(locator).toBeHidden() passes when there is no element.1045 if (!options.isNot && options.expression === 'to.be.hidden') return {1046 matches: true1047 }; // expect(locator).not.toBeVisible() passes when there is no element.1048 if (options.isNot && options.expression === 'to.be.visible') return {1049 matches: false1050 }; // When none of the above applies, keep waiting for the element.1051 return progress.continuePolling;1052 }1053 result = progress.injectedScript.expectSingleElement(progress, element, options);1054 }1055 if (result.matches === options.isNot) {1056 // Keep waiting in these cases:1057 // expect(locator).conditionThatDoesNotMatch1058 // expect(locator).not.conditionThatDoesMatch1059 progress.setIntermediateResult(result.received);1060 if (!Array.isArray(result.received)) progress.log(` unexpected value "${result.received}"`);1061 return progress.continuePolling;1062 } // Reached the expected state!1063 return result;1064 }, { ...options,1065 isArray1066 }, {1067 strict: true,1068 querySelectorAll: isArray,1069 mainWorld,1070 omitAttached,1071 logScale: true,1072 ...options1073 });1074 }, timeout).catch(e => {1075 // Q: Why not throw upon isSessionClosedError(e) as in other places?1076 // A: We want user to receive a friendly message containing the last intermediate result.1077 if (js.isJavaScriptErrorInEvaluate(e) || (0, _selectorErrors.isInvalidSelectorError)(e)) throw e;1078 return {1079 received: controller.lastIntermediateResult(),1080 matches: options.isNot,1081 log: metadata.log1082 };1083 });1084 }1085 async _waitForFunctionExpression(metadata, expression, isFunction, arg, options, world = 'main') {1086 const controller = new _progress.ProgressController(metadata, this);1087 if (typeof options.pollingInterval === 'number') (0, _utils.assert)(options.pollingInterval > 0, 'Cannot poll with non-positive interval: ' + options.pollingInterval);1088 expression = js.normalizeEvaluationExpression(expression, isFunction);1089 const task = injectedScript => injectedScript.evaluateHandle((injectedScript, {1090 expression,1091 isFunction,1092 polling,1093 arg1094 }) => {1095 const predicate = arg => {1096 let result = self.eval(expression);1097 if (isFunction === true) {1098 result = result(arg);1099 } else if (isFunction === false) {1100 result = result;1101 } else {1102 // auto detect.1103 if (typeof result === 'function') result = result(arg);1104 }1105 return result;1106 };1107 if (typeof polling !== 'number') return injectedScript.pollRaf(progress => predicate(arg) || progress.continuePolling);1108 return injectedScript.pollInterval(polling, progress => predicate(arg) || progress.continuePolling);1109 }, {1110 expression,1111 isFunction,1112 polling: options.pollingInterval,1113 arg1114 });1115 return controller.run(progress => this._scheduleRerunnableHandleTask(progress, world, task), this._page._timeoutSettings.timeout(options));1116 }1117 async waitForFunctionValueInUtility(progress, pageFunction) {1118 const expression = `() => {1119 const result = (${pageFunction})();1120 if (!result)1121 return result;1122 return JSON.stringify(result);1123 }`;1124 const handle = await this._waitForFunctionExpression((0, _instrumentation.internalCallMetadata)(), expression, true, undefined, {1125 timeout: progress.timeUntilDeadline()1126 }, 'utility');1127 return JSON.parse(handle.rawValue());1128 }1129 async title() {1130 const context = await this._utilityContext();1131 return context.evaluate(() => document.title);1132 }1133 _onDetached() {1134 this._stopNetworkIdleTimer();1135 this._detached = true;1136 this._detachedCallback();1137 const error = new Error('Frame was detached');1138 for (const data of this._contextData.values()) {1139 if (data.context) data.context.contextDestroyed(error);1140 data.contextPromise.resolve(error);1141 for (const rerunnableTask of data.rerunnableTasks) rerunnableTask.terminate(error);1142 }1143 if (this._parentFrame) this._parentFrame._childFrames.delete(this);1144 this._parentFrame = null;1145 }1146 async _scheduleRerunnableTask(metadata, selector, body, taskData, options = {}) {1147 const controller = new _progress.ProgressController(metadata, this);1148 return controller.run(async progress => {1149 return await this._scheduleRerunnableTaskWithProgress(progress, selector, body, taskData, options);1150 }, this._page._timeoutSettings.timeout(options));1151 }1152 async _scheduleRerunnableTaskWithProgress(progress, selector, body, taskData, options = {}) {1153 const callbackText = body.toString();1154 return this.retryWithProgress(progress, selector, options, async selectorInFrame => {1155 // Be careful, |this| can be different from |frame|.1156 progress.log(`waiting for selector "${selector}"`);1157 const {1158 frame,1159 info1160 } = selectorInFrame || {1161 frame: this,1162 info: {1163 parsed: {1164 parts: [{1165 name: 'control',1166 body: 'return-empty',1167 source: 'control=return-empty'1168 }]1169 },1170 world: 'utility',1171 strict: !!options.strict1172 }1173 };1174 return await frame._scheduleRerunnableTaskInFrame(progress, info, callbackText, taskData, options);1175 });1176 }1177 async _scheduleRerunnableTaskInFrame(progress, info, callbackText, taskData, options) {1178 progress.throwIfAborted();1179 const data = this._contextData.get(options.mainWorld ? 'main' : info.world); // This potentially runs in a sub-frame.1180 {1181 const rerunnableTask = new RerunnableTask(data, progress, injectedScript => {1182 return injectedScript.evaluateHandle((injected, {1183 info,1184 taskData,1185 callbackText,1186 querySelectorAll,1187 logScale,1188 omitAttached,1189 snapshotName1190 }) => {1191 const callback = injected.eval(callbackText);1192 const poller = logScale ? injected.pollLogScale.bind(injected) : injected.pollRaf.bind(injected);1193 let markedElements = new Set();1194 return poller(progress => {1195 let element;1196 let elements = [];1197 if (querySelectorAll) {1198 elements = injected.querySelectorAll(info.parsed, document);1199 element = elements[0];1200 progress.logRepeating(` selector resolved to ${elements.length} element${elements.length === 1 ? '' : 's'}`);1201 } else {1202 element = injected.querySelector(info.parsed, document, info.strict);1203 elements = element ? [element] : [];1204 if (element) progress.logRepeating(` selector resolved to ${injected.previewNode(element)}`);1205 }1206 if (!element && !omitAttached) return progress.continuePolling;1207 if (snapshotName) {1208 const previouslyMarkedElements = markedElements;1209 markedElements = new Set(elements);1210 for (const e of previouslyMarkedElements) {1211 if (!markedElements.has(e)) e.removeAttribute('__playwright_target__');1212 }1213 for (const e of markedElements) {1214 if (!previouslyMarkedElements.has(e)) e.setAttribute('__playwright_target__', snapshotName);1215 }1216 }1217 return callback(progress, element, taskData, elements);1218 });1219 }, {1220 info,1221 taskData,1222 callbackText,1223 querySelectorAll: options.querySelectorAll,1224 logScale: options.logScale,1225 omitAttached: options.omitAttached,1226 snapshotName: progress.metadata.afterSnapshot1227 });1228 }, true);1229 if (this._detached) rerunnableTask.terminate(new Error('Frame got detached.'));1230 if (data.context) rerunnableTask.rerun(data.context);1231 return await rerunnableTask.promise;1232 }1233 }1234 _scheduleRerunnableHandleTask(progress, world, task) {1235 const data = this._contextData.get(world);1236 const rerunnableTask = new RerunnableTask(data, progress, task, false1237 /* returnByValue */1238 );1239 if (this._detached) rerunnableTask.terminate(new Error('waitForFunction failed: frame got detached.'));1240 if (data.context) rerunnableTask.rerun(data.context);1241 return rerunnableTask.handlePromise;1242 }1243 _setContext(world, context) {1244 const data = this._contextData.get(world);1245 data.context = context;1246 if (context) {1247 data.contextPromise.resolve(context);1248 for (const rerunnableTask of data.rerunnableTasks) rerunnableTask.rerun(context);1249 } else {1250 data.contextPromise = new _async.ManualPromise();1251 }1252 }1253 _contextCreated(world, context) {1254 const data = this._contextData.get(world); // In case of multiple sessions to the same target, there's a race between1255 // connections so we might end up creating multiple isolated worlds.1256 // We can use either.1257 if (data.context) {1258 data.context.contextDestroyed(new Error('Execution context was destroyed, most likely because of a navigation'));1259 this._setContext(world, null);1260 }1261 this._setContext(world, context);1262 }1263 _contextDestroyed(context) {1264 // Sometimes we get this after detach, in which case we should not reset1265 // our already destroyed contexts to something that will never resolve.1266 if (this._detached) return;1267 context.contextDestroyed(new Error('Execution context was destroyed, most likely because of a navigation'));1268 for (const [world, data] of this._contextData) {1269 if (data.context === context) this._setContext(world, null);1270 }1271 }1272 _startNetworkIdleTimer() {1273 (0, _utils.assert)(!this._networkIdleTimer); // We should not start a timer and report networkidle in detached frames.1274 // This happens at least in Firefox for child frames, where we may get requestFinished1275 // after the frame was detached - probably a race in the Firefox itself.1276 if (this._firedLifecycleEvents.has('networkidle') || this._detached) return;1277 this._networkIdleTimer = setTimeout(() => this._onLifecycleEvent('networkidle'), 500);1278 }1279 _stopNetworkIdleTimer() {1280 if (this._networkIdleTimer) clearTimeout(this._networkIdleTimer);1281 this._networkIdleTimer = undefined;1282 }1283 async extendInjectedScript(source, arg) {1284 const context = await this._context('main');1285 const injectedScriptHandle = await context.injectedScript();1286 return injectedScriptHandle.evaluateHandle((injectedScript, {1287 source,1288 arg1289 }) => {1290 return injectedScript.extend(source, arg);1291 }, {1292 source,1293 arg1294 });1295 }1296 async _resolveFrameForSelector(progress, selector, options, scope) {1297 const elementPath = [];1298 progress.cleanupWhenAborted(() => {1299 // Do not await here to avoid being blocked, either by stalled1300 // page (e.g. alert) or unresolved navigation in Chromium.1301 for (const element of elementPath) element.dispose();1302 });1303 let frame = this;1304 const frameChunks = (0, _selectorParser.splitSelectorByFrame)(selector);1305 for (let i = 0; i < frameChunks.length - 1 && progress.isRunning(); ++i) {1306 const info = this._page.parseSelector(frameChunks[i], options);1307 const task = dom.waitForSelectorTask(info, 'attached', false, i === 0 ? scope : undefined);1308 progress.log(` waiting for frame "${(0, _selectorParser.stringifySelector)(frameChunks[i])}"`);1309 const handle = i === 0 && scope ? await frame._runWaitForSelectorTaskOnce(progress, (0, _selectorParser.stringifySelector)(info.parsed), info.world, task) : await frame._scheduleRerunnableHandleTask(progress, info.world, task);1310 const element = handle.asElement();1311 const isIframe = await element.isIframeElement();1312 if (isIframe === 'error:notconnected') return null; // retry1313 if (!isIframe) throw new Error(`Selector "${(0, _selectorParser.stringifySelector)(info.parsed)}" resolved to ${element.preview()}, <iframe> was expected`);1314 frame = await element.contentFrame();1315 element.dispose();1316 if (!frame) return null; // retry1317 }1318 return {1319 frame,1320 info: this._page.parseSelector(frameChunks[frameChunks.length - 1], options)1321 };1322 }1323 async resolveFrameForSelectorNoWait(selector, options = {}, scope) {1324 let frame = this;1325 const frameChunks = (0, _selectorParser.splitSelectorByFrame)(selector);1326 for (let i = 0; i < frameChunks.length - 1; ++i) {1327 const info = this._page.parseSelector(frameChunks[i], options);1328 const element = await this._page.selectors.query(frame, info, i === 0 ? scope : undefined);1329 if (!element) return null;1330 frame = await element.contentFrame();1331 element.dispose();1332 if (!frame) throw new Error(`Selector "${(0, _selectorParser.stringifySelector)(info.parsed)}" resolved to ${element.preview()}, <iframe> was expected`);1333 }1334 return {1335 frame,1336 info: this._page.parseSelector(frameChunks[frameChunks.length - 1], options)1337 };1338 }1339 async _runWaitForSelectorTaskOnce(progress, selector, world, task) {1340 const context = await this._context(world);1341 const injected = await context.injectedScript();1342 try {1343 const pollHandler = new dom.InjectedScriptPollHandler(progress, await task(injected));1344 const result = await pollHandler.finishHandle();1345 progress.cleanupWhenAborted(() => result.dispose());1346 return result;1347 } catch (e) {1348 throw new Error(`Error: frame navigated while waiting for selector "${selector}"`);1349 }1350 }1351}1352exports.Frame = Frame;1353Frame.Events = {1354 Navigation: 'navigation',1355 AddLifecycle: 'addlifecycle',1356 RemoveLifecycle: 'removelifecycle'1357};1358class RerunnableTask {1359 constructor(data, progress, task, returnByValue) {1360 this.promise = void 0;1361 this.handlePromise = void 0;1362 this._task = void 0;1363 this._progress = void 0;1364 this._returnByValue = void 0;1365 this._contextData = void 0;1366 this._task = task;1367 this._progress = progress;1368 this._returnByValue = returnByValue;1369 if (returnByValue) this.promise = new _async.ManualPromise();else this.handlePromise = new _async.ManualPromise();1370 this._contextData = data;1371 this._contextData.rerunnableTasks.add(this);1372 }1373 terminate(error) {1374 this._reject(error);1375 }1376 _resolve(value) {1377 if (this.promise) this.promise.resolve(value);1378 if (this.handlePromise) this.handlePromise.resolve(value);1379 }1380 _reject(error) {1381 if (this.promise) this.promise.reject(error);1382 if (this.handlePromise) this.handlePromise.reject(error);1383 }1384 async rerun(context) {1385 try {1386 const injectedScript = await context.injectedScript();1387 const pollHandler = new dom.InjectedScriptPollHandler(this._progress, await this._task(injectedScript));1388 const result = this._returnByValue ? await pollHandler.finish() : await pollHandler.finishHandle();1389 this._contextData.rerunnableTasks.delete(this);1390 this._resolve(result);1391 } catch (e) {1392 if (js.isJavaScriptErrorInEvaluate(e) || (0, _protocolError.isSessionClosedError)(e)) {1393 this._contextData.rerunnableTasks.delete(this);1394 this._reject(e);1395 } // Unlike other places, we don't check frame for being detached since the whole scope of this1396 // evaluation is within the frame's execution context. So we only let JavaScript errors and1397 // session termination errors go through.1398 // We will try again in the new execution context.1399 }1400 }1401}1402class SignalBarrier {1403 constructor(progress) {1404 this._progress = void 0;1405 this._protectCount = 0;1406 this._promise = new _async.ManualPromise();1407 this._progress = progress;1408 this.retain();1409 }1410 waitFor() {1411 this.release();1412 return this._promise;1413 }1414 async addFrameNavigation(frame) {1415 // Auto-wait top-level navigations only.1416 if (frame.parentFrame()) return;1417 this.retain();1418 const waiter = _helper.helper.waitForEvent(null, frame, Frame.Events.Navigation, e => {1419 if (!e.error && this._progress) this._progress.log(` navigated to "${frame._url}"`);1420 return true;1421 });1422 await Promise.race([frame._page._disconnectedPromise, frame._page._crashedPromise, frame._detachedPromise, waiter.promise]).catch(e => {});1423 waiter.dispose();1424 this.release();1425 }1426 retain() {1427 ++this._protectCount;1428 }1429 release() {1430 --this._protectCount;1431 if (!this._protectCount) this._promise.resolve();1432 }1433}1434function verifyLifecycle(name, waitUntil) {1435 if (waitUntil === 'networkidle0') waitUntil = 'networkidle';1436 if (!types.kLifecycleEvents.has(waitUntil)) throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`);1437 return waitUntil;...
page.js
Source:page.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5exports.Worker = exports.PageBinding = exports.Page = void 0;6var frames = _interopRequireWildcard(require("./frames"));7var input = _interopRequireWildcard(require("./input"));8var js = _interopRequireWildcard(require("./javascript"));9var network = _interopRequireWildcard(require("./network"));10var _screenshotter = require("./screenshotter");11var _timeoutSettings = require("../utils/timeoutSettings");12var _browserContext = require("./browserContext");13var _console = require("./console");14var accessibility = _interopRequireWildcard(require("./accessibility"));15var _fileChooser = require("./fileChooser");16var _progress = require("./progress");17var _utils = require("../utils/utils");18var _async = require("../utils/async");19var _debugLogger = require("../utils/debugLogger");20var _comparators = require("../utils/comparators");21var _instrumentation = require("./instrumentation");22var _selectorParser = require("./common/selectorParser");23function _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); }24function _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; }25/**26 * Copyright 2017 Google Inc. All rights reserved.27 * Modifications copyright (c) Microsoft Corporation.28 *29 * Licensed under the Apache License, Version 2.0 (the "License");30 * you may not use this file except in compliance with the License.31 * You may obtain a copy of the License at32 *33 * http://www.apache.org/licenses/LICENSE-2.034 *35 * Unless required by applicable law or agreed to in writing, software36 * distributed under the License is distributed on an "AS IS" BASIS,37 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.38 * See the License for the specific language governing permissions and39 * limitations under the License.40 */41class Page extends _instrumentation.SdkObject {42 constructor(delegate, browserContext) {43 super(browserContext, 'page');44 this._closedState = 'open';45 this._closedPromise = new _async.ManualPromise();46 this._disconnected = false;47 this._initialized = false;48 this._disconnectedPromise = new _async.ManualPromise();49 this._crashedPromise = new _async.ManualPromise();50 this._browserContext = void 0;51 this.keyboard = void 0;52 this.mouse = void 0;53 this.touchscreen = void 0;54 this._timeoutSettings = void 0;55 this._delegate = void 0;56 this._state = void 0;57 this._pageBindings = new Map();58 this._evaluateOnNewDocumentSources = [];59 this._screenshotter = void 0;60 this._frameManager = void 0;61 this.accessibility = void 0;62 this._workers = new Map();63 this.pdf = void 0;64 this.coverage = void 0;65 this._clientRequestInterceptor = void 0;66 this._serverRequestInterceptor = void 0;67 this._ownedContext = void 0;68 this.selectors = void 0;69 this._pageIsError = void 0;70 this._video = null;71 this._opener = void 0;72 this._frameThrottler = new FrameThrottler(10, 200);73 this.attribution.page = this;74 this._delegate = delegate;75 this._browserContext = browserContext;76 this._state = {77 emulatedSize: browserContext._options.viewport ? {78 viewport: browserContext._options.viewport,79 screen: browserContext._options.screen || browserContext._options.viewport80 } : null,81 mediaType: null,82 colorScheme: browserContext._options.colorScheme !== undefined ? browserContext._options.colorScheme : 'light',83 reducedMotion: browserContext._options.reducedMotion !== undefined ? browserContext._options.reducedMotion : 'no-preference',84 forcedColors: browserContext._options.forcedColors !== undefined ? browserContext._options.forcedColors : 'none',85 extraHTTPHeaders: null86 };87 this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate));88 this.keyboard = new input.Keyboard(delegate.rawKeyboard, this);89 this.mouse = new input.Mouse(delegate.rawMouse, this);90 this.touchscreen = new input.Touchscreen(delegate.rawTouchscreen, this);91 this._timeoutSettings = new _timeoutSettings.TimeoutSettings(browserContext._timeoutSettings);92 this._screenshotter = new _screenshotter.Screenshotter(this);93 this._frameManager = new frames.FrameManager(this);94 if (delegate.pdf) this.pdf = delegate.pdf.bind(delegate);95 this.coverage = delegate.coverage ? delegate.coverage() : null;96 this.selectors = browserContext.selectors();97 this.instrumentation.onPageOpen(this);98 }99 async initOpener(opener) {100 if (!opener) return;101 const openerPage = await opener.pageOrError();102 if (openerPage instanceof Page && !openerPage.isClosed()) this._opener = openerPage;103 }104 reportAsNew(error) {105 if (error) {106 // Initialization error could have happened because of107 // context/browser closure. Just ignore the page.108 if (this._browserContext.isClosingOrClosed()) return;109 this._setIsError(error);110 }111 this._initialized = true;112 this._browserContext.emit(_browserContext.BrowserContext.Events.Page, this); // I may happen that page iniatialization finishes after Close event has already been sent,113 // in that case we fire another Close event to ensure that each reported Page will have114 // corresponding Close event after it is reported on the context.115 if (this.isClosed()) this.emit(Page.Events.Close);116 }117 initializedOrUndefined() {118 return this._initialized ? this : undefined;119 }120 async _doSlowMo() {121 const slowMo = this._browserContext._browser.options.slowMo;122 if (!slowMo) return;123 await new Promise(x => setTimeout(x, slowMo));124 }125 _didClose() {126 this.instrumentation.onPageClose(this);127 this._frameManager.dispose();128 this._frameThrottler.setEnabled(false);129 (0, _utils.assert)(this._closedState !== 'closed', 'Page closed twice');130 this._closedState = 'closed';131 this.emit(Page.Events.Close);132 this._closedPromise.resolve();133 }134 _didCrash() {135 this.instrumentation.onPageClose(this);136 this._frameManager.dispose();137 this._frameThrottler.setEnabled(false);138 this.emit(Page.Events.Crash);139 this._crashedPromise.resolve(new Error('Page crashed'));140 }141 _didDisconnect() {142 this.instrumentation.onPageClose(this);143 this._frameManager.dispose();144 this._frameThrottler.setEnabled(false);145 (0, _utils.assert)(!this._disconnected, 'Page disconnected twice');146 this._disconnected = true;147 this._disconnectedPromise.resolve(new Error('Page closed'));148 }149 async _onFileChooserOpened(handle) {150 let multiple;151 try {152 multiple = await handle.evaluate(element => !!element.multiple);153 } catch (e) {154 // Frame/context may be gone during async processing. Do not throw.155 return;156 }157 if (!this.listenerCount(Page.Events.FileChooser)) {158 handle.dispose();159 return;160 }161 const fileChooser = new _fileChooser.FileChooser(this, handle, multiple);162 this.emit(Page.Events.FileChooser, fileChooser);163 }164 context() {165 return this._browserContext;166 }167 opener() {168 return this._opener;169 }170 mainFrame() {171 return this._frameManager.mainFrame();172 }173 frames() {174 return this._frameManager.frames();175 }176 setDefaultNavigationTimeout(timeout) {177 this._timeoutSettings.setDefaultNavigationTimeout(timeout);178 }179 setDefaultTimeout(timeout) {180 this._timeoutSettings.setDefaultTimeout(timeout);181 }182 async exposeBinding(name, needsHandle, playwrightBinding) {183 if (this._pageBindings.has(name)) throw new Error(`Function "${name}" has been already registered`);184 if (this._browserContext._pageBindings.has(name)) throw new Error(`Function "${name}" has been already registered in the browser context`);185 const binding = new PageBinding(name, playwrightBinding, needsHandle);186 this._pageBindings.set(name, binding);187 await this._delegate.exposeBinding(binding);188 }189 setExtraHTTPHeaders(headers) {190 this._state.extraHTTPHeaders = headers;191 return this._delegate.updateExtraHTTPHeaders();192 }193 async _onBindingCalled(payload, context) {194 if (this._disconnected || this._closedState === 'closed') return;195 await PageBinding.dispatch(this, payload, context);196 }197 _addConsoleMessage(type, args, location, text) {198 const message = new _console.ConsoleMessage(this, type, text, args, location);199 const intercepted = this._frameManager.interceptConsoleMessage(message);200 if (intercepted || !this.listenerCount(Page.Events.Console)) args.forEach(arg => arg.dispose());else this.emit(Page.Events.Console, message);201 }202 async reload(metadata, options) {203 const controller = new _progress.ProgressController(metadata, this);204 return controller.run(progress => this.mainFrame().raceNavigationAction(async () => {205 // Note: waitForNavigation may fail before we get response to reload(),206 // so we should await it immediately.207 const [response] = await Promise.all([this.mainFrame()._waitForNavigation(progress, options), this._delegate.reload()]);208 await this._doSlowMo();209 return response;210 }), this._timeoutSettings.navigationTimeout(options));211 }212 async goBack(metadata, options) {213 const controller = new _progress.ProgressController(metadata, this);214 return controller.run(progress => this.mainFrame().raceNavigationAction(async () => {215 // Note: waitForNavigation may fail before we get response to goBack,216 // so we should catch it immediately.217 let error;218 const waitPromise = this.mainFrame()._waitForNavigation(progress, options).catch(e => {219 error = e;220 return null;221 });222 const result = await this._delegate.goBack();223 if (!result) return null;224 const response = await waitPromise;225 if (error) throw error;226 await this._doSlowMo();227 return response;228 }), this._timeoutSettings.navigationTimeout(options));229 }230 async goForward(metadata, options) {231 const controller = new _progress.ProgressController(metadata, this);232 return controller.run(progress => this.mainFrame().raceNavigationAction(async () => {233 // Note: waitForNavigation may fail before we get response to goForward,234 // so we should catch it immediately.235 let error;236 const waitPromise = this.mainFrame()._waitForNavigation(progress, options).catch(e => {237 error = e;238 return null;239 });240 const result = await this._delegate.goForward();241 if (!result) return null;242 const response = await waitPromise;243 if (error) throw error;244 await this._doSlowMo();245 return response;246 }), this._timeoutSettings.navigationTimeout(options));247 }248 async emulateMedia(options) {249 if (options.media !== undefined) this._state.mediaType = options.media;250 if (options.colorScheme !== undefined) this._state.colorScheme = options.colorScheme;251 if (options.reducedMotion !== undefined) this._state.reducedMotion = options.reducedMotion;252 if (options.forcedColors !== undefined) this._state.forcedColors = options.forcedColors;253 await this._delegate.updateEmulateMedia();254 await this._doSlowMo();255 }256 async setViewportSize(viewportSize) {257 this._state.emulatedSize = {258 viewport: { ...viewportSize259 },260 screen: { ...viewportSize261 }262 };263 await this._delegate.setEmulatedSize(this._state.emulatedSize);264 await this._doSlowMo();265 }266 viewportSize() {267 var _this$_state$emulated;268 return ((_this$_state$emulated = this._state.emulatedSize) === null || _this$_state$emulated === void 0 ? void 0 : _this$_state$emulated.viewport) || null;269 }270 async bringToFront() {271 await this._delegate.bringToFront();272 }273 async _addInitScriptExpression(source) {274 this._evaluateOnNewDocumentSources.push(source);275 await this._delegate.evaluateOnNewDocument(source);276 }277 _needsRequestInterception() {278 return !!this._clientRequestInterceptor || !!this._serverRequestInterceptor || !!this._browserContext._requestInterceptor;279 }280 async _setClientRequestInterceptor(handler) {281 this._clientRequestInterceptor = handler;282 await this._delegate.updateRequestInterception();283 }284 async _setServerRequestInterceptor(handler) {285 this._serverRequestInterceptor = handler;286 await this._delegate.updateRequestInterception();287 }288 _requestStarted(request, routeDelegate) {289 const route = new network.Route(request, routeDelegate);290 if (this._serverRequestInterceptor) {291 this._serverRequestInterceptor(route, request);292 return;293 }294 if (this._clientRequestInterceptor) {295 this._clientRequestInterceptor(route, request);296 return;297 }298 if (this._browserContext._requestInterceptor) {299 this._browserContext._requestInterceptor(route, request);300 return;301 }302 route.continue();303 }304 async expectScreenshot(metadata, options = {}) {305 const locator = options.locator;306 const rafrafScreenshot = locator ? async (progress, timeout) => {307 return await locator.frame.rafrafTimeoutScreenshotElementWithProgress(progress, locator.selector, timeout, options.screenshotOptions || {});308 } : async (progress, timeout) => {309 await this.mainFrame().rafrafTimeout(timeout);310 return await this._screenshotter.screenshotPage(progress, options.screenshotOptions || {});311 };312 const comparator = (0, _comparators.getComparator)('image/png');313 const controller = new _progress.ProgressController(metadata, this);314 const isGeneratingNewScreenshot = !options.expected;315 if (isGeneratingNewScreenshot && options.isNot) return {316 errorMessage: '"not" matcher requires expected result'317 };318 let intermediateResult = undefined;319 return controller.run(async progress => {320 let actual;321 let previous;322 const pollIntervals = [0, 100, 250, 500];323 while (true) {324 var _pollIntervals$shift;325 progress.throwIfAborted();326 if (this.isClosed()) throw new Error('The page has closed');327 let comparatorResult;328 const screenshotTimeout = (_pollIntervals$shift = pollIntervals.shift()) !== null && _pollIntervals$shift !== void 0 ? _pollIntervals$shift : 1000;329 if (isGeneratingNewScreenshot) {330 previous = actual;331 actual = await rafrafScreenshot(progress, screenshotTimeout).catch(e => undefined);332 comparatorResult = actual && previous ? comparator(actual, previous, options.comparatorOptions) : undefined;333 } else {334 actual = await rafrafScreenshot(progress, screenshotTimeout).catch(e => undefined);335 comparatorResult = actual ? comparator(actual, options.expected, options.comparatorOptions) : undefined;336 }337 if (comparatorResult !== undefined && !!comparatorResult === !!options.isNot) break;338 if (comparatorResult) intermediateResult = {339 errorMessage: comparatorResult.errorMessage,340 diff: comparatorResult.diff,341 actual,342 previous343 };344 }345 return isGeneratingNewScreenshot ? {346 actual347 } : {};348 }, this._timeoutSettings.timeout(options)).catch(e => {349 var _intermediateResult$e, _intermediateResult;350 // Q: Why not throw upon isSessionClosedError(e) as in other places?351 // A: We want user to receive a friendly diff between actual and expected/previous.352 if (js.isJavaScriptErrorInEvaluate(e) || (0, _selectorParser.isInvalidSelectorError)(e)) throw e;353 return {354 log: metadata.log,355 ...intermediateResult,356 errorMessage: (_intermediateResult$e = (_intermediateResult = intermediateResult) === null || _intermediateResult === void 0 ? void 0 : _intermediateResult.errorMessage) !== null && _intermediateResult$e !== void 0 ? _intermediateResult$e : e.message357 };358 });359 }360 async screenshot(metadata, options = {}) {361 const controller = new _progress.ProgressController(metadata, this);362 return controller.run(progress => this._screenshotter.screenshotPage(progress, options), this._timeoutSettings.timeout(options));363 }364 async close(metadata, options) {365 if (this._closedState === 'closed') return;366 const runBeforeUnload = !!options && !!options.runBeforeUnload;367 if (this._closedState !== 'closing') {368 this._closedState = 'closing';369 (0, _utils.assert)(!this._disconnected, 'Target closed'); // This might throw if the browser context containing the page closes370 // while we are trying to close the page.371 await this._delegate.closePage(runBeforeUnload).catch(e => _debugLogger.debugLogger.log('error', e));372 }373 if (!runBeforeUnload) await this._closedPromise;374 if (this._ownedContext) await this._ownedContext.close(metadata);375 }376 _setIsError(error) {377 this._pageIsError = error;378 if (!this._frameManager.mainFrame()) this._frameManager.frameAttached('<dummy>', null);379 }380 isClosed() {381 return this._closedState === 'closed';382 }383 _addWorker(workerId, worker) {384 this._workers.set(workerId, worker);385 this.emit(Page.Events.Worker, worker);386 }387 _removeWorker(workerId) {388 const worker = this._workers.get(workerId);389 if (!worker) return;390 worker.didClose();391 this._workers.delete(workerId);392 }393 _clearWorkers() {394 for (const [workerId, worker] of this._workers) {395 worker.didClose();396 this._workers.delete(workerId);397 }398 }399 async _setFileChooserIntercepted(enabled) {400 await this._delegate.setFileChooserIntercepted(enabled);401 }402 frameNavigatedToNewDocument(frame) {403 this.emit(Page.Events.InternalFrameNavigatedToNewDocument, frame);404 const url = frame.url();405 if (!url.startsWith('http')) return;406 const purl = network.parsedURL(url);407 if (purl) this._browserContext.addVisitedOrigin(purl.origin);408 }409 allBindings() {410 return [...this._browserContext._pageBindings.values(), ...this._pageBindings.values()];411 }412 getBinding(name) {413 return this._pageBindings.get(name) || this._browserContext._pageBindings.get(name);414 }415 setScreencastOptions(options) {416 this._delegate.setScreencastOptions(options).catch(e => _debugLogger.debugLogger.log('error', e));417 this._frameThrottler.setEnabled(!!options);418 }419 throttleScreencastFrameAck(ack) {420 // Don't ack immediately, tracing has smart throttling logic that is implemented here.421 this._frameThrottler.ack(ack);422 }423 temporarlyDisableTracingScreencastThrottling() {424 this._frameThrottler.recharge();425 }426 firePageError(error) {427 this.emit(Page.Events.PageError, error);428 }429 parseSelector(selector, options) {430 const strict = typeof (options === null || options === void 0 ? void 0 : options.strict) === 'boolean' ? options.strict : !!this.context()._options.strictSelectors;431 return this.selectors.parseSelector(selector, strict);432 }433 async hideHighlight() {434 await Promise.all(this.frames().map(frame => frame.hideHighlight().catch(() => {})));435 }436}437exports.Page = Page;438Page.Events = {439 Close: 'close',440 Crash: 'crash',441 Console: 'console',442 Dialog: 'dialog',443 Download: 'download',444 FileChooser: 'filechooser',445 DOMContentLoaded: 'domcontentloaded',446 // Can't use just 'error' due to node.js special treatment of error events.447 // @see https://nodejs.org/api/events.html#events_error_events448 PageError: 'pageerror',449 FrameAttached: 'frameattached',450 FrameDetached: 'framedetached',451 InternalFrameNavigatedToNewDocument: 'internalframenavigatedtonewdocument',452 Load: 'load',453 ScreencastFrame: 'screencastframe',454 Video: 'video',455 WebSocket: 'websocket',456 Worker: 'worker'457};458class Worker extends _instrumentation.SdkObject {459 constructor(parent, url) {460 super(parent, 'worker');461 this._url = void 0;462 this._executionContextPromise = void 0;463 this._executionContextCallback = void 0;464 this._existingExecutionContext = null;465 this._url = url;466 this._executionContextCallback = () => {};467 this._executionContextPromise = new Promise(x => this._executionContextCallback = x);468 }469 _createExecutionContext(delegate) {470 this._existingExecutionContext = new js.ExecutionContext(this, delegate);471 this._executionContextCallback(this._existingExecutionContext);472 }473 url() {474 return this._url;475 }476 didClose() {477 if (this._existingExecutionContext) this._existingExecutionContext.contextDestroyed(new Error('Worker was closed'));478 this.emit(Worker.Events.Close, this);479 }480 async evaluateExpression(expression, isFunction, arg) {481 return js.evaluateExpression(await this._executionContextPromise, true482 /* returnByValue */483 , expression, isFunction, arg);484 }485 async evaluateExpressionHandle(expression, isFunction, arg) {486 return js.evaluateExpression(await this._executionContextPromise, false487 /* returnByValue */488 , expression, isFunction, arg);489 }490}491exports.Worker = Worker;492Worker.Events = {493 Close: 'close'494};495class PageBinding {496 constructor(name, playwrightFunction, needsHandle) {497 this.name = void 0;498 this.playwrightFunction = void 0;499 this.source = void 0;500 this.needsHandle = void 0;501 this.name = name;502 this.playwrightFunction = playwrightFunction;503 this.source = `(${addPageBinding.toString()})(${JSON.stringify(name)}, ${needsHandle})`;504 this.needsHandle = needsHandle;505 }506 static async dispatch(page, payload, context) {507 const {508 name,509 seq,510 args511 } = JSON.parse(payload);512 try {513 (0, _utils.assert)(context.world);514 const binding = page.getBinding(name);515 let result;516 if (binding.needsHandle) {517 const handle = await context.evaluateHandle(takeHandle, {518 name,519 seq520 }).catch(e => null);521 result = await binding.playwrightFunction({522 frame: context.frame,523 page,524 context: page._browserContext525 }, handle);526 } else {527 result = await binding.playwrightFunction({528 frame: context.frame,529 page,530 context: page._browserContext531 }, ...args);532 }533 context.evaluate(deliverResult, {534 name,535 seq,536 result537 }).catch(e => _debugLogger.debugLogger.log('error', e));538 } catch (error) {539 if ((0, _utils.isError)(error)) context.evaluate(deliverError, {540 name,541 seq,542 message: error.message,543 stack: error.stack544 }).catch(e => _debugLogger.debugLogger.log('error', e));else context.evaluate(deliverErrorValue, {545 name,546 seq,547 error548 }).catch(e => _debugLogger.debugLogger.log('error', e));549 }550 function takeHandle(arg) {551 const handle = globalThis[arg.name]['handles'].get(arg.seq);552 globalThis[arg.name]['handles'].delete(arg.seq);553 return handle;554 }555 function deliverResult(arg) {556 globalThis[arg.name]['callbacks'].get(arg.seq).resolve(arg.result);557 globalThis[arg.name]['callbacks'].delete(arg.seq);558 }559 function deliverError(arg) {560 const error = new Error(arg.message);561 error.stack = arg.stack;562 globalThis[arg.name]['callbacks'].get(arg.seq).reject(error);563 globalThis[arg.name]['callbacks'].delete(arg.seq);564 }565 function deliverErrorValue(arg) {566 globalThis[arg.name]['callbacks'].get(arg.seq).reject(arg.error);567 globalThis[arg.name]['callbacks'].delete(arg.seq);568 }569 }570}571exports.PageBinding = PageBinding;572function addPageBinding(bindingName, needsHandle) {573 const binding = globalThis[bindingName];574 if (binding.__installed) return;575 globalThis[bindingName] = (...args) => {576 const me = globalThis[bindingName];577 if (needsHandle && args.slice(1).some(arg => arg !== undefined)) throw new Error(`exposeBindingHandle supports a single argument, ${args.length} received`);578 let callbacks = me['callbacks'];579 if (!callbacks) {580 callbacks = new Map();581 me['callbacks'] = callbacks;582 }583 const seq = (me['lastSeq'] || 0) + 1;584 me['lastSeq'] = seq;585 let handles = me['handles'];586 if (!handles) {587 handles = new Map();588 me['handles'] = handles;589 }590 const promise = new Promise((resolve, reject) => callbacks.set(seq, {591 resolve,592 reject593 }));594 if (needsHandle) {595 handles.set(seq, args[0]);596 binding(JSON.stringify({597 name: bindingName,598 seq599 }));600 } else {601 binding(JSON.stringify({602 name: bindingName,603 seq,604 args605 }));606 }607 return promise;608 };609 globalThis[bindingName].__installed = true;610}611class FrameThrottler {612 constructor(nonThrottledFrames, interval) {613 this._acks = [];614 this._interval = void 0;615 this._nonThrottledFrames = void 0;616 this._budget = void 0;617 this._intervalId = void 0;618 this._nonThrottledFrames = nonThrottledFrames;619 this._budget = nonThrottledFrames;620 this._interval = interval;621 }622 setEnabled(enabled) {623 if (enabled) {624 if (this._intervalId) clearInterval(this._intervalId);625 this._intervalId = setInterval(() => this._tick(), this._interval);626 } else if (this._intervalId) {627 clearInterval(this._intervalId);628 this._intervalId = undefined;629 }630 }631 recharge() {632 // Send all acks, reset budget.633 for (const ack of this._acks) ack();634 this._acks = [];635 this._budget = this._nonThrottledFrames;636 }637 ack(ack) {638 // Either not engaged or video is also recording, don't throttle.639 if (!this._intervalId) {640 ack();641 return;642 } // Do we have enough budget to respond w/o throttling?643 if (--this._budget > 0) {644 ack();645 return;646 } // Schedule.647 this._acks.push(ack);648 }649 _tick() {650 var _this$_acks$shift;651 (_this$_acks$shift = this._acks.shift()) === null || _this$_acks$shift === void 0 ? void 0 : _this$_acks$shift();652 }...
cssParser.js
Source:cssParser.js
...25 * limitations under the License.26 */27class InvalidSelectorError extends Error {}28exports.InvalidSelectorError = InvalidSelectorError;29function isInvalidSelectorError(error) {30 return error instanceof InvalidSelectorError;31} // Note: '>=' is used internally for text engine to preserve backwards compatibility.32function parseCSS(selector, customNames) {33 let tokens;34 try {35 tokens = css.tokenize(selector);36 if (!(tokens[tokens.length - 1] instanceof css.EOFToken)) tokens.push(new css.EOFToken());37 } catch (e) {38 const newMessage = e.message + ` while parsing selector "${selector}"`;39 const index = (e.stack || '').indexOf(e.message);40 if (index !== -1) e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);41 e.message = newMessage;42 throw e;43 }...
selectorParser.js
Source:selectorParser.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5Object.defineProperty(exports, "InvalidSelectorError", {6 enumerable: true,7 get: function () {8 return _cssParser.InvalidSelectorError;9 }10});11exports.allEngineNames = allEngineNames;12exports.customCSSNames = void 0;13Object.defineProperty(exports, "isInvalidSelectorError", {14 enumerable: true,15 get: function () {16 return _cssParser.isInvalidSelectorError;17 }18});19exports.parseSelector = parseSelector;20exports.splitSelectorByFrame = splitSelectorByFrame;21exports.stringifySelector = stringifySelector;22var _cssParser = require("./cssParser");23/**24 * Copyright (c) Microsoft Corporation.25 *26 * Licensed under the Apache License, Version 2.0 (the "License");27 * you may not use this file except in compliance with the License.28 * You may obtain a copy of the License at29 *30 * http://www.apache.org/licenses/LICENSE-2.031 *32 * Unless required by applicable law or agreed to in writing, software33 * distributed under the License is distributed on an "AS IS" BASIS,34 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.35 * See the License for the specific language governing permissions and36 * limitations under the License.37 */38const customCSSNames = new Set(['not', 'is', 'where', 'has', 'scope', 'light', 'visible', 'text', 'text-matches', 'text-is', 'has-text', 'above', 'below', 'right-of', 'left-of', 'near', 'nth-match']);39exports.customCSSNames = customCSSNames;40const kNestedSelectorNames = new Set(['has']);41function parseSelector(selector) {42 const result = parseSelectorString(selector);43 const parts = result.parts.map(part => {44 if (part.name === 'css' || part.name === 'css:light') {45 if (part.name === 'css:light') part.body = ':light(' + part.body + ')';46 const parsedCSS = (0, _cssParser.parseCSS)(part.body, customCSSNames);47 return {48 name: 'css',49 body: parsedCSS.selector,50 source: part.body51 };52 }53 if (kNestedSelectorNames.has(part.name)) {54 let innerSelector;55 try {56 const unescaped = JSON.parse(part.body);57 if (typeof unescaped !== 'string') throw new Error(`Malformed selector: ${part.name}=` + part.body);58 innerSelector = unescaped;59 } catch (e) {60 throw new Error(`Malformed selector: ${part.name}=` + part.body);61 }62 const result = {63 name: part.name,64 source: part.body,65 body: parseSelector(innerSelector)66 };67 if (result.body.parts.some(part => part.name === 'control' && part.body === 'enter-frame')) throw new Error(`Frames are not allowed inside "${part.name}" selectors`);68 return result;69 }70 return { ...part,71 source: part.body72 };73 });74 if (kNestedSelectorNames.has(parts[0].name)) throw new Error(`"${parts[0].name}" selector cannot be first`);75 return {76 capture: result.capture,77 parts78 };79}80function splitSelectorByFrame(selectorText) {81 const selector = parseSelector(selectorText);82 const result = [];83 let chunk = {84 parts: []85 };86 let chunkStartIndex = 0;87 for (let i = 0; i < selector.parts.length; ++i) {88 const part = selector.parts[i];89 if (part.name === 'control' && part.body === 'enter-frame') {90 if (!chunk.parts.length) throw new _cssParser.InvalidSelectorError('Selector cannot start with entering frame, select the iframe first');91 result.push(chunk);92 chunk = {93 parts: []94 };95 chunkStartIndex = i + 1;96 continue;97 }98 if (selector.capture === i) chunk.capture = i - chunkStartIndex;99 chunk.parts.push(part);100 }101 if (!chunk.parts.length) throw new _cssParser.InvalidSelectorError(`Selector cannot end with entering frame, while parsing selector ${selectorText}`);102 result.push(chunk);103 if (typeof selector.capture === 'number' && typeof result[result.length - 1].capture !== 'number') throw new _cssParser.InvalidSelectorError(`Can not capture the selector before diving into the frame. Only use * after the last frame has been selected`);104 return result;105}106function stringifySelector(selector) {107 if (typeof selector === 'string') return selector;108 return selector.parts.map((p, i) => {109 const prefix = p.name === 'css' ? '' : p.name + '=';110 return `${i === selector.capture ? '*' : ''}${prefix}${p.source}`;111 }).join(' >> ');112}113function allEngineNames(selector) {114 const result = new Set();115 const visit = selector => {116 for (const part of selector.parts) {117 result.add(part.name);118 if (kNestedSelectorNames.has(part.name)) visit(part.body);119 }120 };121 visit(selector);122 return result;123}124function parseSelectorString(selector) {125 let index = 0;126 let quote;127 let start = 0;128 const result = {129 parts: []130 };131 const append = () => {132 const part = selector.substring(start, index).trim();133 const eqIndex = part.indexOf('=');134 let name;135 let body;136 if (eqIndex !== -1 && part.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9-+:*]+$/)) {137 name = part.substring(0, eqIndex).trim();138 body = part.substring(eqIndex + 1);139 } else if (part.length > 1 && part[0] === '"' && part[part.length - 1] === '"') {140 name = 'text';141 body = part;142 } else if (part.length > 1 && part[0] === "'" && part[part.length - 1] === "'") {143 name = 'text';144 body = part;145 } else if (/^\(*\/\//.test(part) || part.startsWith('..')) {146 // If selector starts with '//' or '//' prefixed with multiple opening147 // parenthesis, consider xpath. @see https://github.com/microsoft/playwright/issues/817148 // If selector starts with '..', consider xpath as well.149 name = 'xpath';150 body = part;151 } else {152 name = 'css';153 body = part;154 }155 let capture = false;156 if (name[0] === '*') {157 capture = true;158 name = name.substring(1);159 }160 result.parts.push({161 name,162 body163 });164 if (capture) {165 if (result.capture !== undefined) throw new _cssParser.InvalidSelectorError(`Only one of the selectors can capture using * modifier`);166 result.capture = result.parts.length - 1;167 }168 };169 if (!selector.includes('>>')) {170 index = selector.length;171 append();172 return result;173 }174 while (index < selector.length) {175 const c = selector[index];176 if (c === '\\' && index + 1 < selector.length) {177 index += 2;178 } else if (c === quote) {179 quote = undefined;180 index++;181 } else if (!quote && (c === '"' || c === '\'' || c === '`')) {182 quote = c;183 index++;184 } else if (!quote && c === '>' && selector[index + 1] === '>') {185 append();186 index += 2;187 start = index;188 } else {189 index++;190 }191 }192 append();193 return result;...
selectorErrors.js
Source:selectorErrors.js
...20 * limitations under the License.21 */22class InvalidSelectorError extends Error {}23exports.InvalidSelectorError = InvalidSelectorError;24function isInvalidSelectorError(error) {25 return error instanceof InvalidSelectorError;...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 try {7 await page.click('div');8 } catch (e) {9 if (e instanceof Error && e.name === 'Error') {10 if (e.isInvalidSelectorError) {11 console.log('Invalid selector error!');12 }13 }14 }15 await browser.close();16})();17const { chromium } = require('playwright');18(async () => {19 const browser = await chromium.launch();20 const context = await browser.newContext();21 const page = await context.newPage();22 try {23 await page.waitForSelector('div');24 } catch (e) {25 if (e instanceof Error && e.name === 'TimeoutError') {26 if (e.isTimeoutError) {27 console.log('Timeout error!');28 }29 }30 }31 await browser.close();32})();33const { chromium } = require('playwright');34(async () => {35 const browser = await chromium.launch();36 const context = await browser.newContext();37 const page = await context.newPage();38 try {39 await page.evaluate(() => {40 throw new Error('Evaluation failed');41 });42 } catch (e) {43 if (e instanceof Error && e.name === 'Error') {44 if (e.isEvaluationFailedError) {45 console.log('Evaluation failed error!');46 }47 }48 }49 await browser.close();50})();51const { chromium } = require('playwright');52(async () => {53 const browser = await chromium.launch();54 const context = await browser.newContext();55 const page = await context.newPage();56 try {57 await page.click('div');58 } catch (e) {59 if (e instanceof Error && e.name === 'Error') {60 if (e.isSelectorMatchesMultipleElementsError) {61 console.log('Selector matches multiple elements error!');62 }
Using AI Code Generation
1const { isInvalidSelectorError } = require('playwright/lib/helper');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 try {7 await page.click('text=Get started');8 } catch (e) {9 if (isInvalidSelectorError(e)) {10 console.log('Invalid selector error');11 }12 }13 await browser.close();14})();15const { isInvalidSelectorError } = require('playwright/lib/helper');16const { chromium } = require('playwright');17(async () => {18 const browser = await chromium.launch();19 const page = await browser.newPage();20 try {21 await page.click('text=Get started');22 } catch (e) {23 if (isInvalidSelectorError(e)) {24 console.log('Invalid selector error');25 }26 }27 await browser.close();28})();29const { isInvalidSelectorError } = require('playwright/lib/helper');30const { chromium } = require('playwright');31(async () => {32 const browser = await chromium.launch();33 const page = await browser.newPage();34 try {35 await page.click('text=Get started');36 } catch (e) {37 if (isInvalidSelectorError(e)) {38 console.log('Invalid selector error');39 }40 }41 await browser.close();42})();43const { isInvalidSelectorError } = require('playwright/lib/helper');44const { chromium } = require('playwright');45(async () => {46 const browser = await chromium.launch();47 const page = await browser.newPage();48 try {49 await page.click('text=Get started');50 } catch (e) {51 if (isInvalidSelectorError(e)) {52 console.log('Invalid selector error');53 }
Using AI Code Generation
1const { chromium } = require('playwright');2const { isInvalidSelectorError } = require('playwright/lib/internal/errors');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 try {7 await page.$('invalid');8 } catch (error) {9 if (isInvalidSelectorError(error)) {10 console.log('Invalid selector error');11 }12 }13 await browser.close();14})();15isTimeoutError(error)16isNavigationError(error)17isEvaluationError(error)18isSelectorError(error)19isElementHandleError(error)20isJSHandleError(error)21isRequestError(error)22isResponseError(error)23isBrowserContextError(error)24isPageError(error)25isWorkerError(error)26isPlaywrightError(error)27isError(error)28isErrorWithMessage(error)29isErrorWithStack(error)30isErrorWithMetadata(error)31isErrorWithInternalProperties(error)32isErrorWithInternalDetails(error)33isErrorWithInternalFrames(er
Using AI Code Generation
1const { isInvalidSelectorError } = require('playwright/lib/utils/error');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 try {8 await page.waitForSelector('div');9 } catch (error) {10 if (isInvalidSelectorError(error)) {11 console.log('Invalid selector');12 } else {13 throw error;14 }15 }16 await browser.close();17})();
Using AI Code Generation
1const { Playwright } = require('playwright');2const { isInvalidSelectorError } = Playwright.InternalError;3const { chromium } = require('playwright');4(async () => {5 const browser = await chromium.launch();6 const page = await browser.newPage();7 try {8 await page.setContent('<h1>Test</h1>');9 await page.click('h1');10 } catch (error) {11 if (isInvalidSelectorError(error)) {12 console.log('Invalid selector');13 } else {14 console.log('Other error');15 }16 }17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const page = await browser.newPage();23 try {24 await page.setContent('<h1>Test</h1>');25 await page.click('h1');26 } catch (error) {27 if (error.isInvalidSelectorError) {28 console.log('Invalid selector');29 } else {30 console.log('Other error');31 }32 }33 await browser.close();34})();35const { chromium } = require('playwright');36(async () => {37 const browser = await chromium.launch();38 const page = await browser.newPage();39 try {40 await page.setContent('<h1>Test</h1>');41 await page.click('h1');42 } catch (error) {43 if (error.isPlaywrightError && error.name === 'PlaywrightError' && error.code === 'ERR_INVALID_SELECTOR') {44 console.log('Invalid selector');45 } else {46 console.log('Other error');47 }48 }49 await browser.close();50})();51const { chromium } = require('playwright');52(async () => {53 const browser = await chromium.launch();54 const page = await browser.newPage();55 try {56 await page.setContent('<h1>Test</h1>');57 await page.click('h1');58 } catch (error) {59 if (error instanceof Error && error.name === 'PlaywrightError' && error.code === 'ERR_INVALID_SELECTOR') {60 console.log('Invalid
Using AI Code Generation
1const { InternalError } = require('playwright/lib/server/errors');2const { isInvalidSelectorError } = InternalError;3console.log(isInvalidSelectorError(new Error('Invalid selector')));4console.log(isInvalidSelectorError(new Error('Invalid selector: foo')));5console.log(isInvalidSelectorError(new Error('Invalid selector: foo bar')));6console.log(isInvalidSelectorError(new Error('Invalid selector: foo bar baz')));7console.log(isInvalidSelectorError(new Error('Invalid selector: foo bar baz qux')));
Using AI Code Generation
1const { isInvalidSelectorError } = require('playwright/lib/helper');2const { isInvalidSelectorError } = require('playwright/lib/helper');3class MyHelper extends Helper {4 async _before() {5 this.helpers = this.helpers || {};6 this.helpers.Playwright = this.helpers.Playwright || this.helpers['Playwright'];7 }8 async isInvalidSelectorError(error) {9 return isInvalidSelectorError(error);10 }11}12module.exports = MyHelper;13const { expect } = require('chai');14Feature('My Feature');15Scenario('My Scenario', async ({ I }) => {16 try {17 await I.click('I do not exist');18 } catch (e) {19 expect(await I.isInvalidSelectorError(e)).to.be.true;20 }21});
Using AI Code Generation
1const { isInvalidSelectorError } = require('playwright/lib/server/utils');2if (isInvalidSelectorError(error)) {3 console.log('Invalid Selector Error');4}5const { isInvalidSelectorError } = require('playwright/lib/server/utils');6if (isInvalidSelectorError(error)) {7 console.log('Invalid Selector Error');8}9const { isInvalidSelectorError } = require('playwright/lib/server/utils');10if (isInvalidSelectorError(error)) {11 console.log('Invalid Selector Error');12}13const { isInvalidSelectorError } = require('playwright/lib/server/utils');14if (isInvalidSelectorError(error)) {15 console.log('Invalid Selector Error');16}17const { isInvalidSelectorError } = require('playwright/lib/server/utils');18if (isInvalidSelectorError(error)) {19 console.log('Invalid Selector Error');20}21const { isInvalidSelectorError } = require('playwright/lib/server/utils');22if (isInvalidSelectorError(error)) {23 console.log('Invalid Selector Error');24}25const { isInvalidSelectorError } = require('playwright/lib/server/utils');26if (isInvalidSelectorError(error)) {27 console.log('Invalid Selector Error');28}29const { isInvalidSelectorError } = require('playwright/lib/server/utils');30if (isInvalidSelectorError(error)) {31 console.log('Invalid Selector Error');32}33const { isInvalidSelectorError } = require('playwright/lib/server/utils');34if (isInvalidSelectorError(error)) {35 console.log('Invalid Selector Error');36}37const { isInvalidSelectorError } = require('playwright/lib/server/utils');38if (isInvalidSelectorError(error)) {39 console.log('Invalid Selector Error
Using AI Code Generation
1const { Playwright } = require('playwright');2const { InternalError } = Playwright;3const error = new InternalError('error message');4const { chromium } = require('playwright');5(async () => {6 const browser = await chromium.launch();7 const context = await browser.newContext();8 try {9 await context.waitForSelector('div', { timeout: 1000 });10 } catch (error) {11 if (error.isInvalidSelectorError()) {12 console.log('Invalid selector error');13 } else {14 console.log('Other error');15 }16 }17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 try {25 await page.click('non-existent-selector');26 } catch (error) {27 if (error.isTimeoutError()) {28 console.log('Timeout error');29 } else if (error.isElementHandleError()) {30 console.log('ElementHandle error');31 } else {32 console.log('Other error');33 }34 }35 await browser.close();36})();
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!