frames.js 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var frames_exports = {};
  30. __export(frames_exports, {
  31. Frame: () => Frame,
  32. FrameManager: () => FrameManager,
  33. NavigationAbortedError: () => NavigationAbortedError
  34. });
  35. module.exports = __toCommonJS(frames_exports);
  36. var import_browserContext = require("./browserContext");
  37. var dom = __toESM(require("./dom"));
  38. var import_errors = require("./errors");
  39. var import_fileUploadUtils = require("./fileUploadUtils");
  40. var import_frameSelectors = require("./frameSelectors");
  41. var import_helper = require("./helper");
  42. var import_instrumentation = require("./instrumentation");
  43. var js = __toESM(require("./javascript"));
  44. var network = __toESM(require("./network"));
  45. var import_page = require("./page");
  46. var import_progress = require("./progress");
  47. var types = __toESM(require("./types"));
  48. var import_utils = require("../utils");
  49. var import_protocolError = require("./protocolError");
  50. var import_debugLogger = require("./utils/debugLogger");
  51. var import_eventsHelper = require("./utils/eventsHelper");
  52. var import_selectorParser = require("../utils/isomorphic/selectorParser");
  53. var import_manualPromise = require("../utils/isomorphic/manualPromise");
  54. var import_callLog = require("./callLog");
  55. class NavigationAbortedError extends Error {
  56. constructor(documentId, message) {
  57. super(message);
  58. this.documentId = documentId;
  59. }
  60. }
  61. const kDummyFrameId = "<dummy>";
  62. class FrameManager {
  63. constructor(page) {
  64. this._frames = /* @__PURE__ */ new Map();
  65. this._consoleMessageTags = /* @__PURE__ */ new Map();
  66. this._signalBarriers = /* @__PURE__ */ new Set();
  67. this._webSockets = /* @__PURE__ */ new Map();
  68. this._page = page;
  69. this._mainFrame = void 0;
  70. }
  71. createDummyMainFrameIfNeeded() {
  72. if (!this._mainFrame)
  73. this.frameAttached(kDummyFrameId, null);
  74. }
  75. dispose() {
  76. for (const frame of this._frames.values()) {
  77. frame._stopNetworkIdleTimer();
  78. frame._invalidateNonStallingEvaluations("Target crashed");
  79. }
  80. }
  81. mainFrame() {
  82. return this._mainFrame;
  83. }
  84. frames() {
  85. const frames = [];
  86. collect(this._mainFrame);
  87. return frames;
  88. function collect(frame) {
  89. frames.push(frame);
  90. for (const subframe of frame.childFrames())
  91. collect(subframe);
  92. }
  93. }
  94. frame(frameId) {
  95. return this._frames.get(frameId) || null;
  96. }
  97. frameAttached(frameId, parentFrameId) {
  98. const parentFrame = parentFrameId ? this._frames.get(parentFrameId) : null;
  99. if (!parentFrame) {
  100. if (this._mainFrame) {
  101. this._frames.delete(this._mainFrame._id);
  102. this._mainFrame._id = frameId;
  103. } else {
  104. (0, import_utils.assert)(!this._frames.has(frameId));
  105. this._mainFrame = new Frame(this._page, frameId, parentFrame);
  106. }
  107. this._frames.set(frameId, this._mainFrame);
  108. return this._mainFrame;
  109. } else {
  110. (0, import_utils.assert)(!this._frames.has(frameId));
  111. const frame = new Frame(this._page, frameId, parentFrame);
  112. this._frames.set(frameId, frame);
  113. this._page.emit(import_page.Page.Events.FrameAttached, frame);
  114. return frame;
  115. }
  116. }
  117. async waitForSignalsCreatedBy(progress, waitAfter, action) {
  118. if (!waitAfter)
  119. return action();
  120. const barrier = new SignalBarrier(progress);
  121. this._signalBarriers.add(barrier);
  122. try {
  123. const result = await action();
  124. await progress.race(this._page.delegate.inputActionEpilogue());
  125. await barrier.waitFor();
  126. await new Promise((0, import_utils.makeWaitForNextTask)());
  127. return result;
  128. } finally {
  129. this._signalBarriers.delete(barrier);
  130. }
  131. }
  132. frameWillPotentiallyRequestNavigation() {
  133. for (const barrier of this._signalBarriers)
  134. barrier.retain();
  135. }
  136. frameDidPotentiallyRequestNavigation() {
  137. for (const barrier of this._signalBarriers)
  138. barrier.release();
  139. }
  140. frameRequestedNavigation(frameId, documentId) {
  141. const frame = this._frames.get(frameId);
  142. if (!frame)
  143. return;
  144. for (const barrier of this._signalBarriers)
  145. barrier.addFrameNavigation(frame);
  146. if (frame.pendingDocument() && frame.pendingDocument().documentId === documentId) {
  147. return;
  148. }
  149. const request = documentId ? Array.from(frame._inflightRequests).find((request2) => request2._documentId === documentId) : void 0;
  150. frame.setPendingDocument({ documentId, request });
  151. }
  152. frameCommittedNewDocumentNavigation(frameId, url, name, documentId, initial) {
  153. const frame = this._frames.get(frameId);
  154. this.removeChildFramesRecursively(frame);
  155. this.clearWebSockets(frame);
  156. frame._url = url;
  157. frame._name = name;
  158. let keepPending;
  159. const pendingDocument = frame.pendingDocument();
  160. if (pendingDocument) {
  161. if (pendingDocument.documentId === void 0) {
  162. pendingDocument.documentId = documentId;
  163. }
  164. if (pendingDocument.documentId === documentId) {
  165. frame._currentDocument = pendingDocument;
  166. } else {
  167. keepPending = pendingDocument;
  168. frame._currentDocument = { documentId, request: void 0 };
  169. }
  170. frame.setPendingDocument(void 0);
  171. } else {
  172. frame._currentDocument = { documentId, request: void 0 };
  173. }
  174. frame._onClearLifecycle();
  175. const navigationEvent = { url, name, newDocument: frame._currentDocument, isPublic: true };
  176. this._fireInternalFrameNavigation(frame, navigationEvent);
  177. if (!initial) {
  178. import_debugLogger.debugLogger.log("api", ` navigated to "${url}"`);
  179. this._page.frameNavigatedToNewDocument(frame);
  180. }
  181. frame.setPendingDocument(keepPending);
  182. }
  183. frameCommittedSameDocumentNavigation(frameId, url) {
  184. const frame = this._frames.get(frameId);
  185. if (!frame)
  186. return;
  187. const pending = frame.pendingDocument();
  188. if (pending && pending.documentId === void 0 && pending.request === void 0) {
  189. frame.setPendingDocument(void 0);
  190. }
  191. frame._url = url;
  192. const navigationEvent = { url, name: frame._name, isPublic: true };
  193. this._fireInternalFrameNavigation(frame, navigationEvent);
  194. import_debugLogger.debugLogger.log("api", ` navigated to "${url}"`);
  195. }
  196. frameAbortedNavigation(frameId, errorText, documentId) {
  197. const frame = this._frames.get(frameId);
  198. if (!frame || !frame.pendingDocument())
  199. return;
  200. if (documentId !== void 0 && frame.pendingDocument().documentId !== documentId)
  201. return;
  202. const navigationEvent = {
  203. url: frame._url,
  204. name: frame._name,
  205. newDocument: frame.pendingDocument(),
  206. error: new NavigationAbortedError(documentId, errorText),
  207. isPublic: !(documentId && frame._redirectedNavigations.has(documentId))
  208. };
  209. frame.setPendingDocument(void 0);
  210. this._fireInternalFrameNavigation(frame, navigationEvent);
  211. }
  212. frameDetached(frameId) {
  213. const frame = this._frames.get(frameId);
  214. if (frame) {
  215. this._removeFramesRecursively(frame);
  216. this._page.mainFrame()._recalculateNetworkIdle();
  217. }
  218. }
  219. frameLifecycleEvent(frameId, event) {
  220. const frame = this._frames.get(frameId);
  221. if (frame)
  222. frame._onLifecycleEvent(event);
  223. }
  224. requestStarted(request, route) {
  225. const frame = request.frame();
  226. this._inflightRequestStarted(request);
  227. if (request._documentId)
  228. frame.setPendingDocument({ documentId: request._documentId, request });
  229. if (request._isFavicon) {
  230. route?.abort("aborted").catch(() => {
  231. });
  232. return;
  233. }
  234. this._page.emitOnContext(import_browserContext.BrowserContext.Events.Request, request);
  235. if (route)
  236. new network.Route(request, route).handle([...this._page.requestInterceptors, ...this._page.browserContext.requestInterceptors]);
  237. }
  238. requestReceivedResponse(response) {
  239. if (response.request()._isFavicon)
  240. return;
  241. this._page.emitOnContext(import_browserContext.BrowserContext.Events.Response, response);
  242. }
  243. reportRequestFinished(request, response) {
  244. this._inflightRequestFinished(request);
  245. if (request._isFavicon)
  246. return;
  247. this._page.emitOnContext(import_browserContext.BrowserContext.Events.RequestFinished, { request, response });
  248. }
  249. requestFailed(request, canceled) {
  250. const frame = request.frame();
  251. this._inflightRequestFinished(request);
  252. if (frame.pendingDocument() && frame.pendingDocument().request === request) {
  253. let errorText = request.failure().errorText;
  254. if (canceled)
  255. errorText += "; maybe frame was detached?";
  256. this.frameAbortedNavigation(frame._id, errorText, frame.pendingDocument().documentId);
  257. }
  258. if (request._isFavicon)
  259. return;
  260. this._page.emitOnContext(import_browserContext.BrowserContext.Events.RequestFailed, request);
  261. }
  262. removeChildFramesRecursively(frame) {
  263. for (const child of frame.childFrames())
  264. this._removeFramesRecursively(child);
  265. }
  266. _removeFramesRecursively(frame) {
  267. this.removeChildFramesRecursively(frame);
  268. frame._onDetached();
  269. this._frames.delete(frame._id);
  270. if (!this._page.isClosed())
  271. this._page.emit(import_page.Page.Events.FrameDetached, frame);
  272. }
  273. _inflightRequestFinished(request) {
  274. const frame = request.frame();
  275. if (request._isFavicon)
  276. return;
  277. if (!frame._inflightRequests.has(request))
  278. return;
  279. frame._inflightRequests.delete(request);
  280. if (frame._inflightRequests.size === 0)
  281. frame._startNetworkIdleTimer();
  282. }
  283. _inflightRequestStarted(request) {
  284. const frame = request.frame();
  285. if (request._isFavicon)
  286. return;
  287. frame._inflightRequests.add(request);
  288. if (frame._inflightRequests.size === 1)
  289. frame._stopNetworkIdleTimer();
  290. }
  291. interceptConsoleMessage(message) {
  292. if (message.type() !== "debug")
  293. return false;
  294. const tag = message.text();
  295. const handler = this._consoleMessageTags.get(tag);
  296. if (!handler)
  297. return false;
  298. this._consoleMessageTags.delete(tag);
  299. handler();
  300. return true;
  301. }
  302. clearWebSockets(frame) {
  303. if (frame.parentFrame())
  304. return;
  305. this._webSockets.clear();
  306. }
  307. onWebSocketCreated(requestId, url) {
  308. const ws = new network.WebSocket(this._page, url);
  309. this._webSockets.set(requestId, ws);
  310. }
  311. onWebSocketRequest(requestId) {
  312. const ws = this._webSockets.get(requestId);
  313. if (ws && ws.markAsNotified())
  314. this._page.emit(import_page.Page.Events.WebSocket, ws);
  315. }
  316. onWebSocketResponse(requestId, status, statusText) {
  317. const ws = this._webSockets.get(requestId);
  318. if (status < 400)
  319. return;
  320. if (ws)
  321. ws.error(`${statusText}: ${status}`);
  322. }
  323. onWebSocketFrameSent(requestId, opcode, data) {
  324. const ws = this._webSockets.get(requestId);
  325. if (ws)
  326. ws.frameSent(opcode, data);
  327. }
  328. webSocketFrameReceived(requestId, opcode, data) {
  329. const ws = this._webSockets.get(requestId);
  330. if (ws)
  331. ws.frameReceived(opcode, data);
  332. }
  333. webSocketClosed(requestId) {
  334. const ws = this._webSockets.get(requestId);
  335. if (ws)
  336. ws.closed();
  337. this._webSockets.delete(requestId);
  338. }
  339. webSocketError(requestId, errorMessage) {
  340. const ws = this._webSockets.get(requestId);
  341. if (ws)
  342. ws.error(errorMessage);
  343. }
  344. _fireInternalFrameNavigation(frame, event) {
  345. frame.emit(Frame.Events.InternalNavigation, event);
  346. }
  347. }
  348. class Frame extends import_instrumentation.SdkObject {
  349. constructor(page, id, parentFrame) {
  350. super(page, "frame");
  351. this._firedLifecycleEvents = /* @__PURE__ */ new Set();
  352. this._firedNetworkIdleSelf = false;
  353. this._url = "";
  354. this._contextData = /* @__PURE__ */ new Map();
  355. this._childFrames = /* @__PURE__ */ new Set();
  356. this._name = "";
  357. this._inflightRequests = /* @__PURE__ */ new Set();
  358. this._setContentCounter = 0;
  359. this._detachedScope = new import_utils.LongStandingScope();
  360. this._raceAgainstEvaluationStallingEventsPromises = /* @__PURE__ */ new Set();
  361. this._redirectedNavigations = /* @__PURE__ */ new Map();
  362. this.attribution.frame = this;
  363. this._id = id;
  364. this._page = page;
  365. this._parentFrame = parentFrame;
  366. this._currentDocument = { documentId: void 0, request: void 0 };
  367. this.selectors = new import_frameSelectors.FrameSelectors(this);
  368. this._contextData.set("main", { contextPromise: new import_manualPromise.ManualPromise(), context: null });
  369. this._contextData.set("utility", { contextPromise: new import_manualPromise.ManualPromise(), context: null });
  370. this._setContext("main", null);
  371. this._setContext("utility", null);
  372. if (this._parentFrame)
  373. this._parentFrame._childFrames.add(this);
  374. this._firedLifecycleEvents.add("commit");
  375. if (id !== kDummyFrameId)
  376. this._startNetworkIdleTimer();
  377. }
  378. static {
  379. this.Events = {
  380. InternalNavigation: "internalnavigation",
  381. AddLifecycle: "addlifecycle",
  382. RemoveLifecycle: "removelifecycle"
  383. };
  384. }
  385. isDetached() {
  386. return this._detachedScope.isClosed();
  387. }
  388. _onLifecycleEvent(event) {
  389. if (this._firedLifecycleEvents.has(event))
  390. return;
  391. this._firedLifecycleEvents.add(event);
  392. this.emit(Frame.Events.AddLifecycle, event);
  393. if (this === this._page.mainFrame() && this._url !== "about:blank")
  394. import_debugLogger.debugLogger.log("api", ` "${event}" event fired`);
  395. this._page.mainFrame()._recalculateNetworkIdle();
  396. }
  397. _onClearLifecycle() {
  398. for (const event of this._firedLifecycleEvents)
  399. this.emit(Frame.Events.RemoveLifecycle, event);
  400. this._firedLifecycleEvents.clear();
  401. this._inflightRequests = new Set(Array.from(this._inflightRequests).filter((request) => request === this._currentDocument.request));
  402. this._stopNetworkIdleTimer();
  403. if (this._inflightRequests.size === 0)
  404. this._startNetworkIdleTimer();
  405. this._page.mainFrame()._recalculateNetworkIdle(this);
  406. this._onLifecycleEvent("commit");
  407. }
  408. setPendingDocument(documentInfo) {
  409. this._pendingDocument = documentInfo;
  410. if (documentInfo)
  411. this._invalidateNonStallingEvaluations("Navigation interrupted the evaluation");
  412. }
  413. pendingDocument() {
  414. return this._pendingDocument;
  415. }
  416. _invalidateNonStallingEvaluations(message) {
  417. if (!this._raceAgainstEvaluationStallingEventsPromises.size)
  418. return;
  419. const error = new Error(message);
  420. for (const promise of this._raceAgainstEvaluationStallingEventsPromises)
  421. promise.reject(error);
  422. }
  423. async raceAgainstEvaluationStallingEvents(cb) {
  424. if (this._pendingDocument)
  425. throw new Error("Frame is currently attempting a navigation");
  426. if (this._page.browserContext.dialogManager.hasOpenDialogsForPage(this._page))
  427. throw new Error("Open JavaScript dialog prevents evaluation");
  428. const promise = new import_manualPromise.ManualPromise();
  429. this._raceAgainstEvaluationStallingEventsPromises.add(promise);
  430. try {
  431. return await Promise.race([
  432. cb(),
  433. promise
  434. ]);
  435. } finally {
  436. this._raceAgainstEvaluationStallingEventsPromises.delete(promise);
  437. }
  438. }
  439. nonStallingRawEvaluateInExistingMainContext(expression) {
  440. return this.raceAgainstEvaluationStallingEvents(() => {
  441. const context = this._existingMainContext();
  442. if (!context)
  443. throw new Error("Frame does not yet have a main execution context");
  444. return context.rawEvaluateJSON(expression);
  445. });
  446. }
  447. nonStallingEvaluateInExistingContext(expression, world) {
  448. return this.raceAgainstEvaluationStallingEvents(() => {
  449. const context = this._contextData.get(world)?.context;
  450. if (!context)
  451. throw new Error("Frame does not yet have the execution context");
  452. return context.evaluateExpression(expression, { isFunction: false });
  453. });
  454. }
  455. _recalculateNetworkIdle(frameThatAllowsRemovingNetworkIdle) {
  456. let isNetworkIdle = this._firedNetworkIdleSelf;
  457. for (const child of this._childFrames) {
  458. child._recalculateNetworkIdle(frameThatAllowsRemovingNetworkIdle);
  459. if (!child._firedLifecycleEvents.has("networkidle"))
  460. isNetworkIdle = false;
  461. }
  462. if (isNetworkIdle && !this._firedLifecycleEvents.has("networkidle")) {
  463. this._firedLifecycleEvents.add("networkidle");
  464. this.emit(Frame.Events.AddLifecycle, "networkidle");
  465. if (this === this._page.mainFrame() && this._url !== "about:blank")
  466. import_debugLogger.debugLogger.log("api", ` "networkidle" event fired`);
  467. }
  468. if (frameThatAllowsRemovingNetworkIdle !== this && this._firedLifecycleEvents.has("networkidle") && !isNetworkIdle) {
  469. this._firedLifecycleEvents.delete("networkidle");
  470. this.emit(Frame.Events.RemoveLifecycle, "networkidle");
  471. }
  472. }
  473. async raceNavigationAction(progress, action) {
  474. return import_utils.LongStandingScope.raceMultiple([
  475. this._detachedScope,
  476. this._page.openScope
  477. ], action().catch((e) => {
  478. if (e instanceof NavigationAbortedError && e.documentId) {
  479. const data = this._redirectedNavigations.get(e.documentId);
  480. if (data) {
  481. progress.log(`waiting for redirected navigation to "${data.url}"`);
  482. return progress.race(data.gotoPromise);
  483. }
  484. }
  485. throw e;
  486. }));
  487. }
  488. redirectNavigation(url, documentId, referer) {
  489. const controller = new import_progress.ProgressController();
  490. const data = {
  491. url,
  492. gotoPromise: controller.run((progress) => this.gotoImpl(progress, url, { referer }), 0)
  493. };
  494. this._redirectedNavigations.set(documentId, data);
  495. data.gotoPromise.finally(() => this._redirectedNavigations.delete(documentId));
  496. }
  497. async goto(progress, url, options = {}) {
  498. const constructedNavigationURL = (0, import_utils.constructURLBasedOnBaseURL)(this._page.browserContext._options.baseURL, url);
  499. return this.raceNavigationAction(progress, async () => this.gotoImpl(progress, constructedNavigationURL, options));
  500. }
  501. async gotoImpl(progress, url, options) {
  502. const waitUntil = verifyLifecycle("waitUntil", options.waitUntil === void 0 ? "load" : options.waitUntil);
  503. progress.log(`navigating to "${url}", waiting until "${waitUntil}"`);
  504. const headers = this._page.extraHTTPHeaders() || [];
  505. const refererHeader = headers.find((h) => h.name.toLowerCase() === "referer");
  506. let referer = refererHeader ? refererHeader.value : void 0;
  507. if (options.referer !== void 0) {
  508. if (referer !== void 0 && referer !== options.referer)
  509. throw new Error('"referer" is already specified as extra HTTP header');
  510. referer = options.referer;
  511. }
  512. url = import_helper.helper.completeUserURL(url);
  513. const navigationEvents = [];
  514. const collectNavigations = (arg) => navigationEvents.push(arg);
  515. this.on(Frame.Events.InternalNavigation, collectNavigations);
  516. const navigateResult = await progress.race(this._page.delegate.navigateFrame(this, url, referer)).finally(
  517. () => this.off(Frame.Events.InternalNavigation, collectNavigations)
  518. );
  519. let event;
  520. if (navigateResult.newDocumentId) {
  521. const predicate = (event2) => {
  522. return event2.newDocument && (event2.newDocument.documentId === navigateResult.newDocumentId || !event2.error);
  523. };
  524. const events = navigationEvents.filter(predicate);
  525. if (events.length)
  526. event = events[0];
  527. else
  528. event = await import_helper.helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, predicate).promise;
  529. if (event.newDocument.documentId !== navigateResult.newDocumentId) {
  530. throw new NavigationAbortedError(navigateResult.newDocumentId, `Navigation to "${url}" is interrupted by another navigation to "${event.url}"`);
  531. }
  532. if (event.error)
  533. throw event.error;
  534. } else {
  535. const predicate = (e) => !e.newDocument;
  536. const events = navigationEvents.filter(predicate);
  537. if (events.length)
  538. event = events[0];
  539. else
  540. event = await import_helper.helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, predicate).promise;
  541. }
  542. if (!this._firedLifecycleEvents.has(waitUntil))
  543. await import_helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e) => e === waitUntil).promise;
  544. const request = event.newDocument ? event.newDocument.request : void 0;
  545. const response = request ? progress.race(request._finalRequest().response()) : null;
  546. return response;
  547. }
  548. async _waitForNavigation(progress, requiresNewDocument, options) {
  549. const waitUntil = verifyLifecycle("waitUntil", options.waitUntil === void 0 ? "load" : options.waitUntil);
  550. progress.log(`waiting for navigation until "${waitUntil}"`);
  551. const navigationEvent = await import_helper.helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, (event) => {
  552. if (event.error)
  553. return true;
  554. if (requiresNewDocument && !event.newDocument)
  555. return false;
  556. progress.log(` navigated to "${this._url}"`);
  557. return true;
  558. }).promise;
  559. if (navigationEvent.error)
  560. throw navigationEvent.error;
  561. if (!this._firedLifecycleEvents.has(waitUntil))
  562. await import_helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e) => e === waitUntil).promise;
  563. const request = navigationEvent.newDocument ? navigationEvent.newDocument.request : void 0;
  564. return request ? progress.race(request._finalRequest().response()) : null;
  565. }
  566. async _waitForLoadState(progress, state) {
  567. const waitUntil = verifyLifecycle("state", state);
  568. if (!this._firedLifecycleEvents.has(waitUntil))
  569. await import_helper.helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e) => e === waitUntil).promise;
  570. }
  571. async frameElement() {
  572. return this._page.delegate.getFrameElement(this);
  573. }
  574. _context(world) {
  575. return this._contextData.get(world).contextPromise.then((contextOrDestroyedReason) => {
  576. if (contextOrDestroyedReason instanceof js.ExecutionContext)
  577. return contextOrDestroyedReason;
  578. throw new Error(contextOrDestroyedReason.destroyedReason);
  579. });
  580. }
  581. _mainContext() {
  582. return this._context("main");
  583. }
  584. _existingMainContext() {
  585. return this._contextData.get("main")?.context || null;
  586. }
  587. _utilityContext() {
  588. return this._context("utility");
  589. }
  590. async evaluateExpression(expression, options = {}, arg) {
  591. const context = await this._context(options.world ?? "main");
  592. const value = await context.evaluateExpression(expression, options, arg);
  593. return value;
  594. }
  595. async evaluateExpressionHandle(expression, options = {}, arg) {
  596. const context = await this._context(options.world ?? "main");
  597. const value = await context.evaluateExpressionHandle(expression, options, arg);
  598. return value;
  599. }
  600. async querySelector(selector, options) {
  601. import_debugLogger.debugLogger.log("api", ` finding element using the selector "${selector}"`);
  602. return this.selectors.query(selector, options);
  603. }
  604. async waitForSelector(progress, selector, performActionPreChecksAndLog, options, scope) {
  605. if (options.visibility)
  606. throw new Error("options.visibility is not supported, did you mean options.state?");
  607. if (options.waitFor && options.waitFor !== "visible")
  608. throw new Error("options.waitFor is not supported, did you mean options.state?");
  609. const { state = "visible" } = options;
  610. if (!["attached", "detached", "visible", "hidden"].includes(state))
  611. throw new Error(`state: expected one of (attached|detached|visible|hidden)`);
  612. if (performActionPreChecksAndLog)
  613. progress.log(`waiting for ${this._asLocator(selector)}${state === "attached" ? "" : " to be " + state}`);
  614. const promise = this.retryWithProgressAndTimeouts(progress, [0, 20, 50, 100, 100, 500], async (continuePolling) => {
  615. if (performActionPreChecksAndLog)
  616. await this._page.performActionPreChecks(progress);
  617. const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector, options, scope));
  618. if (!resolved) {
  619. if (state === "hidden" || state === "detached")
  620. return null;
  621. return continuePolling;
  622. }
  623. const result = await progress.race(resolved.injected.evaluateHandle((injected, { info, root }) => {
  624. if (root && !root.isConnected)
  625. throw injected.createStacklessError("Element is not attached to the DOM");
  626. const elements = injected.querySelectorAll(info.parsed, root || document);
  627. const element2 = elements[0];
  628. const visible2 = element2 ? injected.utils.isElementVisible(element2) : false;
  629. let log2 = "";
  630. if (elements.length > 1) {
  631. if (info.strict)
  632. throw injected.strictModeViolationError(info.parsed, elements);
  633. log2 = ` locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(elements[0])}`;
  634. } else if (element2) {
  635. log2 = ` locator resolved to ${visible2 ? "visible" : "hidden"} ${injected.previewNode(element2)}`;
  636. }
  637. return { log: log2, element: element2, visible: visible2, attached: !!element2 };
  638. }, { info: resolved.info, root: resolved.frame === this ? scope : void 0 }));
  639. const { log, visible, attached } = await progress.race(result.evaluate((r) => ({ log: r.log, visible: r.visible, attached: r.attached })));
  640. if (log)
  641. progress.log(log);
  642. const success = { attached, detached: !attached, visible, hidden: !visible }[state];
  643. if (!success) {
  644. result.dispose();
  645. return continuePolling;
  646. }
  647. if (options.omitReturnValue) {
  648. result.dispose();
  649. return null;
  650. }
  651. const element = state === "attached" || state === "visible" ? await progress.race(result.evaluateHandle((r) => r.element)) : null;
  652. result.dispose();
  653. if (!element)
  654. return null;
  655. if (options.__testHookBeforeAdoptNode)
  656. await progress.race(options.__testHookBeforeAdoptNode());
  657. try {
  658. const mainContext = await progress.race(resolved.frame._mainContext());
  659. return await progress.race(element._adoptTo(mainContext));
  660. } catch (e) {
  661. return continuePolling;
  662. }
  663. });
  664. return scope ? scope._context._raceAgainstContextDestroyed(promise) : promise;
  665. }
  666. async dispatchEvent(progress, selector, type, eventInit = {}, options, scope) {
  667. await this._callOnElementOnceMatches(progress, selector, (injectedScript, element, data) => {
  668. injectedScript.dispatchEvent(element, data.type, data.eventInit);
  669. }, { type, eventInit }, { mainWorld: true, ...options }, scope);
  670. }
  671. async evalOnSelector(selector, strict, expression, isFunction, arg, scope) {
  672. const handle = await this.selectors.query(selector, { strict }, scope);
  673. if (!handle)
  674. throw new Error(`Failed to find element matching selector "${selector}"`);
  675. const result = await handle.evaluateExpression(expression, { isFunction }, arg);
  676. handle.dispose();
  677. return result;
  678. }
  679. async evalOnSelectorAll(selector, expression, isFunction, arg, scope) {
  680. const arrayHandle = await this.selectors.queryArrayInMainWorld(selector, scope);
  681. const result = await arrayHandle.evaluateExpression(expression, { isFunction }, arg);
  682. arrayHandle.dispose();
  683. return result;
  684. }
  685. async maskSelectors(selectors, color) {
  686. const context = await this._utilityContext();
  687. const injectedScript = await context.injectedScript();
  688. await injectedScript.evaluate((injected, { parsed, color: color2 }) => {
  689. injected.maskSelectors(parsed, color2);
  690. }, { parsed: selectors, color });
  691. }
  692. async querySelectorAll(selector) {
  693. return this.selectors.queryAll(selector);
  694. }
  695. async queryCount(selector, options) {
  696. try {
  697. return await this.selectors.queryCount(selector, options);
  698. } catch (e) {
  699. if (this.isNonRetriableError(e))
  700. throw e;
  701. return 0;
  702. }
  703. }
  704. async content() {
  705. try {
  706. const context = await this._utilityContext();
  707. return await context.evaluate(() => {
  708. let retVal = "";
  709. if (document.doctype)
  710. retVal = new XMLSerializer().serializeToString(document.doctype);
  711. if (document.documentElement)
  712. retVal += document.documentElement.outerHTML;
  713. return retVal;
  714. });
  715. } catch (e) {
  716. if (this.isNonRetriableError(e))
  717. throw e;
  718. throw new Error(`Unable to retrieve content because the page is navigating and changing the content.`);
  719. }
  720. }
  721. async setContent(progress, html, options) {
  722. const tag = `--playwright--set--content--${this._id}--${++this._setContentCounter}--`;
  723. await this.raceNavigationAction(progress, async () => {
  724. const waitUntil = options.waitUntil === void 0 ? "load" : options.waitUntil;
  725. progress.log(`setting frame content, waiting until "${waitUntil}"`);
  726. const context = await progress.race(this._utilityContext());
  727. const tagPromise = new import_manualPromise.ManualPromise();
  728. this._page.frameManager._consoleMessageTags.set(tag, () => {
  729. this._onClearLifecycle();
  730. tagPromise.resolve();
  731. });
  732. const lifecyclePromise = progress.race(tagPromise).then(() => this._waitForLoadState(progress, waitUntil));
  733. const contentPromise = progress.race(context.evaluate(({ html: html2, tag: tag2 }) => {
  734. document.open();
  735. console.debug(tag2);
  736. document.write(html2);
  737. document.close();
  738. }, { html, tag }));
  739. await Promise.all([contentPromise, lifecyclePromise]);
  740. return null;
  741. }).finally(() => {
  742. this._page.frameManager._consoleMessageTags.delete(tag);
  743. });
  744. }
  745. name() {
  746. return this._name || "";
  747. }
  748. url() {
  749. return this._url;
  750. }
  751. origin() {
  752. if (!this._url.startsWith("http"))
  753. return;
  754. return network.parseURL(this._url)?.origin;
  755. }
  756. parentFrame() {
  757. return this._parentFrame;
  758. }
  759. childFrames() {
  760. return Array.from(this._childFrames);
  761. }
  762. async addScriptTag(params) {
  763. const {
  764. url = null,
  765. content = null,
  766. type = ""
  767. } = params;
  768. if (!url && !content)
  769. throw new Error("Provide an object with a `url`, `path` or `content` property");
  770. const context = await this._mainContext();
  771. return this._raceWithCSPError(async () => {
  772. if (url !== null)
  773. return (await context.evaluateHandle(addScriptUrl, { url, type })).asElement();
  774. const result = (await context.evaluateHandle(addScriptContent, { content, type })).asElement();
  775. if (this._page.delegate.cspErrorsAsynchronousForInlineScripts)
  776. await context.evaluate(() => true);
  777. return result;
  778. });
  779. async function addScriptUrl(params2) {
  780. const script = document.createElement("script");
  781. script.src = params2.url;
  782. if (params2.type)
  783. script.type = params2.type;
  784. const promise = new Promise((res, rej) => {
  785. script.onload = res;
  786. script.onerror = (e) => rej(typeof e === "string" ? new Error(e) : new Error(`Failed to load script at ${script.src}`));
  787. });
  788. document.head.appendChild(script);
  789. await promise;
  790. return script;
  791. }
  792. function addScriptContent(params2) {
  793. const script = document.createElement("script");
  794. script.type = params2.type || "text/javascript";
  795. script.text = params2.content;
  796. let error = null;
  797. script.onerror = (e) => error = e;
  798. document.head.appendChild(script);
  799. if (error)
  800. throw error;
  801. return script;
  802. }
  803. }
  804. async addStyleTag(params) {
  805. const {
  806. url = null,
  807. content = null
  808. } = params;
  809. if (!url && !content)
  810. throw new Error("Provide an object with a `url`, `path` or `content` property");
  811. const context = await this._mainContext();
  812. return this._raceWithCSPError(async () => {
  813. if (url !== null)
  814. return (await context.evaluateHandle(addStyleUrl, url)).asElement();
  815. return (await context.evaluateHandle(addStyleContent, content)).asElement();
  816. });
  817. async function addStyleUrl(url2) {
  818. const link = document.createElement("link");
  819. link.rel = "stylesheet";
  820. link.href = url2;
  821. const promise = new Promise((res, rej) => {
  822. link.onload = res;
  823. link.onerror = rej;
  824. });
  825. document.head.appendChild(link);
  826. await promise;
  827. return link;
  828. }
  829. async function addStyleContent(content2) {
  830. const style = document.createElement("style");
  831. style.type = "text/css";
  832. style.appendChild(document.createTextNode(content2));
  833. const promise = new Promise((res, rej) => {
  834. style.onload = res;
  835. style.onerror = rej;
  836. });
  837. document.head.appendChild(style);
  838. await promise;
  839. return style;
  840. }
  841. }
  842. async _raceWithCSPError(func) {
  843. const listeners = [];
  844. let result;
  845. let error;
  846. let cspMessage;
  847. const actionPromise = func().then((r) => result = r).catch((e) => error = e);
  848. const errorPromise = new Promise((resolve) => {
  849. listeners.push(import_eventsHelper.eventsHelper.addEventListener(this._page.browserContext, import_browserContext.BrowserContext.Events.Console, (message) => {
  850. if (message.page() !== this._page || message.type() !== "error")
  851. return;
  852. if (message.text().includes("Content-Security-Policy") || message.text().includes("Content Security Policy")) {
  853. cspMessage = message;
  854. resolve();
  855. }
  856. }));
  857. });
  858. await Promise.race([actionPromise, errorPromise]);
  859. import_eventsHelper.eventsHelper.removeEventListeners(listeners);
  860. if (cspMessage)
  861. throw new Error(cspMessage.text());
  862. if (error)
  863. throw error;
  864. return result;
  865. }
  866. async retryWithProgressAndTimeouts(progress, timeouts, action) {
  867. const continuePolling = Symbol("continuePolling");
  868. timeouts = [0, ...timeouts];
  869. let timeoutIndex = 0;
  870. while (true) {
  871. const timeout = timeouts[Math.min(timeoutIndex++, timeouts.length - 1)];
  872. if (timeout) {
  873. const actionPromise = new Promise((f) => setTimeout(f, timeout));
  874. await progress.race(import_utils.LongStandingScope.raceMultiple([
  875. this._page.openScope,
  876. this._detachedScope
  877. ], actionPromise));
  878. }
  879. try {
  880. const result = await action(continuePolling);
  881. if (result === continuePolling)
  882. continue;
  883. return result;
  884. } catch (e) {
  885. if (this.isNonRetriableError(e))
  886. throw e;
  887. continue;
  888. }
  889. }
  890. }
  891. isNonRetriableError(e) {
  892. if ((0, import_progress.isAbortError)(e))
  893. return true;
  894. if (js.isJavaScriptErrorInEvaluate(e) || (0, import_protocolError.isSessionClosedError)(e))
  895. return true;
  896. if (dom.isNonRecoverableDOMError(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
  897. return true;
  898. if (this.isDetached())
  899. return true;
  900. return false;
  901. }
  902. async _retryWithProgressIfNotConnected(progress, selector, strict, performActionPreChecks, action) {
  903. progress.log(`waiting for ${this._asLocator(selector)}`);
  904. return this.retryWithProgressAndTimeouts(progress, [0, 20, 50, 100, 100, 500], async (continuePolling) => {
  905. if (performActionPreChecks)
  906. await this._page.performActionPreChecks(progress);
  907. const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector, { strict }));
  908. if (!resolved)
  909. return continuePolling;
  910. const result = await progress.race(resolved.injected.evaluateHandle((injected, { info, callId }) => {
  911. const elements = injected.querySelectorAll(info.parsed, document);
  912. if (callId)
  913. injected.markTargetElements(new Set(elements), callId);
  914. const element2 = elements[0];
  915. let log2 = "";
  916. if (elements.length > 1) {
  917. if (info.strict)
  918. throw injected.strictModeViolationError(info.parsed, elements);
  919. log2 = ` locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(elements[0])}`;
  920. } else if (element2) {
  921. log2 = ` locator resolved to ${injected.previewNode(element2)}`;
  922. }
  923. return { log: log2, success: !!element2, element: element2 };
  924. }, { info: resolved.info, callId: progress.metadata.id }));
  925. const { log, success } = await progress.race(result.evaluate((r) => ({ log: r.log, success: r.success })));
  926. if (log)
  927. progress.log(log);
  928. if (!success) {
  929. result.dispose();
  930. return continuePolling;
  931. }
  932. const element = await progress.race(result.evaluateHandle((r) => r.element));
  933. result.dispose();
  934. try {
  935. const result2 = await action(element);
  936. if (result2 === "error:notconnected") {
  937. progress.log("element was detached from the DOM, retrying");
  938. return continuePolling;
  939. }
  940. return result2;
  941. } finally {
  942. element?.dispose();
  943. }
  944. });
  945. }
  946. async rafrafTimeoutScreenshotElementWithProgress(progress, selector, timeout, options) {
  947. return await this._retryWithProgressIfNotConnected(progress, selector, true, true, async (handle) => {
  948. await handle._frame.rafrafTimeout(progress, timeout);
  949. return await this._page.screenshotter.screenshotElement(progress, handle, options);
  950. });
  951. }
  952. async click(progress, selector, options) {
  953. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._click(progress, { ...options, waitAfter: !options.noWaitAfter })));
  954. }
  955. async dblclick(progress, selector, options) {
  956. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._dblclick(progress, options)));
  957. }
  958. async dragAndDrop(progress, source, target, options) {
  959. dom.assertDone(await this._retryWithProgressIfNotConnected(progress, source, options.strict, !options.force, async (handle) => {
  960. return handle._retryPointerAction(progress, "move and down", false, async (point) => {
  961. await this._page.mouse.move(progress, point.x, point.y);
  962. await this._page.mouse.down(progress);
  963. }, {
  964. ...options,
  965. waitAfter: "disabled",
  966. position: options.sourcePosition
  967. });
  968. }));
  969. dom.assertDone(await this._retryWithProgressIfNotConnected(progress, target, options.strict, false, async (handle) => {
  970. return handle._retryPointerAction(progress, "move and up", false, async (point) => {
  971. await this._page.mouse.move(progress, point.x, point.y);
  972. await this._page.mouse.up(progress);
  973. }, {
  974. ...options,
  975. waitAfter: "disabled",
  976. position: options.targetPosition
  977. });
  978. }));
  979. }
  980. async tap(progress, selector, options) {
  981. if (!this._page.browserContext._options.hasTouch)
  982. throw new Error("The page does not support tap. Use hasTouch context option to enable touch support.");
  983. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._tap(progress, options)));
  984. }
  985. async fill(progress, selector, value, options) {
  986. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._fill(progress, value, options)));
  987. }
  988. async focus(progress, selector, options) {
  989. dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._focus(progress)));
  990. }
  991. async blur(progress, selector, options) {
  992. dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._blur(progress)));
  993. }
  994. async resolveSelector(progress, selector, options = {}) {
  995. const element = await progress.race(this.selectors.query(selector, options));
  996. if (!element)
  997. throw new Error(`No element matching ${selector}`);
  998. const generated = await progress.race(element.evaluateInUtility(async ([injected, node]) => {
  999. return injected.generateSelectorSimple(node);
  1000. }, {}));
  1001. if (!generated)
  1002. throw new Error(`Unable to generate locator for ${selector}`);
  1003. let frame = element._frame;
  1004. const result = [generated];
  1005. while (frame?.parentFrame()) {
  1006. const frameElement = await progress.race(frame.frameElement());
  1007. if (frameElement) {
  1008. const generated2 = await progress.race(frameElement.evaluateInUtility(async ([injected, node]) => {
  1009. return injected.generateSelectorSimple(node);
  1010. }, {}));
  1011. frameElement.dispose();
  1012. if (generated2 === "error:notconnected" || !generated2)
  1013. throw new Error(`Unable to generate locator for ${selector}`);
  1014. result.push(generated2);
  1015. }
  1016. frame = frame.parentFrame();
  1017. }
  1018. const resolvedSelector = result.reverse().join(" >> internal:control=enter-frame >> ");
  1019. return { resolvedSelector };
  1020. }
  1021. async textContent(progress, selector, options, scope) {
  1022. return this._callOnElementOnceMatches(progress, selector, (injected, element) => element.textContent, void 0, options, scope);
  1023. }
  1024. async innerText(progress, selector, options, scope) {
  1025. return this._callOnElementOnceMatches(progress, selector, (injectedScript, element) => {
  1026. if (element.namespaceURI !== "http://www.w3.org/1999/xhtml")
  1027. throw injectedScript.createStacklessError("Node is not an HTMLElement");
  1028. return element.innerText;
  1029. }, void 0, options, scope);
  1030. }
  1031. async innerHTML(progress, selector, options, scope) {
  1032. return this._callOnElementOnceMatches(progress, selector, (injected, element) => element.innerHTML, void 0, options, scope);
  1033. }
  1034. async getAttribute(progress, selector, name, options, scope) {
  1035. return this._callOnElementOnceMatches(progress, selector, (injected, element, data) => element.getAttribute(data.name), { name }, options, scope);
  1036. }
  1037. async inputValue(progress, selector, options, scope) {
  1038. return this._callOnElementOnceMatches(progress, selector, (injectedScript, node) => {
  1039. const element = injectedScript.retarget(node, "follow-label");
  1040. if (!element || element.nodeName !== "INPUT" && element.nodeName !== "TEXTAREA" && element.nodeName !== "SELECT")
  1041. throw injectedScript.createStacklessError("Node is not an <input>, <textarea> or <select> element");
  1042. return element.value;
  1043. }, void 0, options, scope);
  1044. }
  1045. async highlight(progress, selector) {
  1046. const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector));
  1047. if (!resolved)
  1048. return;
  1049. return await progress.race(resolved.injected.evaluate((injected, { info }) => {
  1050. return injected.highlight(info.parsed);
  1051. }, { info: resolved.info }));
  1052. }
  1053. async hideHighlight() {
  1054. return this.raceAgainstEvaluationStallingEvents(async () => {
  1055. const context = await this._utilityContext();
  1056. const injectedScript = await context.injectedScript();
  1057. return await injectedScript.evaluate((injected) => {
  1058. return injected.hideHighlight();
  1059. });
  1060. });
  1061. }
  1062. async _elementState(progress, selector, state, options, scope) {
  1063. const result = await this._callOnElementOnceMatches(progress, selector, (injected, element, data) => {
  1064. return injected.elementState(element, data.state);
  1065. }, { state }, options, scope);
  1066. if (result.received === "error:notconnected")
  1067. dom.throwElementIsNotAttached();
  1068. return result.matches;
  1069. }
  1070. async isVisible(progress, selector, options = {}, scope) {
  1071. progress.log(` checking visibility of ${this._asLocator(selector)}`);
  1072. return await this.isVisibleInternal(progress, selector, options, scope);
  1073. }
  1074. async isVisibleInternal(progress, selector, options = {}, scope) {
  1075. try {
  1076. const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector, options, scope));
  1077. if (!resolved)
  1078. return false;
  1079. return await progress.race(resolved.injected.evaluate((injected, { info, root }) => {
  1080. const element = injected.querySelector(info.parsed, root || document, info.strict);
  1081. const state = element ? injected.elementState(element, "visible") : { matches: false, received: "error:notconnected" };
  1082. return state.matches;
  1083. }, { info: resolved.info, root: resolved.frame === this ? scope : void 0 }));
  1084. } catch (e) {
  1085. if (this.isNonRetriableError(e))
  1086. throw e;
  1087. return false;
  1088. }
  1089. }
  1090. async isHidden(progress, selector, options = {}, scope) {
  1091. return !await this.isVisible(progress, selector, options, scope);
  1092. }
  1093. async isDisabled(progress, selector, options, scope) {
  1094. return this._elementState(progress, selector, "disabled", options, scope);
  1095. }
  1096. async isEnabled(progress, selector, options, scope) {
  1097. return this._elementState(progress, selector, "enabled", options, scope);
  1098. }
  1099. async isEditable(progress, selector, options, scope) {
  1100. return this._elementState(progress, selector, "editable", options, scope);
  1101. }
  1102. async isChecked(progress, selector, options, scope) {
  1103. return this._elementState(progress, selector, "checked", options, scope);
  1104. }
  1105. async hover(progress, selector, options) {
  1106. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._hover(progress, options)));
  1107. }
  1108. async selectOption(progress, selector, elements, values, options) {
  1109. return await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._selectOption(progress, elements, values, options));
  1110. }
  1111. async setInputFiles(progress, selector, params) {
  1112. const inputFileItems = await (0, import_fileUploadUtils.prepareFilesForUpload)(this, params);
  1113. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, params.strict, true, (handle) => handle._setInputFiles(progress, inputFileItems)));
  1114. }
  1115. async type(progress, selector, text, options) {
  1116. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._type(progress, text, options)));
  1117. }
  1118. async press(progress, selector, key, options) {
  1119. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._press(progress, key, options)));
  1120. }
  1121. async check(progress, selector, options) {
  1122. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._setChecked(progress, true, options)));
  1123. }
  1124. async uncheck(progress, selector, options) {
  1125. return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._setChecked(progress, false, options)));
  1126. }
  1127. async waitForTimeout(progress, timeout) {
  1128. return progress.wait(timeout);
  1129. }
  1130. async ariaSnapshot(progress, selector) {
  1131. return await this._retryWithProgressIfNotConnected(progress, selector, true, true, (handle) => progress.race(handle.ariaSnapshot()));
  1132. }
  1133. async expect(progress, selector, options, timeout) {
  1134. progress.log(`${(0, import_utils.renderTitleForCall)(progress.metadata)}${timeout ? ` with timeout ${timeout}ms` : ""}`);
  1135. const lastIntermediateResult = { isSet: false };
  1136. const fixupMetadataError = (result) => {
  1137. if (result.matches === options.isNot)
  1138. progress.metadata.error = { error: { name: "Expect", message: "Expect failed" } };
  1139. };
  1140. try {
  1141. if (selector)
  1142. progress.log(`waiting for ${this._asLocator(selector)}`);
  1143. await this._page.performActionPreChecks(progress);
  1144. try {
  1145. const resultOneShot = await this._expectInternal(progress, selector, options, lastIntermediateResult, true);
  1146. if (resultOneShot.matches !== options.isNot)
  1147. return resultOneShot;
  1148. } catch (e) {
  1149. if (this.isNonRetriableError(e))
  1150. throw e;
  1151. }
  1152. const result = await this.retryWithProgressAndTimeouts(progress, [100, 250, 500, 1e3], async (continuePolling) => {
  1153. await this._page.performActionPreChecks(progress);
  1154. const { matches, received } = await this._expectInternal(progress, selector, options, lastIntermediateResult, false);
  1155. if (matches === options.isNot) {
  1156. return continuePolling;
  1157. }
  1158. return { matches, received };
  1159. });
  1160. fixupMetadataError(result);
  1161. return result;
  1162. } catch (e) {
  1163. if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
  1164. throw e;
  1165. const result = { matches: options.isNot, log: (0, import_callLog.compressCallLog)(progress.metadata.log) };
  1166. if (lastIntermediateResult.isSet)
  1167. result.received = lastIntermediateResult.received;
  1168. if (e instanceof import_errors.TimeoutError)
  1169. result.timedOut = true;
  1170. fixupMetadataError(result);
  1171. return result;
  1172. }
  1173. }
  1174. async _expectInternal(progress, selector, options, lastIntermediateResult, noAbort) {
  1175. const race = (p) => noAbort ? p : progress.race(p);
  1176. const selectorInFrame = selector ? await race(this.selectors.resolveFrameForSelector(selector, { strict: true })) : void 0;
  1177. const { frame, info } = selectorInFrame || { frame: this, info: void 0 };
  1178. const world = options.expression === "to.have.property" ? "main" : info?.world ?? "utility";
  1179. const context = await race(frame._context(world));
  1180. const injected = await race(context.injectedScript());
  1181. const { log, matches, received, missingReceived } = await race(injected.evaluate(async (injected2, { info: info2, options: options2, callId }) => {
  1182. const elements = info2 ? injected2.querySelectorAll(info2.parsed, document) : [];
  1183. if (callId)
  1184. injected2.markTargetElements(new Set(elements), callId);
  1185. const isArray = options2.expression === "to.have.count" || options2.expression.endsWith(".array");
  1186. let log2 = "";
  1187. if (isArray)
  1188. log2 = ` locator resolved to ${elements.length} element${elements.length === 1 ? "" : "s"}`;
  1189. else if (elements.length > 1)
  1190. throw injected2.strictModeViolationError(info2.parsed, elements);
  1191. else if (elements.length)
  1192. log2 = ` locator resolved to ${injected2.previewNode(elements[0])}`;
  1193. return { log: log2, ...await injected2.expect(elements[0], options2, elements) };
  1194. }, { info, options, callId: progress.metadata.id }));
  1195. if (log)
  1196. progress.log(log);
  1197. if (matches === options.isNot) {
  1198. lastIntermediateResult.received = missingReceived ? "<element(s) not found>" : received;
  1199. lastIntermediateResult.isSet = true;
  1200. if (!missingReceived && !Array.isArray(received))
  1201. progress.log(` unexpected value "${renderUnexpectedValue(options.expression, received)}"`);
  1202. }
  1203. return { matches, received };
  1204. }
  1205. async waitForFunctionExpression(progress, expression, isFunction, arg, options, world = "main") {
  1206. if (typeof options.pollingInterval === "number")
  1207. (0, import_utils.assert)(options.pollingInterval > 0, "Cannot poll with non-positive interval: " + options.pollingInterval);
  1208. expression = js.normalizeEvaluationExpression(expression, isFunction);
  1209. return this.retryWithProgressAndTimeouts(progress, [100], async () => {
  1210. const context = world === "main" ? await progress.race(this._mainContext()) : await progress.race(this._utilityContext());
  1211. const injectedScript = await progress.race(context.injectedScript());
  1212. const handle = await progress.race(injectedScript.evaluateHandle((injected, { expression: expression2, isFunction: isFunction2, polling, arg: arg2 }) => {
  1213. let evaledExpression;
  1214. const predicate = () => {
  1215. let result2 = evaledExpression ?? globalThis.eval(expression2);
  1216. if (isFunction2 === true) {
  1217. evaledExpression = result2;
  1218. result2 = result2(arg2);
  1219. } else if (isFunction2 === false) {
  1220. result2 = result2;
  1221. } else {
  1222. if (typeof result2 === "function") {
  1223. evaledExpression = result2;
  1224. result2 = result2(arg2);
  1225. }
  1226. }
  1227. return result2;
  1228. };
  1229. let fulfill;
  1230. let reject;
  1231. let aborted = false;
  1232. const result = new Promise((f, r) => {
  1233. fulfill = f;
  1234. reject = r;
  1235. });
  1236. const next = () => {
  1237. if (aborted)
  1238. return;
  1239. try {
  1240. const success = predicate();
  1241. if (success) {
  1242. fulfill(success);
  1243. return;
  1244. }
  1245. if (typeof polling !== "number")
  1246. injected.utils.builtins.requestAnimationFrame(next);
  1247. else
  1248. injected.utils.builtins.setTimeout(next, polling);
  1249. } catch (e) {
  1250. reject(e);
  1251. }
  1252. };
  1253. next();
  1254. return { result, abort: () => aborted = true };
  1255. }, { expression, isFunction, polling: options.pollingInterval, arg }));
  1256. try {
  1257. return await progress.race(handle.evaluateHandle((h) => h.result));
  1258. } catch (error) {
  1259. await handle.evaluate((h) => h.abort()).catch(() => {
  1260. });
  1261. throw error;
  1262. } finally {
  1263. handle.dispose();
  1264. }
  1265. });
  1266. }
  1267. async waitForFunctionValueInUtility(progress, pageFunction) {
  1268. const expression = `() => {
  1269. const result = (${pageFunction})();
  1270. if (!result)
  1271. return result;
  1272. return JSON.stringify(result);
  1273. }`;
  1274. const handle = await this.waitForFunctionExpression(progress, expression, true, void 0, {}, "utility");
  1275. return JSON.parse(handle.rawValue());
  1276. }
  1277. async title() {
  1278. const context = await this._utilityContext();
  1279. return context.evaluate(() => document.title);
  1280. }
  1281. async rafrafTimeout(progress, timeout) {
  1282. if (timeout === 0)
  1283. return;
  1284. const context = await progress.race(this._utilityContext());
  1285. await Promise.all([
  1286. // wait for double raf
  1287. progress.race(context.evaluate(() => new Promise((x) => {
  1288. requestAnimationFrame(() => {
  1289. requestAnimationFrame(x);
  1290. });
  1291. }))),
  1292. progress.wait(timeout)
  1293. ]);
  1294. }
  1295. _onDetached() {
  1296. this._stopNetworkIdleTimer();
  1297. this._detachedScope.close(new Error("Frame was detached"));
  1298. for (const data of this._contextData.values()) {
  1299. if (data.context)
  1300. data.context.contextDestroyed("Frame was detached");
  1301. data.contextPromise.resolve({ destroyedReason: "Frame was detached" });
  1302. }
  1303. if (this._parentFrame)
  1304. this._parentFrame._childFrames.delete(this);
  1305. this._parentFrame = null;
  1306. }
  1307. async _callOnElementOnceMatches(progress, selector, body, taskData, options, scope) {
  1308. const callbackText = body.toString();
  1309. progress.log(`waiting for ${this._asLocator(selector)}`);
  1310. const promise = this.retryWithProgressAndTimeouts(progress, [0, 20, 50, 100, 100, 500], async (continuePolling) => {
  1311. const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector, options, scope));
  1312. if (!resolved)
  1313. return continuePolling;
  1314. const { log, success, value } = await progress.race(resolved.injected.evaluate((injected, { info, callbackText: callbackText2, taskData: taskData2, callId, root }) => {
  1315. const callback = injected.eval(callbackText2);
  1316. const element = injected.querySelector(info.parsed, root || document, info.strict);
  1317. if (!element)
  1318. return { success: false };
  1319. const log2 = ` locator resolved to ${injected.previewNode(element)}`;
  1320. if (callId)
  1321. injected.markTargetElements(/* @__PURE__ */ new Set([element]), callId);
  1322. return { log: log2, success: true, value: callback(injected, element, taskData2) };
  1323. }, { info: resolved.info, callbackText, taskData, callId: progress.metadata.id, root: resolved.frame === this ? scope : void 0 }));
  1324. if (log)
  1325. progress.log(log);
  1326. if (!success)
  1327. return continuePolling;
  1328. return value;
  1329. });
  1330. return scope ? scope._context._raceAgainstContextDestroyed(promise) : promise;
  1331. }
  1332. _setContext(world, context) {
  1333. const data = this._contextData.get(world);
  1334. data.context = context;
  1335. if (context)
  1336. data.contextPromise.resolve(context);
  1337. else
  1338. data.contextPromise = new import_manualPromise.ManualPromise();
  1339. }
  1340. _contextCreated(world, context) {
  1341. const data = this._contextData.get(world);
  1342. if (data.context) {
  1343. data.context.contextDestroyed("Execution context was destroyed, most likely because of a navigation");
  1344. this._setContext(world, null);
  1345. }
  1346. this._setContext(world, context);
  1347. }
  1348. _contextDestroyed(context) {
  1349. if (this._detachedScope.isClosed())
  1350. return;
  1351. context.contextDestroyed("Execution context was destroyed, most likely because of a navigation");
  1352. for (const [world, data] of this._contextData) {
  1353. if (data.context === context)
  1354. this._setContext(world, null);
  1355. }
  1356. }
  1357. _startNetworkIdleTimer() {
  1358. (0, import_utils.assert)(!this._networkIdleTimer);
  1359. if (this._firedLifecycleEvents.has("networkidle") || this._detachedScope.isClosed())
  1360. return;
  1361. this._networkIdleTimer = setTimeout(() => {
  1362. this._firedNetworkIdleSelf = true;
  1363. this._page.mainFrame()._recalculateNetworkIdle();
  1364. }, 500);
  1365. }
  1366. _stopNetworkIdleTimer() {
  1367. if (this._networkIdleTimer)
  1368. clearTimeout(this._networkIdleTimer);
  1369. this._networkIdleTimer = void 0;
  1370. this._firedNetworkIdleSelf = false;
  1371. }
  1372. async extendInjectedScript(source, arg) {
  1373. const context = await this._context("main");
  1374. const injectedScriptHandle = await context.injectedScript();
  1375. await injectedScriptHandle.evaluate((injectedScript, { source: source2, arg: arg2 }) => {
  1376. injectedScript.extend(source2, arg2);
  1377. }, { source, arg });
  1378. }
  1379. _asLocator(selector) {
  1380. return (0, import_utils.asLocator)(this._page.browserContext._browser.sdkLanguage(), selector);
  1381. }
  1382. }
  1383. class SignalBarrier {
  1384. constructor(progress) {
  1385. this._protectCount = 0;
  1386. this._promise = new import_manualPromise.ManualPromise();
  1387. this._progress = progress;
  1388. this.retain();
  1389. }
  1390. waitFor() {
  1391. this.release();
  1392. return this._progress.race(this._promise);
  1393. }
  1394. addFrameNavigation(frame) {
  1395. if (frame.parentFrame())
  1396. return;
  1397. this.retain();
  1398. const waiter = import_helper.helper.waitForEvent(this._progress, frame, Frame.Events.InternalNavigation, (e) => {
  1399. if (!e.isPublic)
  1400. return false;
  1401. if (!e.error && this._progress)
  1402. this._progress.log(` navigated to "${frame._url}"`);
  1403. return true;
  1404. });
  1405. import_utils.LongStandingScope.raceMultiple([
  1406. frame._page.openScope,
  1407. frame._detachedScope
  1408. ], waiter.promise).catch(() => {
  1409. }).finally(() => {
  1410. waiter.dispose();
  1411. this.release();
  1412. });
  1413. }
  1414. retain() {
  1415. ++this._protectCount;
  1416. }
  1417. release() {
  1418. --this._protectCount;
  1419. if (!this._protectCount)
  1420. this._promise.resolve();
  1421. }
  1422. }
  1423. function verifyLifecycle(name, waitUntil) {
  1424. if (waitUntil === "networkidle0")
  1425. waitUntil = "networkidle";
  1426. if (!types.kLifecycleEvents.has(waitUntil))
  1427. throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`);
  1428. return waitUntil;
  1429. }
  1430. function renderUnexpectedValue(expression, received) {
  1431. if (expression === "to.match.aria")
  1432. return received ? received.raw : received;
  1433. return received;
  1434. }
  1435. // Annotate the CommonJS export names for ESM import in node:
  1436. 0 && (module.exports = {
  1437. Frame,
  1438. FrameManager,
  1439. NavigationAbortedError
  1440. });