_frame.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  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. from pathlib import Path
  16. from typing import (
  17. TYPE_CHECKING,
  18. Any,
  19. Dict,
  20. List,
  21. Literal,
  22. Optional,
  23. Pattern,
  24. Sequence,
  25. Set,
  26. Union,
  27. cast,
  28. )
  29. from pyee import EventEmitter
  30. from playwright._impl._api_structures import (
  31. AriaRole,
  32. DropPayload,
  33. FilePayload,
  34. FrameExpectOptions,
  35. FrameExpectResult,
  36. Position,
  37. )
  38. from playwright._impl._connection import (
  39. ChannelOwner,
  40. from_channel,
  41. from_nullable_channel,
  42. )
  43. from playwright._impl._element_handle import ElementHandle, convert_select_option_values
  44. from playwright._impl._errors import Error
  45. from playwright._impl._event_context_manager import EventContextManagerImpl
  46. from playwright._impl._helper import (
  47. DocumentLoadState,
  48. FrameNavigatedEvent,
  49. KeyboardModifier,
  50. MouseButton,
  51. TimeoutSettings,
  52. URLMatch,
  53. async_readfile,
  54. locals_to_params,
  55. monotonic_time,
  56. url_matches,
  57. )
  58. from playwright._impl._js_handle import (
  59. JSHandle,
  60. Serializable,
  61. add_source_url_to_script,
  62. parse_result,
  63. parse_value,
  64. serialize_argument,
  65. )
  66. from playwright._impl._locator import (
  67. FrameLocator,
  68. Locator,
  69. get_by_alt_text_selector,
  70. get_by_label_selector,
  71. get_by_placeholder_selector,
  72. get_by_role_selector,
  73. get_by_test_id_selector,
  74. get_by_text_selector,
  75. get_by_title_selector,
  76. test_id_attribute_name,
  77. )
  78. from playwright._impl._network import Response
  79. from playwright._impl._set_input_files_helpers import convert_input_files
  80. from playwright._impl._waiter import Waiter
  81. if TYPE_CHECKING: # pragma: no cover
  82. from playwright._impl._page import Page
  83. class Frame(ChannelOwner):
  84. def __init__(
  85. self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
  86. ) -> None:
  87. super().__init__(parent, type, guid, initializer)
  88. self._parent_frame = from_nullable_channel(initializer.get("parentFrame"))
  89. if self._parent_frame:
  90. self._parent_frame._child_frames.append(self)
  91. self._name = initializer["name"]
  92. self._url = initializer["url"]
  93. self._detached = False
  94. self._child_frames: List[Frame] = []
  95. self._page: Optional[Page] = None
  96. self._load_states: Set[str] = set(initializer["loadStates"])
  97. self._event_emitter = EventEmitter()
  98. self._channel.on(
  99. "loadstate",
  100. lambda params: self._on_load_state(params.get("add"), params.get("remove")),
  101. )
  102. self._channel.on(
  103. "navigated",
  104. lambda params: self._on_frame_navigated(params),
  105. )
  106. def __repr__(self) -> str:
  107. return f"<Frame name={self.name} url={self.url!r}>"
  108. def _on_load_state(
  109. self, add: DocumentLoadState = None, remove: DocumentLoadState = None
  110. ) -> None:
  111. if add:
  112. self._load_states.add(add)
  113. self._event_emitter.emit("loadstate", add)
  114. elif remove and remove in self._load_states:
  115. self._load_states.remove(remove)
  116. if not self._parent_frame and add == "load" and self._page:
  117. self._page.emit("load", self._page)
  118. self._page.context.emit("pageload", self._page)
  119. if not self._parent_frame and add == "domcontentloaded" and self._page:
  120. self._page.emit("domcontentloaded", self._page)
  121. def _on_frame_navigated(self, event: FrameNavigatedEvent) -> None:
  122. self._url = event["url"]
  123. self._name = event["name"]
  124. self._event_emitter.emit("navigated", event)
  125. if "error" not in event and self._page:
  126. self._page.emit("framenavigated", self)
  127. self._page.context.emit("framenavigated", self)
  128. async def _query_count(self, selector: str) -> int:
  129. return await self._channel.send("queryCount", None, {"selector": selector})
  130. @property
  131. def page(self) -> "Page":
  132. assert self._page
  133. return self._page
  134. async def goto(
  135. self,
  136. url: str,
  137. timeout: float = None,
  138. waitUntil: DocumentLoadState = None,
  139. referer: str = None,
  140. ) -> Optional[Response]:
  141. return cast(
  142. Optional[Response],
  143. from_nullable_channel(
  144. await self._channel.send(
  145. "goto", self._navigation_timeout, locals_to_params(locals())
  146. )
  147. ),
  148. )
  149. def _setup_navigation_waiter(self, wait_name: str, timeout: float = None) -> Waiter:
  150. assert self._page
  151. waiter = Waiter(self._page, f"frame.{wait_name}")
  152. waiter.reject_on_event(
  153. self._page,
  154. "close",
  155. lambda: cast("Page", self._page)._close_error_with_reason(),
  156. )
  157. waiter.reject_on_event(
  158. self._page, "crash", Error("Navigation failed because page crashed!")
  159. )
  160. waiter.reject_on_event(
  161. self._page,
  162. "framedetached",
  163. Error("Navigating frame was detached!"),
  164. lambda frame: frame == self,
  165. )
  166. timeout = self._page._timeout_settings.navigation_timeout(timeout)
  167. waiter.reject_on_timeout(timeout, f"Timeout {timeout}ms exceeded.")
  168. return waiter
  169. async def _expect(
  170. self,
  171. selector: Optional[str],
  172. expression: str,
  173. options: FrameExpectOptions,
  174. title: str = None,
  175. ) -> FrameExpectResult:
  176. if "expectedValue" in options:
  177. options["expectedValue"] = serialize_argument(options["expectedValue"])
  178. result = await self._channel.send_return_as_dict(
  179. "expect",
  180. self._timeout,
  181. {
  182. "selector": selector,
  183. "expression": expression,
  184. **options,
  185. },
  186. title=title,
  187. )
  188. if result.get("received"):
  189. result["received"] = parse_value(result["received"])
  190. return result
  191. def expect_navigation(
  192. self,
  193. url: URLMatch = None,
  194. waitUntil: DocumentLoadState = None,
  195. timeout: float = None,
  196. ) -> EventContextManagerImpl[Response]:
  197. assert self._page
  198. if not waitUntil:
  199. waitUntil = "load"
  200. if timeout is None:
  201. timeout = self._page._timeout_settings.navigation_timeout()
  202. deadline = monotonic_time() + timeout
  203. waiter = self._setup_navigation_waiter("expect_navigation", timeout)
  204. to_url = f' to "{url}"' if url else ""
  205. waiter.log(f"waiting for navigation{to_url} until '{waitUntil}'")
  206. def predicate(event: Any) -> bool:
  207. # Any failed navigation results in a rejection.
  208. if event.get("error"):
  209. return True
  210. waiter.log(f' navigated to "{event["url"]}"')
  211. return url_matches(
  212. cast("Page", self._page)._browser_context._base_url,
  213. event["url"],
  214. url,
  215. )
  216. waiter.wait_for_event(
  217. self._event_emitter,
  218. "navigated",
  219. predicate=predicate,
  220. )
  221. async def continuation() -> Optional[Response]:
  222. event = await waiter.result()
  223. if "error" in event:
  224. raise Error(event["error"])
  225. if waitUntil not in self._load_states:
  226. t = deadline - monotonic_time()
  227. if t > 0:
  228. await self._wait_for_load_state_impl(state=waitUntil, timeout=t)
  229. if "newDocument" in event and "request" in event["newDocument"]:
  230. request = from_channel(event["newDocument"]["request"])
  231. return await request.response()
  232. return None
  233. return EventContextManagerImpl(asyncio.create_task(continuation()))
  234. async def wait_for_url(
  235. self,
  236. url: URLMatch,
  237. waitUntil: DocumentLoadState = None,
  238. timeout: float = None,
  239. ) -> None:
  240. assert self._page
  241. if url_matches(self._page._browser_context._base_url, self.url, url):
  242. await self._wait_for_load_state_impl(state=waitUntil, timeout=timeout)
  243. return
  244. async with self.expect_navigation(
  245. url=url, waitUntil=waitUntil, timeout=timeout
  246. ):
  247. pass
  248. async def wait_for_load_state(
  249. self,
  250. state: Literal["domcontentloaded", "load", "networkidle"] = None,
  251. timeout: float = None,
  252. ) -> None:
  253. return await self._wait_for_load_state_impl(state, timeout)
  254. async def _wait_for_load_state_impl(
  255. self, state: DocumentLoadState = None, timeout: float = None
  256. ) -> None:
  257. if not state:
  258. state = "load"
  259. if state not in ("load", "domcontentloaded", "networkidle", "commit"):
  260. raise Error(
  261. "state: expected one of (load|domcontentloaded|networkidle|commit)"
  262. )
  263. waiter = self._setup_navigation_waiter("wait_for_load_state", timeout)
  264. if state in self._load_states:
  265. waiter.log(f' not waiting, "{state}" event already fired')
  266. # TODO: align with upstream
  267. waiter._fulfill(None)
  268. else:
  269. def handle_load_state_event(actual_state: str) -> bool:
  270. waiter.log(f'"{actual_state}" event fired')
  271. return actual_state == state
  272. waiter.wait_for_event(
  273. self._event_emitter,
  274. "loadstate",
  275. handle_load_state_event,
  276. )
  277. await waiter.result()
  278. def _timeout(self, timeout: Optional[float]) -> float:
  279. timeout_settings = (
  280. self._page._timeout_settings if self._page else TimeoutSettings(None)
  281. )
  282. return timeout_settings.timeout(timeout)
  283. def _navigation_timeout(self, timeout: Optional[float]) -> float:
  284. timeout_settings = (
  285. self._page._timeout_settings if self._page else TimeoutSettings(None)
  286. )
  287. return timeout_settings.navigation_timeout(timeout)
  288. async def frame_element(self) -> ElementHandle:
  289. return from_channel(await self._channel.send("frameElement", None))
  290. async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
  291. return parse_result(
  292. await self._channel.send(
  293. "evaluateExpression",
  294. None,
  295. dict(
  296. expression=expression,
  297. arg=serialize_argument(arg),
  298. ),
  299. )
  300. )
  301. async def evaluate_handle(
  302. self, expression: str, arg: Serializable = None
  303. ) -> JSHandle:
  304. return from_channel(
  305. await self._channel.send(
  306. "evaluateExpressionHandle",
  307. None,
  308. dict(
  309. expression=expression,
  310. arg=serialize_argument(arg),
  311. ),
  312. )
  313. )
  314. async def query_selector(
  315. self, selector: str, strict: bool = None
  316. ) -> Optional[ElementHandle]:
  317. return from_nullable_channel(
  318. await self._channel.send("querySelector", None, locals_to_params(locals()))
  319. )
  320. async def query_selector_all(self, selector: str) -> List[ElementHandle]:
  321. return list(
  322. map(
  323. from_channel,
  324. await self._channel.send(
  325. "querySelectorAll", None, dict(selector=selector)
  326. ),
  327. )
  328. )
  329. async def wait_for_selector(
  330. self,
  331. selector: str,
  332. strict: bool = None,
  333. timeout: float = None,
  334. state: Literal["attached", "detached", "hidden", "visible"] = None,
  335. ) -> Optional[ElementHandle]:
  336. return from_nullable_channel(
  337. await self._channel.send(
  338. "waitForSelector", self._timeout, locals_to_params(locals())
  339. )
  340. )
  341. async def is_checked(
  342. self, selector: str, strict: bool = None, timeout: float = None
  343. ) -> bool:
  344. return await self._channel.send(
  345. "isChecked", self._timeout, locals_to_params(locals())
  346. )
  347. async def is_disabled(
  348. self, selector: str, strict: bool = None, timeout: float = None
  349. ) -> bool:
  350. return await self._channel.send(
  351. "isDisabled", self._timeout, locals_to_params(locals())
  352. )
  353. async def is_editable(
  354. self, selector: str, strict: bool = None, timeout: float = None
  355. ) -> bool:
  356. return await self._channel.send(
  357. "isEditable", self._timeout, locals_to_params(locals())
  358. )
  359. async def is_enabled(
  360. self, selector: str, strict: bool = None, timeout: float = None
  361. ) -> bool:
  362. return await self._channel.send(
  363. "isEnabled", self._timeout, locals_to_params(locals())
  364. )
  365. async def is_hidden(self, selector: str, strict: bool = None) -> bool:
  366. return await self._channel.send(
  367. "isHidden", self._timeout, locals_to_params(locals())
  368. )
  369. async def is_visible(self, selector: str, strict: bool = None) -> bool:
  370. return await self._channel.send(
  371. "isVisible", self._timeout, locals_to_params(locals())
  372. )
  373. async def dispatch_event(
  374. self,
  375. selector: str,
  376. type: str,
  377. eventInit: Dict = None,
  378. strict: bool = None,
  379. timeout: float = None,
  380. ) -> None:
  381. await self._channel.send(
  382. "dispatchEvent",
  383. self._timeout,
  384. locals_to_params(
  385. dict(
  386. selector=selector,
  387. type=type,
  388. eventInit=serialize_argument(eventInit),
  389. strict=strict,
  390. timeout=timeout,
  391. ),
  392. ),
  393. )
  394. async def eval_on_selector(
  395. self,
  396. selector: str,
  397. expression: str,
  398. arg: Serializable = None,
  399. strict: bool = None,
  400. ) -> Any:
  401. return parse_result(
  402. await self._channel.send(
  403. "evalOnSelector",
  404. None,
  405. locals_to_params(
  406. dict(
  407. selector=selector,
  408. expression=expression,
  409. arg=serialize_argument(arg),
  410. strict=strict,
  411. )
  412. ),
  413. )
  414. )
  415. async def eval_on_selector_all(
  416. self,
  417. selector: str,
  418. expression: str,
  419. arg: Serializable = None,
  420. ) -> Any:
  421. return parse_result(
  422. await self._channel.send(
  423. "evalOnSelectorAll",
  424. None,
  425. dict(
  426. selector=selector,
  427. expression=expression,
  428. arg=serialize_argument(arg),
  429. ),
  430. )
  431. )
  432. async def content(self) -> str:
  433. return await self._channel.send("content", None)
  434. async def set_content(
  435. self,
  436. html: str,
  437. timeout: float = None,
  438. waitUntil: DocumentLoadState = None,
  439. ) -> None:
  440. await self._channel.send(
  441. "setContent", self._navigation_timeout, locals_to_params(locals())
  442. )
  443. @property
  444. def name(self) -> str:
  445. return self._name or ""
  446. @property
  447. def url(self) -> str:
  448. return self._url or ""
  449. @property
  450. def parent_frame(self) -> Optional["Frame"]:
  451. return self._parent_frame
  452. @property
  453. def child_frames(self) -> List["Frame"]:
  454. return self._child_frames.copy()
  455. def is_detached(self) -> bool:
  456. return self._detached
  457. async def add_script_tag(
  458. self,
  459. url: str = None,
  460. path: Union[str, Path] = None,
  461. content: str = None,
  462. type: str = None,
  463. ) -> ElementHandle:
  464. params = locals_to_params(locals())
  465. if path:
  466. params["content"] = add_source_url_to_script(
  467. (await async_readfile(path)).decode(), path
  468. )
  469. del params["path"]
  470. return from_channel(await self._channel.send("addScriptTag", None, params))
  471. async def add_style_tag(
  472. self, url: str = None, path: Union[str, Path] = None, content: str = None
  473. ) -> ElementHandle:
  474. params = locals_to_params(locals())
  475. if path:
  476. params["content"] = (
  477. (await async_readfile(path)).decode()
  478. + "\n/*# sourceURL="
  479. + str(Path(path))
  480. + "*/"
  481. )
  482. del params["path"]
  483. return from_channel(await self._channel.send("addStyleTag", None, params))
  484. async def click(
  485. self,
  486. selector: str,
  487. modifiers: Sequence[KeyboardModifier] = None,
  488. position: Position = None,
  489. delay: float = None,
  490. button: MouseButton = None,
  491. clickCount: int = None,
  492. timeout: float = None,
  493. force: bool = None,
  494. noWaitAfter: bool = None,
  495. strict: bool = None,
  496. trial: bool = None,
  497. ) -> None:
  498. await self._click(**locals_to_params(locals()))
  499. async def _click(
  500. self,
  501. selector: str,
  502. modifiers: Sequence[KeyboardModifier] = None,
  503. position: Position = None,
  504. delay: float = None,
  505. button: MouseButton = None,
  506. clickCount: int = None,
  507. timeout: float = None,
  508. force: bool = None,
  509. noWaitAfter: bool = None,
  510. strict: bool = None,
  511. trial: bool = None,
  512. steps: int = None,
  513. ) -> None:
  514. await self._channel.send("click", self._timeout, locals_to_params(locals()))
  515. async def dblclick(
  516. self,
  517. selector: str,
  518. modifiers: Sequence[KeyboardModifier] = None,
  519. position: Position = None,
  520. delay: float = None,
  521. button: MouseButton = None,
  522. timeout: float = None,
  523. force: bool = None,
  524. noWaitAfter: bool = None,
  525. strict: bool = None,
  526. trial: bool = None,
  527. ) -> None:
  528. await self._channel.send(
  529. "dblclick", self._timeout, locals_to_params(locals()), title="Double click"
  530. )
  531. async def tap(
  532. self,
  533. selector: str,
  534. modifiers: Sequence[KeyboardModifier] = None,
  535. position: Position = None,
  536. timeout: float = None,
  537. force: bool = None,
  538. noWaitAfter: bool = None,
  539. strict: bool = None,
  540. trial: bool = None,
  541. ) -> None:
  542. await self._channel.send("tap", self._timeout, locals_to_params(locals()))
  543. async def fill(
  544. self,
  545. selector: str,
  546. value: str,
  547. timeout: float = None,
  548. noWaitAfter: bool = None,
  549. strict: bool = None,
  550. force: bool = None,
  551. ) -> None:
  552. await self._fill(**locals_to_params(locals()))
  553. async def _fill(
  554. self,
  555. selector: str,
  556. value: str,
  557. timeout: float = None,
  558. noWaitAfter: bool = None,
  559. strict: bool = None,
  560. force: bool = None,
  561. title: str = None,
  562. ) -> None:
  563. await self._channel.send("fill", self._timeout, locals_to_params(locals()))
  564. def locator(
  565. self,
  566. selector: str,
  567. hasText: Union[str, Pattern[str]] = None,
  568. hasNotText: Union[str, Pattern[str]] = None,
  569. has: Locator = None,
  570. hasNot: Locator = None,
  571. ) -> Locator:
  572. return Locator(
  573. self,
  574. selector,
  575. has_text=hasText,
  576. has_not_text=hasNotText,
  577. has=has,
  578. has_not=hasNot,
  579. )
  580. def get_by_alt_text(
  581. self, text: Union[str, Pattern[str]], exact: bool = None
  582. ) -> "Locator":
  583. return self.locator(get_by_alt_text_selector(text, exact=exact))
  584. def get_by_label(
  585. self, text: Union[str, Pattern[str]], exact: bool = None
  586. ) -> "Locator":
  587. return self.locator(get_by_label_selector(text, exact=exact))
  588. def get_by_placeholder(
  589. self, text: Union[str, Pattern[str]], exact: bool = None
  590. ) -> "Locator":
  591. return self.locator(get_by_placeholder_selector(text, exact=exact))
  592. def get_by_role(
  593. self,
  594. role: AriaRole,
  595. checked: bool = None,
  596. disabled: bool = None,
  597. expanded: bool = None,
  598. includeHidden: bool = None,
  599. level: int = None,
  600. name: Union[str, Pattern[str]] = None,
  601. pressed: bool = None,
  602. selected: bool = None,
  603. exact: bool = None,
  604. description: Union[str, Pattern[str]] = None,
  605. ) -> "Locator":
  606. return self.locator(
  607. get_by_role_selector(
  608. role,
  609. checked=checked,
  610. disabled=disabled,
  611. expanded=expanded,
  612. includeHidden=includeHidden,
  613. level=level,
  614. name=name,
  615. pressed=pressed,
  616. selected=selected,
  617. exact=exact,
  618. description=description,
  619. )
  620. )
  621. def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
  622. return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId))
  623. def get_by_text(
  624. self, text: Union[str, Pattern[str]], exact: bool = None
  625. ) -> "Locator":
  626. return self.locator(get_by_text_selector(text, exact=exact))
  627. def get_by_title(
  628. self, text: Union[str, Pattern[str]], exact: bool = None
  629. ) -> "Locator":
  630. return self.locator(get_by_title_selector(text, exact=exact))
  631. def frame_locator(self, selector: str) -> FrameLocator:
  632. return FrameLocator(self, selector)
  633. async def focus(
  634. self, selector: str, strict: bool = None, timeout: float = None
  635. ) -> None:
  636. await self._channel.send("focus", self._timeout, locals_to_params(locals()))
  637. async def text_content(
  638. self, selector: str, strict: bool = None, timeout: float = None
  639. ) -> Optional[str]:
  640. return await self._channel.send(
  641. "textContent", self._timeout, locals_to_params(locals())
  642. )
  643. async def inner_text(
  644. self, selector: str, strict: bool = None, timeout: float = None
  645. ) -> str:
  646. return await self._channel.send(
  647. "innerText", self._timeout, locals_to_params(locals())
  648. )
  649. async def inner_html(
  650. self, selector: str, strict: bool = None, timeout: float = None
  651. ) -> str:
  652. return await self._channel.send(
  653. "innerHTML", self._timeout, locals_to_params(locals())
  654. )
  655. async def get_attribute(
  656. self, selector: str, name: str, strict: bool = None, timeout: float = None
  657. ) -> Optional[str]:
  658. return await self._channel.send(
  659. "getAttribute", self._timeout, locals_to_params(locals())
  660. )
  661. async def hover(
  662. self,
  663. selector: str,
  664. modifiers: Sequence[KeyboardModifier] = None,
  665. position: Position = None,
  666. timeout: float = None,
  667. noWaitAfter: bool = None,
  668. force: bool = None,
  669. strict: bool = None,
  670. trial: bool = None,
  671. ) -> None:
  672. await self._channel.send("hover", self._timeout, locals_to_params(locals()))
  673. async def drag_and_drop(
  674. self,
  675. source: str,
  676. target: str,
  677. sourcePosition: Position = None,
  678. targetPosition: Position = None,
  679. force: bool = None,
  680. noWaitAfter: bool = None,
  681. strict: bool = None,
  682. timeout: float = None,
  683. trial: bool = None,
  684. steps: int = None,
  685. ) -> None:
  686. await self._channel.send(
  687. "dragAndDrop", self._timeout, locals_to_params(locals())
  688. )
  689. async def select_option(
  690. self,
  691. selector: str,
  692. value: Union[str, Sequence[str]] = None,
  693. index: Union[int, Sequence[int]] = None,
  694. label: Union[str, Sequence[str]] = None,
  695. element: Union["ElementHandle", Sequence["ElementHandle"]] = None,
  696. timeout: float = None,
  697. noWaitAfter: bool = None,
  698. strict: bool = None,
  699. force: bool = None,
  700. ) -> List[str]:
  701. params = locals_to_params(
  702. dict(
  703. selector=selector,
  704. timeout=timeout,
  705. strict=strict,
  706. force=force,
  707. **convert_select_option_values(value, index, label, element),
  708. )
  709. )
  710. return await self._channel.send("selectOption", self._timeout, params)
  711. async def input_value(
  712. self,
  713. selector: str,
  714. strict: bool = None,
  715. timeout: float = None,
  716. ) -> str:
  717. return await self._channel.send(
  718. "inputValue", self._timeout, locals_to_params(locals())
  719. )
  720. async def set_input_files(
  721. self,
  722. selector: str,
  723. files: Union[
  724. str, Path, FilePayload, Sequence[Union[str, Path]], Sequence[FilePayload]
  725. ],
  726. strict: bool = None,
  727. timeout: float = None,
  728. noWaitAfter: bool = None,
  729. ) -> None:
  730. converted = await convert_input_files(files, self.page.context)
  731. await self._channel.send(
  732. "setInputFiles",
  733. self._timeout,
  734. {
  735. "selector": selector,
  736. "strict": strict,
  737. "timeout": self._timeout(timeout),
  738. **converted,
  739. },
  740. )
  741. async def _drop(
  742. self,
  743. selector: str,
  744. payload: "DropPayload",
  745. strict: bool = None,
  746. position: Position = None,
  747. timeout: float = None,
  748. ) -> None:
  749. params: Dict[str, Any] = {
  750. "selector": selector,
  751. "strict": strict,
  752. "position": position,
  753. "timeout": self._timeout(timeout),
  754. }
  755. files = payload.get("files") if payload else None
  756. if files is not None:
  757. converted = await convert_input_files(files, self.page.context)
  758. if "directoryStream" in converted or "directoryLocalPath" in converted:
  759. raise Error(
  760. "Dropping a directory is not supported, pass individual files instead."
  761. )
  762. params.update(converted)
  763. data = payload.get("data") if payload else None
  764. if data is not None:
  765. params["data"] = [{"mimeType": k, "value": v} for k, v in data.items()]
  766. await self._channel.send("drop", self._timeout, params)
  767. async def type(
  768. self,
  769. selector: str,
  770. text: str,
  771. delay: float = None,
  772. strict: bool = None,
  773. timeout: float = None,
  774. noWaitAfter: bool = None,
  775. ) -> None:
  776. await self._channel.send("type", self._timeout, locals_to_params(locals()))
  777. async def press(
  778. self,
  779. selector: str,
  780. key: str,
  781. delay: float = None,
  782. strict: bool = None,
  783. timeout: float = None,
  784. noWaitAfter: bool = None,
  785. ) -> None:
  786. await self._channel.send("press", self._timeout, locals_to_params(locals()))
  787. async def check(
  788. self,
  789. selector: str,
  790. position: Position = None,
  791. timeout: float = None,
  792. force: bool = None,
  793. noWaitAfter: bool = None,
  794. strict: bool = None,
  795. trial: bool = None,
  796. ) -> None:
  797. await self._channel.send("check", self._timeout, locals_to_params(locals()))
  798. async def uncheck(
  799. self,
  800. selector: str,
  801. position: Position = None,
  802. timeout: float = None,
  803. force: bool = None,
  804. noWaitAfter: bool = None,
  805. strict: bool = None,
  806. trial: bool = None,
  807. ) -> None:
  808. await self._channel.send("uncheck", self._timeout, locals_to_params(locals()))
  809. async def wait_for_timeout(self, timeout: float) -> None:
  810. await self._channel.send("waitForTimeout", None, {"waitTimeout": timeout})
  811. async def wait_for_function(
  812. self,
  813. expression: str,
  814. arg: Serializable = None,
  815. timeout: float = None,
  816. polling: Union[float, Literal["raf"]] = None,
  817. ) -> JSHandle:
  818. if isinstance(polling, str) and polling != "raf":
  819. raise Error(f"Unknown polling option: {polling}")
  820. params = locals_to_params(locals())
  821. params["arg"] = serialize_argument(arg)
  822. if polling is not None and polling != "raf":
  823. params["pollingInterval"] = polling
  824. return from_channel(
  825. await self._channel.send("waitForFunction", self._timeout, params)
  826. )
  827. async def title(self) -> str:
  828. return await self._channel.send("title", None)
  829. async def set_checked(
  830. self,
  831. selector: str,
  832. checked: bool,
  833. position: Position = None,
  834. timeout: float = None,
  835. force: bool = None,
  836. noWaitAfter: bool = None,
  837. strict: bool = None,
  838. trial: bool = None,
  839. ) -> None:
  840. if checked:
  841. await self.check(
  842. selector=selector,
  843. position=position,
  844. timeout=timeout,
  845. force=force,
  846. strict=strict,
  847. trial=trial,
  848. )
  849. else:
  850. await self.uncheck(
  851. selector=selector,
  852. position=position,
  853. timeout=timeout,
  854. force=force,
  855. strict=strict,
  856. trial=trial,
  857. )
  858. async def _highlight(self, selector: str, style: str = None) -> None:
  859. await self._channel.send(
  860. "highlight", None, {"selector": selector, "style": style}
  861. )
  862. async def _hide_highlight(self, selector: str) -> None:
  863. await self._channel.send("hideHighlight", None, {"selector": selector})