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;...
selectorParser.js
Source:selectorParser.js
...45 capture: result.capture,46 parts47 };48}49function splitSelectorByFrame(selectorText) {50 const selector = parseSelector(selectorText);51 const result = [];52 let chunk = {53 parts: []54 };55 let chunkStartIndex = 0;56 for (let i = 0; i < selector.parts.length; ++i) {57 const part = selector.parts[i];58 if (part.name === 'control' && part.body === 'enter-frame') {59 if (!chunk.parts.length) throw new _selectorErrors.InvalidSelectorError('Selector cannot start with entering frame, select the iframe first');60 result.push(chunk);61 chunk = {62 parts: []63 };...
Using AI Code Generation
1const { splitSelectorByFrame } = require('playwright/lib/server/dom.js');2const { ElementHandle } = require('playwright/lib/server/dom.js');3const { Frame } = require('playwright/lib/server/dom.js');4const frame = new Frame();5const elementHandle = new ElementHandle();6const result = splitSelectorByFrame(frame, elementHandle, selector);7console.log(result);
Using AI Code Generation
1const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;2const { Frame } = require('@playwright/test/lib/server/frames');3const { ElementHandle } = require('@playwright/test/lib/server/dom');4const { Page } = require('@playwright/test/lib/server/page');5const { selectors } = require('@playwright/test/lib/server/selectors');6const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');7const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;8const { Frame } = require('@playwright/test/lib/server/frames');9const { ElementHandle } = require('@playwright/test/lib/server/dom');10const { Page } = require('@playwright/test/lib/server/page');11const { selectors } = require('@playwright/test/lib/server/selectors');12const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');13const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;14const { Frame } = require('@playwright/test/lib/server/frames');15const { ElementHandle } = require('@playwright/test/lib/server/dom');16const { Page } = require('@playwright/test/lib/server/page');17const { selectors } = require('@playwright/test/lib/server/selectors');18const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');19const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;20const { Frame } = require('@playwright/test/lib/server/frames');21const { ElementHandle } = require('@playwright/test/lib/server/dom');22const { Page } = require('@playwright/test/lib/server/page');23const { selectors } = require('@playwright/test/lib/server/selectors');24const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');25const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;26const { Frame } = require('@playwright/test/lib/server/frames');27const { ElementHandle } = require('@playwright/test/lib/server/dom');28const { Page }
Using AI Code Generation
1const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;2const { Frame } = require('@playwright/test/lib/server/frames');3const { ElementHandle } = require('@playwright/test/lib/server/dom');4const { Page } = require('@playwright/test/lib/server/page');5const { selectors } = require('@playwright/test/lib/server/selectors');6const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');7const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;8const { Frame } = require('@playwright/test/lib/server/frames');9const { ElementHandle } = require('@playwright/test/lib/server/dom');10const { Page } = require('@playwright/test/lib/server/page');11const { selectors } = require('@playwright/test/lib/server/selectors');12const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');13const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;14const { Frame } = require('@playwright/test/lib/server/frames');15const { ElementHandle } = require('@playwright/test/lib/server/dom');16const { Page } = require('@playwright/test/lib/server/page');17const { selectors } = require('@playwright/test/lib/server/selectors');18const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');19const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;20const { Frame } = require('@playwright/test/lib/server/frames');21const { ElementHandle } = require('@playwright/test/lib/server/dom');22const { Page } = require('@playwright/test/lib/server/page');23const { selectors } = require('@playwright/test/lib/server/selectors');24const { Selector } = require('@playwright/test/lib/server/selectors/selectorImpl');25const { splitSelectorByFrame } = require('@playwright/test/lib/utils').internalAPI;26const { Frame } = require('@playwright/test/lib/server/frames');27const { ElementHandle } = require('@playwright/test/lib/server/dom');28const { Page }
Using AI Code Generation
1const { splitSelectorByFrame } = require("playwright/lib/server/dom");2const { Frame, Page } = require("playwright/lib/server/chromium/crPage");3const { ElementHandle } = require("playwright/lib/server/chromium/crElementHandle");4const { JSHandle } = require("playwright/lib/server/chromium/crJSHandle");5const { BrowserContext } = require("playwright/lib/server/chromium/crBrowser");6const { Browser } = require("playwright/lib/server/chromium/crBrowser");7const { splitSelectorByFrame } = require("playwright/lib/server/dom");8const { Frame, Page } = require("playwright/lib/server/chromium/crPage");9const { ElementHandle } = require("playwright/lib/server/chromium/crElementHandle");10const { JSHandle } = require("playwright/lib/server/chromium/crJSHandle");11const { BrowserContext } = require("playwright/lib/server/chromium/crBrowser");12const { Browser } = require("playwright/lib/server/chromium/crBrowser");13async function test() {14 const browser = await chromium.launch({15 });16 const context = await browser.newContext();17 const page = await context.newPage();18 const frame = page.mainFrame();19 const elementHandle = await frame.$('input[name="q"]');20 const jsHandle = await elementHandle.getProperty('value');21 console.log(await jsHandle.jsonValue());22 await browser.close();23}24test();25const { splitSelectorByFrame } = require("playwright/lib/server/dom");26const { Frame, Page } = require("playwright/lib/server/chromium/crPage");27const { ElementHandle } = require("playwright/lib/server/chromium/crElementHandle");28const { JSHandle } = require("playwright/lib/server/chromium/crJSHandle");29const { BrowserContext } = require("playwright/lib/server/chromium/crBrowser");30const { Browser } = require("playwright/lib/server/chromium/crBrowser");31async function test() {32 const browser = await chromium.launch({
Using AI Code Generation
1const { splitSelectorByFrame } = require('playwright/lib/server/dom');2const { parseSelector } = require('playwright/lib/server/dom');3const { parseSelectorV2 } = require('playwright/lib/server/dom');4const { parseSelectorV1 } = require('playwright/lib/server/dom');5const { parseSelectorV0 } = require('playwright/lib/server/dom');6const { parseSelectorV3 } = require('playwright/lib/server/dom');7const { frame, selector: frameSelector } = splitSelectorByFrame(selector);8console.log(frame, frameSelector);
Using AI Code Generation
1const { splitSelectorByFrame } = require('playwright/lib/server/dom');2const { parseSelector } = require('playwright/lib/serverselectorsselectorParser');3const selector = arseSeector('css=div#frame1 >> css=div#frame2 >> css=div#frame3 >> css=div#frame4 >> css=div#frame5 >> css=div#frame6 >> css=div#frame7 >> css=div#frame8 >> css=div#frame9 >> css=div#frame10 >> css=div#frame11 >> css=div#frame12 >> css=div#frame13 >> css=div#frame14 >> css=div#frame15 >> css=div#frame16 >> css=div#frame17 >> css=div#frame18 >> css=div#frame19 >> css=div#frame20 >> css=div#frame21 >> css=div#frame22 >> css=div#frame23 >> css=div#frame24 >> css=div#frame25 >> css=div#frame26 >> css=div#frame27 >> css=div#frame28 >> css=div#frame29 >> css=div#frame30 >> css=div#frame31 >> css=div#frame32 >> css=div#frame33 >> css=div#frame34 >> css=div#frame35 >> css=div#frame36 >> css=div#frame37 >> css=div#frame38 >> css=div#frame39 >> css=div#frame40 >> css=div#frame41 >> css=div#frame42 >> css=div#frame43 >> css=div#frame44 >> css=div#frame45 >> css=div#frame46 >> css=div#frame47 >> css=div#frame48 >> css=div#frame49 >> css=div#frame50 >> css=div#frame51 >> css=div#frme52 >> css=div#frame53 >> css=div#frame54 >> css=div#frame55 >> css=div#frame56 >> css=div#frame57 >> css=div#frame58 >> css=div#frame59 >> css=div#frame60 >> css=div#frame61 >> css=div#frame62 >> css=div#frame63 >> css=div#frame64 >> css=div#frame65 >> css=4const { frame, selector: frameSelector } = splitSelectorByFrame(selector);5console.log(frame, frameSelector);6const { frame, selector: frameSelector } = splitSelectorByFrame(selector);7console.log(frame, frameSelector);8const { frame, selector: frameSelector } = splitSelectorByFrame(selector);9console.log(frame, frameSelector);10const { frame, selector: frameSelector } = sp
Using AI Code Generation
1const { splitSelectorByFrame } = require('@playwright/test/lib/server/frames');2const selector = 'css=div > iframe css=div;3const { frame, selector: remainingSelector } = await splitSelectorByFrame(page, selector4con.t { sdev/delectorByFrame } = require('@playwright/test/lib/server/channels');5const selector = 'css=div > iframe > css=div';6const { frame, socs/sel: remainingSelector } = await splitSelectorByFrame(page, selector);7const element = await frame.waitForSelector('css=div');8const element = await page.waitForSelector('css=div');9const element = await frame.waitForSelector('css=div', { timeout: 2000 });10const element = await page.waitForSelector('css=div', { timeout: 2000 });
Using AI Code Generation
1const { splitSelectorByFrame } = require('playwright/lib/server/frames');2const { context } = require('playwright/lib/server/chromium');3const { frame, selector } = splitSelectorByFrame(context, '.frame1 .frame2 #id');4const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>');5const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id');6const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', '.frame1 .frame2 #id');7const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', 'data:text/html, <h1>Hi</h1>');8const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id');9const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', '.frame1 .frame2 #id');10const { frame, selector } = splitSelectorByFrame(context, 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', 'data:text/html, <h1>Hi</h1>.frame1 .frame2 #id', 'data:text/html, <h1>Hi</h1>');
Using AI Code Generation
1const { splitSelectorByFrame } = require('@playwright/test/lib/server/frames');2const selector = 'css=div > iframe > css=div';3const { frame, selector: remainingSelector } = await splitSelectorByFrame(page, selector);4const { splitSelectorByFrame } = require('@playwright/test/lib/server/channels');5const selector = 'css=div > iframe > css=div';6const { frame, selector: remainingSelector } = await splitSelectorByFrame(page, selector);7const element = await frame.waitForSelector('css=div');8const element = await page.waitForSelector('css=div');9const element = await frame.waitForSelector('css=div', { timeout: 2000 });10const element = await page.waitForSelector('css=div', { timeout: 2000 });
Using AI Code Generation
1const { splitSelectorByFrame } = require('playwright/lib/client/helper');2const { parseSelector } = require('playwright/lib/client/selectorParser');3const result = splitSelectorByFrame(selector);4console.log(result);5 {6 selector: { engine: 'css', selector: 'body' }7 },8 {9 selector: {10 }11 },12 {13 selector: {14 }15 }16const { splitSelectorByFrame } = require('playwright/lib/client/helper');17const { parseSelector } = require('playwright/lib/client/selectorParser');18const result = splitSelectorByFrame(selector);19console.log(result);20 {21 selector: { engine: 'css', selector: 'body' }22 },23 {24 selector: {25 }26 },27 {28 selector: {29 }30 }
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!!