_page.py 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613
  1. # Copyright (c) Microsoft Corporation.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import asyncio
  15. import base64
  16. import inspect
  17. import re
  18. import sys
  19. from pathlib import Path
  20. from types import SimpleNamespace
  21. from typing import (
  22. TYPE_CHECKING,
  23. Any,
  24. Awaitable,
  25. Callable,
  26. Dict,
  27. List,
  28. Literal,
  29. Optional,
  30. Pattern,
  31. Sequence,
  32. Union,
  33. cast,
  34. )
  35. from playwright._impl._api_structures import (
  36. AriaRole,
  37. FilePayload,
  38. FloatRect,
  39. PdfMargins,
  40. Position,
  41. ViewportSize,
  42. )
  43. from playwright._impl._artifact import Artifact
  44. from playwright._impl._clock import Clock
  45. from playwright._impl._connection import (
  46. ChannelOwner,
  47. from_channel,
  48. from_nullable_channel,
  49. )
  50. from playwright._impl._console_message import ConsoleMessage
  51. from playwright._impl._disposable import Disposable, DisposableStub
  52. from playwright._impl._download import Download
  53. from playwright._impl._element_handle import ElementHandle, determine_screenshot_type
  54. from playwright._impl._errors import Error, TargetClosedError, is_target_closed_error
  55. from playwright._impl._event_context_manager import EventContextManagerImpl
  56. from playwright._impl._file_chooser import FileChooser
  57. from playwright._impl._frame import Frame
  58. from playwright._impl._greenlets import LocatorHandlerGreenlet
  59. from playwright._impl._har_router import HarRouter
  60. from playwright._impl._helper import (
  61. ColorScheme,
  62. Contrast,
  63. DocumentLoadState,
  64. ForcedColors,
  65. HarMode,
  66. KeyboardModifier,
  67. MouseButton,
  68. ReducedMotion,
  69. RouteFromHarNotFoundPolicy,
  70. RouteHandler,
  71. RouteHandlerCallback,
  72. TimeoutSettings,
  73. URLMatch,
  74. URLMatchRequest,
  75. URLMatchResponse,
  76. WebSocketRouteHandlerCallback,
  77. async_readfile,
  78. async_writefile,
  79. locals_to_params,
  80. make_dirs_for_file,
  81. parse_error,
  82. serialize_error,
  83. url_matches,
  84. )
  85. from playwright._impl._input import Keyboard, Mouse, Touchscreen
  86. from playwright._impl._js_handle import (
  87. JSHandle,
  88. Serializable,
  89. add_source_url_to_script,
  90. parse_result,
  91. serialize_argument,
  92. )
  93. from playwright._impl._network import (
  94. Request,
  95. Response,
  96. Route,
  97. WebSocketRoute,
  98. WebSocketRouteHandler,
  99. serialize_headers,
  100. )
  101. from playwright._impl._screencast import Screencast
  102. from playwright._impl._video import Video
  103. from playwright._impl._waiter import Waiter
  104. if TYPE_CHECKING: # pragma: no cover
  105. from playwright._impl._browser_context import BrowserContext
  106. from playwright._impl._fetch import APIRequestContext
  107. from playwright._impl._locator import FrameLocator, Locator
  108. from playwright._impl._network import WebSocket
  109. class LocatorHandler:
  110. locator: "Locator"
  111. handler: Union[Callable[["Locator"], Any], Callable[..., Any]]
  112. times: Union[int, None]
  113. def __init__(
  114. self, locator: "Locator", handler: Callable[..., Any], times: Union[int, None]
  115. ) -> None:
  116. self.locator = locator
  117. self._handler = handler
  118. self.times = times
  119. def __call__(self) -> Any:
  120. arg_count = len(inspect.signature(self._handler).parameters)
  121. if arg_count == 0:
  122. return self._handler()
  123. return self._handler(self.locator)
  124. class Page(ChannelOwner):
  125. Events = SimpleNamespace(
  126. Close="close",
  127. Crash="crash",
  128. Console="console",
  129. Dialog="dialog",
  130. Download="download",
  131. FileChooser="filechooser",
  132. DOMContentLoaded="domcontentloaded",
  133. PageError="pageerror",
  134. Request="request",
  135. Response="response",
  136. RequestFailed="requestfailed",
  137. RequestFinished="requestfinished",
  138. FrameAttached="frameattached",
  139. FrameDetached="framedetached",
  140. FrameNavigated="framenavigated",
  141. Load="load",
  142. Popup="popup",
  143. WebSocket="websocket",
  144. Worker="worker",
  145. )
  146. keyboard: Keyboard
  147. mouse: Mouse
  148. touchscreen: Touchscreen
  149. def __init__(
  150. self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
  151. ) -> None:
  152. super().__init__(parent, type, guid, initializer)
  153. self._browser_context = cast("BrowserContext", parent)
  154. self.keyboard = Keyboard(self._channel)
  155. self.mouse = Mouse(self._channel)
  156. self.touchscreen = Touchscreen(self._channel)
  157. self._main_frame: Frame = from_channel(initializer["mainFrame"])
  158. self._main_frame._page = self
  159. self._frames = [self._main_frame]
  160. self._viewport_size: Optional[ViewportSize] = initializer.get("viewportSize")
  161. self._is_closed = False
  162. self._workers: List["Worker"] = []
  163. self._bindings: Dict[str, Any] = {}
  164. self._routes: List[RouteHandler] = []
  165. self._web_socket_routes: List[WebSocketRouteHandler] = []
  166. self._owned_context: Optional["BrowserContext"] = None
  167. self._timeout_settings: TimeoutSettings = TimeoutSettings(
  168. self._browser_context._timeout_settings
  169. )
  170. self._video: Video = Video(
  171. self,
  172. cast(Optional[Artifact], from_nullable_channel(initializer.get("video"))),
  173. )
  174. self._screencast: Screencast = Screencast(self)
  175. self._opener = cast("Page", from_nullable_channel(initializer.get("opener")))
  176. self._close_reason: Optional[str] = None
  177. self._close_was_called = False
  178. self._har_routers: List[HarRouter] = []
  179. self._locator_handlers: Dict[str, LocatorHandler] = {}
  180. self._channel.on(
  181. "bindingCall",
  182. lambda params: self._on_binding(from_channel(params["binding"])),
  183. )
  184. self._channel.on("close", lambda _: self._on_close())
  185. self._channel.on("crash", lambda _: self._on_crash())
  186. self._channel.on("download", lambda params: self._on_download(params))
  187. self._channel.on(
  188. "fileChooser",
  189. lambda params: self.emit(
  190. Page.Events.FileChooser,
  191. FileChooser(
  192. self, from_channel(params["element"]), params["isMultiple"]
  193. ),
  194. ),
  195. )
  196. self._channel.on(
  197. "frameAttached",
  198. lambda params: self._on_frame_attached(from_channel(params["frame"])),
  199. )
  200. self._channel.on(
  201. "frameDetached",
  202. lambda params: self._on_frame_detached(from_channel(params["frame"])),
  203. )
  204. self._channel.on(
  205. "locatorHandlerTriggered",
  206. lambda params: self._loop.create_task(
  207. self._on_locator_handler_triggered(params["uid"])
  208. ),
  209. )
  210. self._channel.on(
  211. "route",
  212. lambda params: self._loop.create_task(
  213. self._on_route(from_channel(params["route"]))
  214. ),
  215. )
  216. self._channel.on(
  217. "webSocketRoute",
  218. lambda params: self._loop.create_task(
  219. self._on_web_socket_route(from_channel(params["webSocketRoute"]))
  220. ),
  221. )
  222. self._channel.on("viewportSizeChanged", self._on_viewport_size_changed)
  223. self._channel.on(
  224. "webSocket",
  225. lambda params: self.emit(
  226. Page.Events.WebSocket, from_channel(params["webSocket"])
  227. ),
  228. )
  229. self._channel.on(
  230. "worker", lambda params: self._on_worker(from_channel(params["worker"]))
  231. )
  232. self._closed_or_crashed_future: asyncio.Future = asyncio.Future()
  233. self.on(
  234. Page.Events.Close,
  235. lambda _: (
  236. self._closed_or_crashed_future.set_result(
  237. self._close_error_with_reason()
  238. )
  239. if not self._closed_or_crashed_future.done()
  240. else None
  241. ),
  242. )
  243. self.on(
  244. Page.Events.Crash,
  245. lambda _: (
  246. self._closed_or_crashed_future.set_result(TargetClosedError())
  247. if not self._closed_or_crashed_future.done()
  248. else None
  249. ),
  250. )
  251. self._set_event_to_subscription_mapping(
  252. {
  253. Page.Events.Console: "console",
  254. Page.Events.Dialog: "dialog",
  255. Page.Events.Request: "request",
  256. Page.Events.Response: "response",
  257. Page.Events.RequestFinished: "requestFinished",
  258. Page.Events.RequestFailed: "requestFailed",
  259. Page.Events.FileChooser: "fileChooser",
  260. }
  261. )
  262. def __repr__(self) -> str:
  263. return f"<Page url={self.url!r}>"
  264. def _on_frame_attached(self, frame: Frame) -> None:
  265. frame._page = self
  266. self._frames.append(frame)
  267. self.emit(Page.Events.FrameAttached, frame)
  268. self._browser_context.emit("frameattached", frame)
  269. def _on_frame_detached(self, frame: Frame) -> None:
  270. self._frames.remove(frame)
  271. frame._detached = True
  272. self.emit(Page.Events.FrameDetached, frame)
  273. self._browser_context.emit("framedetached", frame)
  274. async def _on_route(self, route: Route) -> None:
  275. route._context = self.context
  276. route_handlers = self._routes.copy()
  277. for route_handler in route_handlers:
  278. # If the page was closed we stall all requests right away.
  279. if self._close_was_called or self.context._closing_or_closed:
  280. return
  281. if not route_handler.matches(route.request.url):
  282. continue
  283. if route_handler not in self._routes:
  284. continue
  285. if route_handler.will_expire:
  286. self._routes.remove(route_handler)
  287. try:
  288. handled = await route_handler.handle(route)
  289. finally:
  290. if len(self._routes) == 0:
  291. async def _update_interceptor_patterns_ignore_exceptions() -> None:
  292. try:
  293. await self._update_interception_patterns()
  294. except Error:
  295. pass
  296. asyncio.create_task(
  297. self._connection.wrap_api_call(
  298. _update_interceptor_patterns_ignore_exceptions, True
  299. )
  300. )
  301. if handled:
  302. return
  303. await self._browser_context._on_route(route)
  304. async def _on_web_socket_route(self, web_socket_route: WebSocketRoute) -> None:
  305. route_handler = next(
  306. (
  307. route_handler
  308. for route_handler in self._web_socket_routes
  309. if route_handler.matches(web_socket_route.url)
  310. ),
  311. None,
  312. )
  313. if route_handler:
  314. await route_handler.handle(web_socket_route)
  315. else:
  316. await self._browser_context._on_web_socket_route(web_socket_route)
  317. def _on_binding(self, binding_call: "BindingCall") -> None:
  318. func = self._bindings.get(binding_call._initializer["name"])
  319. if func:
  320. asyncio.create_task(binding_call.call(func))
  321. self._browser_context._on_binding(binding_call)
  322. def _on_worker(self, worker: "Worker") -> None:
  323. self._workers.append(worker)
  324. worker._page = self
  325. self.emit(Page.Events.Worker, worker)
  326. def _on_close(self) -> None:
  327. self._is_closed = True
  328. if self in self._browser_context._pages:
  329. self._browser_context._pages.remove(self)
  330. self._dispose_har_routers()
  331. self.emit(Page.Events.Close, self)
  332. self._browser_context.emit("pageclose", self)
  333. def _on_crash(self) -> None:
  334. self.emit(Page.Events.Crash, self)
  335. def _on_download(self, params: Any) -> None:
  336. url = params["url"]
  337. suggested_filename = params["suggestedFilename"]
  338. artifact = cast(Artifact, from_channel(params["artifact"]))
  339. download = Download(self, url, suggested_filename, artifact)
  340. self.emit(Page.Events.Download, download)
  341. self._browser_context.emit("download", download)
  342. def _on_viewport_size_changed(self, params: Any) -> None:
  343. self._viewport_size = params["viewportSize"]
  344. @property
  345. def context(self) -> "BrowserContext":
  346. return self._browser_context
  347. @property
  348. def clock(self) -> Clock:
  349. return self._browser_context.clock
  350. async def opener(self) -> Optional["Page"]:
  351. if self._opener and self._opener.is_closed():
  352. return None
  353. return self._opener
  354. @property
  355. def main_frame(self) -> Frame:
  356. return self._main_frame
  357. def frame(self, name: str = None, url: URLMatch = None) -> Optional[Frame]:
  358. for frame in self._frames:
  359. if name and frame.name == name:
  360. return frame
  361. if url and url_matches(self._browser_context._base_url, frame.url, url):
  362. return frame
  363. return None
  364. @property
  365. def frames(self) -> List[Frame]:
  366. return self._frames.copy()
  367. def set_default_navigation_timeout(self, timeout: float) -> None:
  368. self._timeout_settings.set_default_navigation_timeout(timeout)
  369. def set_default_timeout(self, timeout: float) -> None:
  370. self._timeout_settings.set_default_timeout(timeout)
  371. async def query_selector(
  372. self,
  373. selector: str,
  374. strict: bool = None,
  375. ) -> Optional[ElementHandle]:
  376. return await self._main_frame.query_selector(selector, strict)
  377. async def query_selector_all(self, selector: str) -> List[ElementHandle]:
  378. return await self._main_frame.query_selector_all(selector)
  379. async def wait_for_selector(
  380. self,
  381. selector: str,
  382. timeout: float = None,
  383. state: Literal["attached", "detached", "hidden", "visible"] = None,
  384. strict: bool = None,
  385. ) -> Optional[ElementHandle]:
  386. return await self._main_frame.wait_for_selector(**locals_to_params(locals()))
  387. async def is_checked(
  388. self, selector: str, strict: bool = None, timeout: float = None
  389. ) -> bool:
  390. return await self._main_frame.is_checked(**locals_to_params(locals()))
  391. async def is_disabled(
  392. self, selector: str, strict: bool = None, timeout: float = None
  393. ) -> bool:
  394. return await self._main_frame.is_disabled(**locals_to_params(locals()))
  395. async def is_editable(
  396. self, selector: str, strict: bool = None, timeout: float = None
  397. ) -> bool:
  398. return await self._main_frame.is_editable(**locals_to_params(locals()))
  399. async def is_enabled(
  400. self, selector: str, strict: bool = None, timeout: float = None
  401. ) -> bool:
  402. return await self._main_frame.is_enabled(**locals_to_params(locals()))
  403. async def is_hidden(
  404. self, selector: str, strict: bool = None, timeout: float = None
  405. ) -> bool:
  406. # timeout is deprecated and does nothing
  407. return await self._main_frame.is_hidden(selector=selector, strict=strict)
  408. async def is_visible(
  409. self, selector: str, strict: bool = None, timeout: float = None
  410. ) -> bool:
  411. # timeout is deprecated and does nothing
  412. return await self._main_frame.is_visible(selector=selector, strict=strict)
  413. async def dispatch_event(
  414. self,
  415. selector: str,
  416. type: str,
  417. eventInit: Dict = None,
  418. timeout: float = None,
  419. strict: bool = None,
  420. ) -> None:
  421. return await self._main_frame.dispatch_event(**locals_to_params(locals()))
  422. async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
  423. return await self._main_frame.evaluate(expression, arg)
  424. async def evaluate_handle(
  425. self, expression: str, arg: Serializable = None
  426. ) -> JSHandle:
  427. return await self._main_frame.evaluate_handle(expression, arg)
  428. async def eval_on_selector(
  429. self,
  430. selector: str,
  431. expression: str,
  432. arg: Serializable = None,
  433. strict: bool = None,
  434. ) -> Any:
  435. return await self._main_frame.eval_on_selector(
  436. selector, expression, arg, strict
  437. )
  438. async def eval_on_selector_all(
  439. self,
  440. selector: str,
  441. expression: str,
  442. arg: Serializable = None,
  443. ) -> Any:
  444. return await self._main_frame.eval_on_selector_all(selector, expression, arg)
  445. async def add_script_tag(
  446. self,
  447. url: str = None,
  448. path: Union[str, Path] = None,
  449. content: str = None,
  450. type: str = None,
  451. ) -> ElementHandle:
  452. return await self._main_frame.add_script_tag(**locals_to_params(locals()))
  453. async def add_style_tag(
  454. self, url: str = None, path: Union[str, Path] = None, content: str = None
  455. ) -> ElementHandle:
  456. return await self._main_frame.add_style_tag(**locals_to_params(locals()))
  457. async def expose_function(self, name: str, callback: Callable) -> Disposable:
  458. return await self.expose_binding(name, lambda source, *args: callback(*args))
  459. async def expose_binding(self, name: str, callback: Callable) -> Disposable:
  460. if name in self._bindings:
  461. raise Error(f'Function "{name}" has been already registered')
  462. if name in self._browser_context._bindings:
  463. raise Error(
  464. f'Function "{name}" has been already registered in the browser context'
  465. )
  466. self._bindings[name] = callback
  467. return from_channel(
  468. await self._channel.send(
  469. "exposeBinding",
  470. None,
  471. dict(name=name),
  472. )
  473. )
  474. async def set_extra_http_headers(self, headers: Dict[str, str]) -> None:
  475. await self._channel.send(
  476. "setExtraHTTPHeaders",
  477. None,
  478. dict(headers=serialize_headers(headers)),
  479. )
  480. @property
  481. def url(self) -> str:
  482. return self._main_frame.url
  483. async def content(self) -> str:
  484. return await self._main_frame.content()
  485. async def set_content(
  486. self,
  487. html: str,
  488. timeout: float = None,
  489. waitUntil: DocumentLoadState = None,
  490. ) -> None:
  491. return await self._main_frame.set_content(**locals_to_params(locals()))
  492. async def goto(
  493. self,
  494. url: str,
  495. timeout: float = None,
  496. waitUntil: DocumentLoadState = None,
  497. referer: str = None,
  498. ) -> Optional[Response]:
  499. return await self._main_frame.goto(**locals_to_params(locals()))
  500. async def reload(
  501. self,
  502. timeout: float = None,
  503. waitUntil: DocumentLoadState = None,
  504. ) -> Optional[Response]:
  505. return from_nullable_channel(
  506. await self._channel.send(
  507. "reload",
  508. self._timeout_settings.navigation_timeout,
  509. locals_to_params(locals()),
  510. )
  511. )
  512. async def wait_for_load_state(
  513. self,
  514. state: Literal["domcontentloaded", "load", "networkidle"] = None,
  515. timeout: float = None,
  516. ) -> None:
  517. return await self._main_frame.wait_for_load_state(**locals_to_params(locals()))
  518. async def wait_for_url(
  519. self,
  520. url: URLMatch,
  521. waitUntil: DocumentLoadState = None,
  522. timeout: float = None,
  523. ) -> None:
  524. return await self._main_frame.wait_for_url(**locals_to_params(locals()))
  525. async def wait_for_event(
  526. self, event: str, predicate: Callable = None, timeout: float = None
  527. ) -> Any:
  528. async with self.expect_event(event, predicate, timeout) as event_info:
  529. pass
  530. return await event_info
  531. async def go_back(
  532. self,
  533. timeout: float = None,
  534. waitUntil: DocumentLoadState = None,
  535. ) -> Optional[Response]:
  536. return from_nullable_channel(
  537. await self._channel.send(
  538. "goBack",
  539. self._timeout_settings.navigation_timeout,
  540. locals_to_params(locals()),
  541. )
  542. )
  543. async def go_forward(
  544. self,
  545. timeout: float = None,
  546. waitUntil: DocumentLoadState = None,
  547. ) -> Optional[Response]:
  548. return from_nullable_channel(
  549. await self._channel.send(
  550. "goForward",
  551. self._timeout_settings.navigation_timeout,
  552. locals_to_params(locals()),
  553. )
  554. )
  555. async def request_gc(self) -> None:
  556. await self._channel.send("requestGC", None)
  557. async def emulate_media(
  558. self,
  559. media: Literal["null", "print", "screen"] = None,
  560. colorScheme: ColorScheme = None,
  561. reducedMotion: ReducedMotion = None,
  562. forcedColors: ForcedColors = None,
  563. contrast: Contrast = None,
  564. ) -> None:
  565. params = locals_to_params(locals())
  566. if "media" in params:
  567. params["media"] = "no-override" if params["media"] == "null" else media
  568. if "colorScheme" in params:
  569. params["colorScheme"] = (
  570. "no-override" if params["colorScheme"] == "null" else colorScheme
  571. )
  572. if "reducedMotion" in params:
  573. params["reducedMotion"] = (
  574. "no-override" if params["reducedMotion"] == "null" else reducedMotion
  575. )
  576. if "forcedColors" in params:
  577. params["forcedColors"] = (
  578. "no-override" if params["forcedColors"] == "null" else forcedColors
  579. )
  580. if "contrast" in params:
  581. params["contrast"] = (
  582. "no-override" if params["contrast"] == "null" else contrast
  583. )
  584. await self._channel.send("emulateMedia", None, params)
  585. async def set_viewport_size(self, viewportSize: ViewportSize) -> None:
  586. self._viewport_size = viewportSize
  587. await self._channel.send(
  588. "setViewportSize",
  589. None,
  590. locals_to_params(locals()),
  591. )
  592. @property
  593. def viewport_size(self) -> Optional[ViewportSize]:
  594. return self._viewport_size
  595. async def bring_to_front(self) -> None:
  596. await self._channel.send("bringToFront", None)
  597. async def hide_highlight(self) -> None:
  598. await self._channel.send("hideHighlight", None)
  599. async def add_init_script(
  600. self, script: str = None, path: Union[str, Path] = None
  601. ) -> Disposable:
  602. if path:
  603. script = add_source_url_to_script(
  604. (await async_readfile(path)).decode(), path
  605. )
  606. if not isinstance(script, str):
  607. raise Error("Either path or script parameter must be specified")
  608. return from_channel(
  609. await self._channel.send("addInitScript", None, dict(source=script))
  610. )
  611. async def route(
  612. self, url: URLMatch, handler: RouteHandlerCallback, times: int = None
  613. ) -> DisposableStub:
  614. self._routes.insert(
  615. 0,
  616. RouteHandler(
  617. self._browser_context._base_url,
  618. url,
  619. handler,
  620. True if self._dispatcher_fiber else False,
  621. times,
  622. ),
  623. )
  624. await self._update_interception_patterns()
  625. return DisposableStub(lambda: self.unroute(url, handler), self)
  626. async def unroute(
  627. self, url: URLMatch, handler: Optional[RouteHandlerCallback] = None
  628. ) -> None:
  629. removed = []
  630. remaining = []
  631. for route in self._routes:
  632. if route.url != url or (handler and route.handler != handler):
  633. remaining.append(route)
  634. else:
  635. removed.append(route)
  636. await self._unroute_internal(removed, remaining, "default")
  637. async def _unroute_internal(
  638. self,
  639. removed: List[RouteHandler],
  640. remaining: List[RouteHandler],
  641. behavior: Literal["default", "ignoreErrors", "wait"] = None,
  642. ) -> None:
  643. self._routes = remaining
  644. if behavior is not None and behavior != "default":
  645. await asyncio.gather(
  646. *map(
  647. lambda route: route.stop(behavior), # type: ignore
  648. removed,
  649. )
  650. )
  651. await self._update_interception_patterns()
  652. async def route_web_socket(
  653. self, url: URLMatch, handler: WebSocketRouteHandlerCallback
  654. ) -> None:
  655. self._web_socket_routes.insert(
  656. 0,
  657. WebSocketRouteHandler(self._browser_context._base_url, url, handler),
  658. )
  659. await self._update_web_socket_interception_patterns()
  660. def _dispose_har_routers(self) -> None:
  661. for router in self._har_routers:
  662. router.dispose()
  663. self._har_routers = []
  664. async def unroute_all(
  665. self, behavior: Literal["default", "ignoreErrors", "wait"] = None
  666. ) -> None:
  667. await self._unroute_internal(self._routes, [], behavior)
  668. self._dispose_har_routers()
  669. async def route_from_har(
  670. self,
  671. har: Union[Path, str],
  672. url: Union[Pattern[str], str] = None,
  673. notFound: RouteFromHarNotFoundPolicy = None,
  674. update: bool = None,
  675. updateContent: Literal["attach", "embed"] = None,
  676. updateMode: HarMode = None,
  677. ) -> None:
  678. if update:
  679. await self._browser_context._tracing._record_into_har(
  680. har=har,
  681. page=self,
  682. url=url,
  683. update_content=updateContent,
  684. update_mode=updateMode,
  685. )
  686. return
  687. router = await HarRouter.create(
  688. local_utils=self._connection.local_utils,
  689. file=str(har),
  690. not_found_action=notFound or "abort",
  691. url_matcher=url,
  692. )
  693. self._har_routers.append(router)
  694. await router.add_page_route(self)
  695. async def _update_interception_patterns(self) -> None:
  696. patterns = RouteHandler.prepare_interception_patterns(self._routes)
  697. await self._channel.send(
  698. "setNetworkInterceptionPatterns",
  699. None,
  700. {"patterns": patterns},
  701. )
  702. async def _update_web_socket_interception_patterns(self) -> None:
  703. patterns = WebSocketRouteHandler.prepare_interception_patterns(
  704. self._web_socket_routes
  705. )
  706. await self._channel.send(
  707. "setWebSocketInterceptionPatterns",
  708. None,
  709. {"patterns": patterns},
  710. )
  711. async def screenshot(
  712. self,
  713. timeout: float = None,
  714. type: Literal["jpeg", "png"] = None,
  715. path: Union[str, Path] = None,
  716. quality: int = None,
  717. omitBackground: bool = None,
  718. fullPage: bool = None,
  719. clip: FloatRect = None,
  720. animations: Literal["allow", "disabled"] = None,
  721. caret: Literal["hide", "initial"] = None,
  722. scale: Literal["css", "device"] = None,
  723. mask: Sequence["Locator"] = None,
  724. maskColor: str = None,
  725. style: str = None,
  726. ) -> bytes:
  727. params = locals_to_params(locals())
  728. if "path" in params:
  729. if "type" not in params:
  730. params["type"] = determine_screenshot_type(params["path"])
  731. del params["path"]
  732. if "mask" in params:
  733. params["mask"] = list(
  734. map(
  735. lambda locator: (
  736. {
  737. "frame": locator._frame._channel,
  738. "selector": locator._selector,
  739. }
  740. ),
  741. params["mask"],
  742. )
  743. )
  744. encoded_binary = await self._channel.send(
  745. "screenshot", self._timeout_settings.timeout, params
  746. )
  747. decoded_binary = base64.b64decode(encoded_binary)
  748. if path:
  749. make_dirs_for_file(path)
  750. await async_writefile(path, decoded_binary)
  751. return decoded_binary
  752. async def title(self) -> str:
  753. return await self._main_frame.title()
  754. async def aria_snapshot(
  755. self,
  756. timeout: float = None,
  757. depth: int = None,
  758. mode: Literal["ai", "default"] = None,
  759. boxes: bool = None,
  760. ) -> str:
  761. return await self._main_frame._channel.send(
  762. "ariaSnapshot",
  763. self._main_frame._timeout,
  764. locals_to_params(locals()),
  765. )
  766. async def close(self, runBeforeUnload: bool = None, reason: str = None) -> None:
  767. self._close_reason = reason
  768. self._close_was_called = True
  769. try:
  770. await self._channel.send("close", None, locals_to_params(locals()))
  771. if self._owned_context:
  772. await self._owned_context.close()
  773. except Exception as e:
  774. if not is_target_closed_error(e) and not runBeforeUnload:
  775. raise e
  776. def is_closed(self) -> bool:
  777. return self._is_closed
  778. async def click(
  779. self,
  780. selector: str,
  781. modifiers: Sequence[KeyboardModifier] = None,
  782. position: Position = None,
  783. delay: float = None,
  784. button: MouseButton = None,
  785. clickCount: int = None,
  786. timeout: float = None,
  787. force: bool = None,
  788. noWaitAfter: bool = None,
  789. trial: bool = None,
  790. strict: bool = None,
  791. ) -> None:
  792. return await self._main_frame._click(**locals_to_params(locals()))
  793. async def dblclick(
  794. self,
  795. selector: str,
  796. modifiers: Sequence[KeyboardModifier] = None,
  797. position: Position = None,
  798. delay: float = None,
  799. button: MouseButton = None,
  800. timeout: float = None,
  801. force: bool = None,
  802. noWaitAfter: bool = None,
  803. strict: bool = None,
  804. trial: bool = None,
  805. ) -> None:
  806. return await self._main_frame.dblclick(**locals_to_params(locals()))
  807. async def tap(
  808. self,
  809. selector: str,
  810. modifiers: Sequence[KeyboardModifier] = None,
  811. position: Position = None,
  812. timeout: float = None,
  813. force: bool = None,
  814. noWaitAfter: bool = None,
  815. strict: bool = None,
  816. trial: bool = None,
  817. ) -> None:
  818. return await self._main_frame.tap(**locals_to_params(locals()))
  819. async def fill(
  820. self,
  821. selector: str,
  822. value: str,
  823. timeout: float = None,
  824. noWaitAfter: bool = None,
  825. strict: bool = None,
  826. force: bool = None,
  827. ) -> None:
  828. return await self._main_frame.fill(**locals_to_params(locals()))
  829. def locator(
  830. self,
  831. selector: str,
  832. hasText: Union[str, Pattern[str]] = None,
  833. hasNotText: Union[str, Pattern[str]] = None,
  834. has: "Locator" = None,
  835. hasNot: "Locator" = None,
  836. ) -> "Locator":
  837. return self._main_frame.locator(
  838. selector,
  839. hasText=hasText,
  840. hasNotText=hasNotText,
  841. has=has,
  842. hasNot=hasNot,
  843. )
  844. def get_by_alt_text(
  845. self, text: Union[str, Pattern[str]], exact: bool = None
  846. ) -> "Locator":
  847. return self._main_frame.get_by_alt_text(text, exact=exact)
  848. def get_by_label(
  849. self, text: Union[str, Pattern[str]], exact: bool = None
  850. ) -> "Locator":
  851. return self._main_frame.get_by_label(text, exact=exact)
  852. def get_by_placeholder(
  853. self, text: Union[str, Pattern[str]], exact: bool = None
  854. ) -> "Locator":
  855. return self._main_frame.get_by_placeholder(text, exact=exact)
  856. def get_by_role(
  857. self,
  858. role: AriaRole,
  859. checked: bool = None,
  860. disabled: bool = None,
  861. expanded: bool = None,
  862. includeHidden: bool = None,
  863. level: int = None,
  864. name: Union[str, Pattern[str]] = None,
  865. pressed: bool = None,
  866. selected: bool = None,
  867. exact: bool = None,
  868. description: Union[str, Pattern[str]] = None,
  869. ) -> "Locator":
  870. return self._main_frame.get_by_role(
  871. role,
  872. checked=checked,
  873. disabled=disabled,
  874. expanded=expanded,
  875. includeHidden=includeHidden,
  876. level=level,
  877. name=name,
  878. pressed=pressed,
  879. selected=selected,
  880. exact=exact,
  881. description=description,
  882. )
  883. def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
  884. return self._main_frame.get_by_test_id(testId)
  885. def get_by_text(
  886. self, text: Union[str, Pattern[str]], exact: bool = None
  887. ) -> "Locator":
  888. return self._main_frame.get_by_text(text, exact=exact)
  889. def get_by_title(
  890. self, text: Union[str, Pattern[str]], exact: bool = None
  891. ) -> "Locator":
  892. return self._main_frame.get_by_title(text, exact=exact)
  893. def frame_locator(self, selector: str) -> "FrameLocator":
  894. return self.main_frame.frame_locator(selector)
  895. async def focus(
  896. self, selector: str, strict: bool = None, timeout: float = None
  897. ) -> None:
  898. return await self._main_frame.focus(**locals_to_params(locals()))
  899. async def text_content(
  900. self, selector: str, strict: bool = None, timeout: float = None
  901. ) -> Optional[str]:
  902. return await self._main_frame.text_content(**locals_to_params(locals()))
  903. async def inner_text(
  904. self, selector: str, strict: bool = None, timeout: float = None
  905. ) -> str:
  906. return await self._main_frame.inner_text(**locals_to_params(locals()))
  907. async def inner_html(
  908. self, selector: str, strict: bool = None, timeout: float = None
  909. ) -> str:
  910. return await self._main_frame.inner_html(**locals_to_params(locals()))
  911. async def get_attribute(
  912. self, selector: str, name: str, strict: bool = None, timeout: float = None
  913. ) -> Optional[str]:
  914. return await self._main_frame.get_attribute(**locals_to_params(locals()))
  915. async def hover(
  916. self,
  917. selector: str,
  918. modifiers: Sequence[KeyboardModifier] = None,
  919. position: Position = None,
  920. timeout: float = None,
  921. noWaitAfter: bool = None,
  922. force: bool = None,
  923. strict: bool = None,
  924. trial: bool = None,
  925. ) -> None:
  926. return await self._main_frame.hover(**locals_to_params(locals()))
  927. async def drag_and_drop(
  928. self,
  929. source: str,
  930. target: str,
  931. sourcePosition: Position = None,
  932. targetPosition: Position = None,
  933. force: bool = None,
  934. noWaitAfter: bool = None,
  935. timeout: float = None,
  936. strict: bool = None,
  937. trial: bool = None,
  938. steps: int = None,
  939. ) -> None:
  940. return await self._main_frame.drag_and_drop(**locals_to_params(locals()))
  941. async def select_option(
  942. self,
  943. selector: str,
  944. value: Union[str, Sequence[str]] = None,
  945. index: Union[int, Sequence[int]] = None,
  946. label: Union[str, Sequence[str]] = None,
  947. element: Union["ElementHandle", Sequence["ElementHandle"]] = None,
  948. timeout: float = None,
  949. noWaitAfter: bool = None,
  950. force: bool = None,
  951. strict: bool = None,
  952. ) -> List[str]:
  953. params = locals_to_params(locals())
  954. return await self._main_frame.select_option(**params)
  955. async def input_value(
  956. self, selector: str, strict: bool = None, timeout: float = None
  957. ) -> str:
  958. params = locals_to_params(locals())
  959. return await self._main_frame.input_value(**params)
  960. async def set_input_files(
  961. self,
  962. selector: str,
  963. files: Union[
  964. str, Path, FilePayload, Sequence[Union[str, Path]], Sequence[FilePayload]
  965. ],
  966. timeout: float = None,
  967. strict: bool = None,
  968. noWaitAfter: bool = None,
  969. ) -> None:
  970. return await self._main_frame.set_input_files(**locals_to_params(locals()))
  971. async def type(
  972. self,
  973. selector: str,
  974. text: str,
  975. delay: float = None,
  976. timeout: float = None,
  977. noWaitAfter: bool = None,
  978. strict: bool = None,
  979. ) -> None:
  980. return await self._main_frame.type(**locals_to_params(locals()))
  981. async def press(
  982. self,
  983. selector: str,
  984. key: str,
  985. delay: float = None,
  986. timeout: float = None,
  987. noWaitAfter: bool = None,
  988. strict: bool = None,
  989. ) -> None:
  990. return await self._main_frame.press(**locals_to_params(locals()))
  991. async def check(
  992. self,
  993. selector: str,
  994. position: Position = None,
  995. timeout: float = None,
  996. force: bool = None,
  997. noWaitAfter: bool = None,
  998. strict: bool = None,
  999. trial: bool = None,
  1000. ) -> None:
  1001. return await self._main_frame.check(**locals_to_params(locals()))
  1002. async def uncheck(
  1003. self,
  1004. selector: str,
  1005. position: Position = None,
  1006. timeout: float = None,
  1007. force: bool = None,
  1008. noWaitAfter: bool = None,
  1009. strict: bool = None,
  1010. trial: bool = None,
  1011. ) -> None:
  1012. return await self._main_frame.uncheck(**locals_to_params(locals()))
  1013. async def wait_for_timeout(self, timeout: float) -> None:
  1014. await self._main_frame.wait_for_timeout(timeout)
  1015. async def wait_for_function(
  1016. self,
  1017. expression: str,
  1018. arg: Serializable = None,
  1019. timeout: float = None,
  1020. polling: Union[float, Literal["raf"]] = None,
  1021. ) -> JSHandle:
  1022. return await self._main_frame.wait_for_function(**locals_to_params(locals()))
  1023. @property
  1024. def workers(self) -> List["Worker"]:
  1025. return self._workers.copy()
  1026. @property
  1027. def request(self) -> "APIRequestContext":
  1028. return self.context.request
  1029. async def pause(self) -> None:
  1030. default_navigation_timeout = (
  1031. self._browser_context._timeout_settings.default_navigation_timeout()
  1032. )
  1033. default_timeout = self._browser_context._timeout_settings.default_timeout()
  1034. self._browser_context.set_default_navigation_timeout(0)
  1035. self._browser_context.set_default_timeout(0)
  1036. try:
  1037. await asyncio.wait(
  1038. [
  1039. asyncio.create_task(
  1040. self._browser_context._channel.send("pause", None)
  1041. ),
  1042. self._closed_or_crashed_future,
  1043. ],
  1044. return_when=asyncio.FIRST_COMPLETED,
  1045. )
  1046. finally:
  1047. self._browser_context._set_default_navigation_timeout_impl(
  1048. default_navigation_timeout
  1049. )
  1050. self._browser_context._set_default_timeout_impl(default_timeout)
  1051. async def pdf(
  1052. self,
  1053. scale: float = None,
  1054. displayHeaderFooter: bool = None,
  1055. headerTemplate: str = None,
  1056. footerTemplate: str = None,
  1057. printBackground: bool = None,
  1058. landscape: bool = None,
  1059. pageRanges: str = None,
  1060. format: str = None,
  1061. width: Union[str, float] = None,
  1062. height: Union[str, float] = None,
  1063. preferCSSPageSize: bool = None,
  1064. margin: PdfMargins = None,
  1065. path: Union[str, Path] = None,
  1066. outline: bool = None,
  1067. tagged: bool = None,
  1068. ) -> bytes:
  1069. params = locals_to_params(locals())
  1070. if "path" in params:
  1071. del params["path"]
  1072. encoded_binary = await self._channel.send("pdf", None, params)
  1073. decoded_binary = base64.b64decode(encoded_binary)
  1074. if path:
  1075. make_dirs_for_file(path)
  1076. await async_writefile(path, decoded_binary)
  1077. return decoded_binary
  1078. @property
  1079. def video(self) -> Optional[Video]:
  1080. # Video is only exposed when the page actually produced a recording artifact.
  1081. # The initializer carries the artifact; if absent, no video was recorded.
  1082. if not self._video._artifact:
  1083. return None
  1084. return self._video
  1085. @property
  1086. def screencast(self) -> Screencast:
  1087. return self._screencast
  1088. def _close_error_with_reason(self) -> TargetClosedError:
  1089. return TargetClosedError(
  1090. self._close_reason or self._browser_context._effective_close_reason()
  1091. )
  1092. def expect_event(
  1093. self,
  1094. event: str,
  1095. predicate: Callable = None,
  1096. timeout: float = None,
  1097. ) -> EventContextManagerImpl:
  1098. return self._expect_event(
  1099. event, predicate, timeout, f'waiting for event "{event}"'
  1100. )
  1101. def _expect_event(
  1102. self,
  1103. event: str,
  1104. predicate: Callable = None,
  1105. timeout: float = None,
  1106. log_line: str = None,
  1107. ) -> EventContextManagerImpl:
  1108. if timeout is None:
  1109. timeout = self._timeout_settings.timeout()
  1110. waiter = Waiter(self, f"page.expect_event({event})")
  1111. waiter.reject_on_timeout(
  1112. timeout, f'Timeout {timeout}ms exceeded while waiting for event "{event}"'
  1113. )
  1114. if log_line:
  1115. waiter.log(log_line)
  1116. if event != Page.Events.Crash:
  1117. waiter.reject_on_event(self, Page.Events.Crash, Error("Page crashed"))
  1118. if event != Page.Events.Close:
  1119. waiter.reject_on_event(
  1120. self, Page.Events.Close, lambda: self._close_error_with_reason()
  1121. )
  1122. waiter.wait_for_event(self, event, predicate)
  1123. return EventContextManagerImpl(waiter.result())
  1124. def expect_console_message(
  1125. self,
  1126. predicate: Callable[[ConsoleMessage], bool] = None,
  1127. timeout: float = None,
  1128. ) -> EventContextManagerImpl[ConsoleMessage]:
  1129. return self.expect_event(Page.Events.Console, predicate, timeout)
  1130. def expect_download(
  1131. self,
  1132. predicate: Callable[[Download], bool] = None,
  1133. timeout: float = None,
  1134. ) -> EventContextManagerImpl[Download]:
  1135. return self.expect_event(Page.Events.Download, predicate, timeout)
  1136. def expect_file_chooser(
  1137. self,
  1138. predicate: Callable[[FileChooser], bool] = None,
  1139. timeout: float = None,
  1140. ) -> EventContextManagerImpl[FileChooser]:
  1141. return self.expect_event(Page.Events.FileChooser, predicate, timeout)
  1142. def expect_navigation(
  1143. self,
  1144. url: URLMatch = None,
  1145. waitUntil: DocumentLoadState = None,
  1146. timeout: float = None,
  1147. ) -> EventContextManagerImpl[Response]:
  1148. return self.main_frame.expect_navigation(url, waitUntil, timeout)
  1149. def expect_popup(
  1150. self,
  1151. predicate: Callable[["Page"], bool] = None,
  1152. timeout: float = None,
  1153. ) -> EventContextManagerImpl["Page"]:
  1154. return self.expect_event(Page.Events.Popup, predicate, timeout)
  1155. def expect_request(
  1156. self,
  1157. urlOrPredicate: URLMatchRequest,
  1158. timeout: float = None,
  1159. ) -> EventContextManagerImpl[Request]:
  1160. def my_predicate(request: Request) -> Union[bool, Awaitable[bool]]:
  1161. if not callable(urlOrPredicate):
  1162. return url_matches(
  1163. self._browser_context._base_url,
  1164. request.url,
  1165. urlOrPredicate,
  1166. )
  1167. return urlOrPredicate(request)
  1168. trimmed_url = trim_url(urlOrPredicate)
  1169. log_line = f"waiting for request {trimmed_url}" if trimmed_url else None
  1170. return self._expect_event(
  1171. Page.Events.Request,
  1172. predicate=my_predicate,
  1173. timeout=timeout,
  1174. log_line=log_line,
  1175. )
  1176. def expect_request_finished(
  1177. self,
  1178. predicate: Callable[["Request"], bool] = None,
  1179. timeout: float = None,
  1180. ) -> EventContextManagerImpl[Request]:
  1181. return self.expect_event(
  1182. Page.Events.RequestFinished, predicate=predicate, timeout=timeout
  1183. )
  1184. def expect_response(
  1185. self,
  1186. urlOrPredicate: URLMatchResponse,
  1187. timeout: float = None,
  1188. ) -> EventContextManagerImpl[Response]:
  1189. def my_predicate(request: Response) -> Union[bool, Awaitable[bool]]:
  1190. if not callable(urlOrPredicate):
  1191. return url_matches(
  1192. self._browser_context._base_url,
  1193. request.url,
  1194. urlOrPredicate,
  1195. )
  1196. return urlOrPredicate(request)
  1197. trimmed_url = trim_url(urlOrPredicate)
  1198. log_line = f"waiting for response {trimmed_url}" if trimmed_url else None
  1199. return self._expect_event(
  1200. Page.Events.Response,
  1201. predicate=my_predicate,
  1202. timeout=timeout,
  1203. log_line=log_line,
  1204. )
  1205. def expect_websocket(
  1206. self,
  1207. predicate: Callable[["WebSocket"], bool] = None,
  1208. timeout: float = None,
  1209. ) -> EventContextManagerImpl["WebSocket"]:
  1210. return self.expect_event("websocket", predicate, timeout)
  1211. def expect_worker(
  1212. self,
  1213. predicate: Callable[["Worker"], bool] = None,
  1214. timeout: float = None,
  1215. ) -> EventContextManagerImpl["Worker"]:
  1216. return self.expect_event("worker", predicate, timeout)
  1217. async def set_checked(
  1218. self,
  1219. selector: str,
  1220. checked: bool,
  1221. position: Position = None,
  1222. timeout: float = None,
  1223. force: bool = None,
  1224. noWaitAfter: bool = None,
  1225. strict: bool = None,
  1226. trial: bool = None,
  1227. ) -> None:
  1228. if checked:
  1229. await self.check(
  1230. selector=selector,
  1231. position=position,
  1232. timeout=timeout,
  1233. force=force,
  1234. strict=strict,
  1235. trial=trial,
  1236. )
  1237. else:
  1238. await self.uncheck(
  1239. selector=selector,
  1240. position=position,
  1241. timeout=timeout,
  1242. force=force,
  1243. strict=strict,
  1244. trial=trial,
  1245. )
  1246. async def add_locator_handler(
  1247. self,
  1248. locator: "Locator",
  1249. handler: Union[Callable[["Locator"], Any], Callable[[], Any]],
  1250. noWaitAfter: bool = None,
  1251. times: int = None,
  1252. ) -> None:
  1253. if locator._frame != self._main_frame:
  1254. raise Error("Locator must belong to the main frame of this page")
  1255. if times == 0:
  1256. return
  1257. uid = await self._channel.send(
  1258. "registerLocatorHandler",
  1259. None,
  1260. {
  1261. "selector": locator._selector,
  1262. "noWaitAfter": noWaitAfter,
  1263. },
  1264. )
  1265. self._locator_handlers[uid] = LocatorHandler(
  1266. handler=handler, times=times, locator=locator
  1267. )
  1268. async def _on_locator_handler_triggered(self, uid: str) -> None:
  1269. remove = False
  1270. try:
  1271. handler = self._locator_handlers.get(uid)
  1272. if handler and handler.times != 0:
  1273. if handler.times is not None:
  1274. handler.times -= 1
  1275. if self._dispatcher_fiber:
  1276. handler_finished_future = self._loop.create_future()
  1277. def _handler() -> None:
  1278. try:
  1279. handler()
  1280. handler_finished_future.set_result(None)
  1281. except Exception as e:
  1282. handler_finished_future.set_exception(e)
  1283. g = LocatorHandlerGreenlet(_handler)
  1284. g.switch()
  1285. await handler_finished_future
  1286. else:
  1287. coro_or_future = handler()
  1288. if coro_or_future:
  1289. await coro_or_future
  1290. remove = handler.times == 0
  1291. finally:
  1292. if remove:
  1293. del self._locator_handlers[uid]
  1294. try:
  1295. await self._connection.wrap_api_call(
  1296. lambda: self._channel.send(
  1297. "resolveLocatorHandlerNoReply",
  1298. None,
  1299. {"uid": uid, "remove": remove},
  1300. ),
  1301. is_internal=True,
  1302. )
  1303. except Error:
  1304. pass
  1305. async def remove_locator_handler(self, locator: "Locator") -> None:
  1306. for uid, data in self._locator_handlers.copy().items():
  1307. if data.locator._equals(locator):
  1308. del self._locator_handlers[uid]
  1309. self._channel.send_no_reply(
  1310. "unregisterLocatorHandler",
  1311. None,
  1312. {"uid": uid},
  1313. )
  1314. async def requests(self) -> List[Request]:
  1315. request_objects = await self._channel.send("requests", None)
  1316. return [from_channel(r) for r in request_objects]
  1317. async def console_messages(
  1318. self, filter: Literal["all", "since-navigation"] = None
  1319. ) -> List[ConsoleMessage]:
  1320. message_dicts = await self._channel.send(
  1321. "consoleMessages", None, locals_to_params(locals())
  1322. )
  1323. return [
  1324. ConsoleMessage(
  1325. {**event, "page": self._channel}, self._loop, self._dispatcher_fiber
  1326. )
  1327. for event in message_dicts
  1328. ]
  1329. async def page_errors(
  1330. self, filter: Literal["all", "since-navigation"] = None
  1331. ) -> List[Error]:
  1332. error_objects = await self._channel.send(
  1333. "pageErrors", None, locals_to_params(locals())
  1334. )
  1335. return [parse_error(error["error"]) for error in error_objects]
  1336. async def clear_console_messages(self) -> None:
  1337. await self._channel.send("clearConsoleMessages", None)
  1338. async def clear_page_errors(self) -> None:
  1339. await self._channel.send("clearPageErrors", None)
  1340. async def pick_locator(self) -> "Locator":
  1341. selector = await self._channel.send("pickLocator", None, {})
  1342. return self.locator(selector)
  1343. async def cancel_pick_locator(self) -> None:
  1344. await self._channel.send("cancelPickLocator", None, {})
  1345. class Worker(ChannelOwner):
  1346. Events = SimpleNamespace(Close="close", Console="console")
  1347. def __init__(
  1348. self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
  1349. ) -> None:
  1350. super().__init__(parent, type, guid, initializer)
  1351. self._set_event_to_subscription_mapping({Worker.Events.Console: "console"})
  1352. self._channel.on("close", lambda _: self._on_close())
  1353. self._page: Optional[Page] = None
  1354. self._context: Optional["BrowserContext"] = None
  1355. def __repr__(self) -> str:
  1356. return f"<Worker url={self.url!r}>"
  1357. def _on_close(self) -> None:
  1358. if self._page:
  1359. self._page._workers.remove(self)
  1360. if self._context:
  1361. self._context._service_workers.remove(self)
  1362. self.emit(Worker.Events.Close, self)
  1363. @property
  1364. def url(self) -> str:
  1365. return self._initializer["url"]
  1366. async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
  1367. return parse_result(
  1368. await self._channel.send(
  1369. "evaluateExpression",
  1370. None,
  1371. dict(
  1372. expression=expression,
  1373. arg=serialize_argument(arg),
  1374. ),
  1375. )
  1376. )
  1377. async def evaluate_handle(
  1378. self, expression: str, arg: Serializable = None
  1379. ) -> JSHandle:
  1380. return from_channel(
  1381. await self._channel.send(
  1382. "evaluateExpressionHandle",
  1383. None,
  1384. dict(
  1385. expression=expression,
  1386. arg=serialize_argument(arg),
  1387. ),
  1388. )
  1389. )
  1390. def expect_event(
  1391. self,
  1392. event: str,
  1393. predicate: Callable = None,
  1394. timeout: float = None,
  1395. ) -> EventContextManagerImpl:
  1396. if timeout is None:
  1397. if self._page:
  1398. timeout = self._page._timeout_settings.timeout()
  1399. elif self._context:
  1400. timeout = self._context._timeout_settings.timeout()
  1401. else:
  1402. timeout = 30000
  1403. waiter = Waiter(self, f"worker.expect_event({event})")
  1404. waiter.reject_on_timeout(
  1405. cast(float, timeout),
  1406. f'Timeout {timeout}ms exceeded while waiting for event "{event}"',
  1407. )
  1408. if event != Worker.Events.Close:
  1409. waiter.reject_on_event(
  1410. self, Worker.Events.Close, lambda: TargetClosedError()
  1411. )
  1412. waiter.wait_for_event(self, event, predicate)
  1413. return EventContextManagerImpl(waiter.result())
  1414. class BindingCall(ChannelOwner):
  1415. def __init__(
  1416. self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
  1417. ) -> None:
  1418. super().__init__(parent, type, guid, initializer)
  1419. async def call(self, func: Callable) -> None:
  1420. try:
  1421. frame = from_channel(self._initializer["frame"])
  1422. source = dict(context=frame._page.context, page=frame._page, frame=frame)
  1423. if self._initializer.get("handle"):
  1424. result = func(source, from_channel(self._initializer["handle"]))
  1425. else:
  1426. func_args = list(map(parse_result, self._initializer["args"]))
  1427. result = func(source, *func_args)
  1428. if inspect.iscoroutine(result):
  1429. result = await result
  1430. await self._channel.send(
  1431. "resolve", None, dict(result=serialize_argument(result))
  1432. )
  1433. except Exception as e:
  1434. tb = sys.exc_info()[2]
  1435. asyncio.create_task(
  1436. self._channel.send(
  1437. "reject", None, dict(error=dict(error=serialize_error(e, tb)))
  1438. )
  1439. )
  1440. def trim_url(param: Union[URLMatchRequest, URLMatchResponse]) -> Optional[str]:
  1441. if isinstance(param, re.Pattern):
  1442. return trim_end(param.pattern)
  1443. if isinstance(param, str):
  1444. return trim_end(param)
  1445. return None
  1446. def trim_end(s: str) -> str:
  1447. if len(s) > 50:
  1448. return s[:50] + "\u2026"
  1449. return s