From 3f5a9e679ceb3db51e3d7e6c5f50b506019623d8 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Thu, 15 Dec 2022 12:28:36 -0800 Subject: [PATCH] chore: roll to ToT --- README.md | 4 +- playwright/_impl/_element_handle.py | 2 +- playwright/_impl/_fetch.py | 33 +- playwright/_impl/_frame.py | 2 +- playwright/_impl/_helper.py | 7 - playwright/_impl/_locator.py | 18 +- playwright/_impl/_network.py | 119 ++++-- playwright/_impl/_page.py | 2 +- playwright/async_api/_generated.py | 432 ++++++++++++-------- playwright/sync_api/_generated.py | 434 +++++++++++++-------- setup.py | 2 +- tests/async/test_locators.py | 8 + tests/async/test_page.py | 177 --------- tests/async/test_page_request_fallback.py | 23 ++ tests/async/test_page_request_intercept.py | 42 ++ tests/async/test_page_select_option.py | 220 +++++++++++ tests/sync/test_locators.py | 8 + tests/sync/test_page_request_fallback.py | 20 + tests/sync/test_page_request_intercept.py | 28 ++ tests/sync/test_page_select_option.py | 214 ++++++++++ 20 files changed, 1245 insertions(+), 550 deletions(-) create mode 100644 tests/async/test_page_request_intercept.py create mode 100644 tests/async/test_page_select_option.py create mode 100644 tests/sync/test_page_request_intercept.py create mode 100644 tests/sync/test_page_select_option.py diff --git a/README.md b/README.md index 04c25a7b1..bcf88ee0a 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 108.0.5359.48 | ✅ | ✅ | ✅ | +| Chromium 109.0.5414.46 | ✅ | ✅ | ✅ | | WebKit 16.4 | ✅ | ✅ | ✅ | -| Firefox 106.0 | ✅ | ✅ | ✅ | +| Firefox 107.0 | ✅ | ✅ | ✅ | ## Documentation diff --git a/playwright/_impl/_element_handle.py b/playwright/_impl/_element_handle.py index 0cf33a160..efb5925ae 100644 --- a/playwright/_impl/_element_handle.py +++ b/playwright/_impl/_element_handle.py @@ -392,7 +392,7 @@ def convert_select_option_values( if value: if not isinstance(value, list): value = [value] - options = (options or []) + list(map(lambda e: dict(value=e), value)) + options = (options or []) + list(map(lambda e: dict(valueOrLabel=e), value)) if index: if not isinstance(index, list): index = [index] diff --git a/playwright/_impl/_fetch.py b/playwright/_impl/_fetch.py index c4428a37e..1d351c124 100644 --- a/playwright/_impl/_fetch.py +++ b/playwright/_impl/_fetch.py @@ -273,6 +273,7 @@ async def fetch( ignoreHTTPSErrors: bool = None, maxRedirects: int = None, ) -> "APIResponse": + url = urlOrRequest if isinstance(urlOrRequest, str) else None request = ( cast(network.Request, to_impl(urlOrRequest)) if isinstance(to_impl(urlOrRequest), network.Request) @@ -281,13 +282,43 @@ async def fetch( assert request or isinstance( urlOrRequest, str ), "First argument must be either URL string or Request" + return await self._inner_fetch( + request, + url, + method, + headers, + data, + params, + form, + multipart, + timeout, + failOnStatusCode, + ignoreHTTPSErrors, + maxRedirects, + ) + + async def _inner_fetch( + self, + request: Optional[network.Request], + url: Optional[str], + method: str = None, + headers: Headers = None, + data: DataType = None, + params: ParamsType = None, + form: FormType = None, + multipart: Dict[str, Union[bytes, bool, float, str, FilePayload]] = None, + timeout: float = None, + failOnStatusCode: bool = None, + ignoreHTTPSErrors: bool = None, + maxRedirects: int = None, + ) -> "APIResponse": assert ( (1 if data else 0) + (1 if form else 0) + (1 if multipart else 0) ) <= 1, "Only one of 'data', 'form' or 'multipart' can be specified" assert ( maxRedirects is None or maxRedirects >= 0 ), "'max_redirects' must be greater than or equal to '0'" - url = request.url if request else urlOrRequest + url = url or (request.url if request else url) method = method or (request.method if request else "GET") # Cannot call allHeaders() here as the request may be paused inside route handler. headers_obj = headers or (request.headers if request else None) diff --git a/playwright/_impl/_frame.py b/playwright/_impl/_frame.py index ca7f4cccb..573a56a72 100644 --- a/playwright/_impl/_frame.py +++ b/playwright/_impl/_frame.py @@ -578,7 +578,7 @@ def get_by_role( ) ) - def get_by_test_id(self, testId: str) -> "Locator": + def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator": return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId)) def get_by_text( diff --git a/playwright/_impl/_helper.py b/playwright/_impl/_helper.py index 43b465c2d..a9857591c 100644 --- a/playwright/_impl/_helper.py +++ b/playwright/_impl/_helper.py @@ -79,13 +79,6 @@ class ErrorPayload(TypedDict, total=False): value: Optional[Any] -class FallbackOverrideParameters(TypedDict, total=False): - url: Optional[str] - method: Optional[str] - headers: Optional[Dict[str, str]] - postData: Optional[Union[str, bytes]] - - class HarRecordingMetadata(TypedDict, total=False): path: str content: Optional[HarContentPolicy] diff --git a/playwright/_impl/_locator.py b/playwright/_impl/_locator.py index 1597a66f3..5d59d5561 100644 --- a/playwright/_impl/_locator.py +++ b/playwright/_impl/_locator.py @@ -261,7 +261,7 @@ def get_by_role( ) ) - def get_by_test_id(self, testId: str) -> "Locator": + def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator": return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId)) def get_by_text( @@ -328,6 +328,14 @@ async def blur(self, timeout: float = None) -> None: }, ) + async def all( + self, + ) -> List["Locator"]: + result = [] + for index in range(await self.count()): + result.append(self.nth(index)) + return result + async def count( self, ) -> int: @@ -709,7 +717,7 @@ def get_by_role( ) ) - def get_by_test_id(self, testId: str) -> "Locator": + def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator": return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId)) def get_by_text( @@ -755,7 +763,11 @@ def set_test_id_attribute_name(attribute_name: str) -> None: _test_id_attribute_name = attribute_name -def get_by_test_id_selector(test_id_attribute_name: str, test_id: str) -> str: +def get_by_test_id_selector( + test_id_attribute_name: str, test_id: Union[str, Pattern[str]] +) -> str: + if isinstance(test_id, Pattern): + return f"internal:testid=[{test_id_attribute_name}=/{test_id.pattern}/{escape_regex_flags(test_id)}]" return f"internal:testid=[{test_id_attribute_name}={escape_for_attribute_selector(test_id, True)}]" diff --git a/playwright/_impl/_network.py b/playwright/_impl/_network.py index 46fadf62c..132c67a49 100644 --- a/playwright/_impl/_network.py +++ b/playwright/_impl/_network.py @@ -17,6 +17,7 @@ import inspect import json import mimetypes +import sys from collections import defaultdict from pathlib import Path from types import SimpleNamespace @@ -31,6 +32,11 @@ Union, cast, ) + +if sys.version_info >= (3, 8): # pragma: no cover + from typing import TypedDict +else: # pragma: no cover + from typing_extensions import TypedDict from urllib import parse from playwright._impl._api_structures import ( @@ -48,7 +54,7 @@ from_nullable_channel, ) from playwright._impl._event_context_manager import EventContextManagerImpl -from playwright._impl._helper import FallbackOverrideParameters, locals_to_params +from playwright._impl._helper import locals_to_params from playwright._impl._wait_helper import WaitHelper if TYPE_CHECKING: # pragma: no cover @@ -57,6 +63,21 @@ from playwright._impl._page import Page +class FallbackOverrideParameters(TypedDict, total=False): + url: Optional[str] + method: Optional[str] + headers: Optional[Dict[str, str]] + postData: Optional[Union[str, bytes]] + + +class SerializedFallbackOverrides: + def __init__(self) -> None: + self.url: Optional[str] = None + self.method: Optional[str] = None + self.headers: Optional[Dict[str, str]] = None + self.post_data_buffer: Optional[bytes] = None + + def serialize_headers(headers: Dict[str, str]) -> HeadersArray: return [ {"name": name, "value": value} @@ -90,21 +111,39 @@ def __init__( } self._provisional_headers = RawHeaders(self._initializer["headers"]) self._all_headers_future: Optional[asyncio.Future[RawHeaders]] = None - self._fallback_overrides: FallbackOverrideParameters = ( - FallbackOverrideParameters() + self._fallback_overrides: SerializedFallbackOverrides = ( + SerializedFallbackOverrides() ) + base64_post_data = initializer.get("postData") + if base64_post_data is not None: + self._fallback_overrides.post_data_buffer = base64.b64decode( + base64_post_data + ) def __repr__(self) -> str: return f"" def _apply_fallback_overrides(self, overrides: FallbackOverrideParameters) -> None: - self._fallback_overrides = cast( - FallbackOverrideParameters, {**self._fallback_overrides, **overrides} + self._fallback_overrides.url = overrides.get( + "url", self._fallback_overrides.url ) + self._fallback_overrides.method = overrides.get( + "method", self._fallback_overrides.method + ) + self._fallback_overrides.headers = overrides.get( + "headers", self._fallback_overrides.headers + ) + post_data = overrides.get("postData") + if isinstance(post_data, str): + self._fallback_overrides.post_data_buffer = post_data.encode() + elif isinstance(post_data, bytes): + self._fallback_overrides.post_data_buffer = post_data + elif post_data is not None: + self._fallback_overrides.post_data_buffer = json.dumps(post_data).encode() @property def url(self) -> str: - return cast(str, self._fallback_overrides.get("url", self._initializer["url"])) + return cast(str, self._fallback_overrides.url or self._initializer["url"]) @property def resource_type(self) -> str: @@ -112,9 +151,7 @@ def resource_type(self) -> str: @property def method(self) -> str: - return cast( - str, self._fallback_overrides.get("method", self._initializer["method"]) - ) + return cast(str, self._fallback_overrides.method or self._initializer["method"]) async def sizes(self) -> RequestSizes: response = await self.response() @@ -124,7 +161,7 @@ async def sizes(self) -> RequestSizes: @property def post_data(self) -> Optional[str]: - data = self._fallback_overrides.get("postData", self.post_data_buffer) + data = self._fallback_overrides.post_data_buffer if not data: return None return data.decode() if isinstance(data, bytes) else data @@ -144,17 +181,7 @@ def post_data_json(self) -> Optional[Any]: @property def post_data_buffer(self) -> Optional[bytes]: - override = self._fallback_overrides.get("post_data") - if override: - return ( - override.encode() - if isinstance(override, str) - else cast(bytes, override) - ) - b64_content = self._initializer.get("postData") - if b64_content is None: - return None - return base64.b64decode(b64_content) + return self._fallback_overrides.post_data_buffer async def response(self) -> Optional["Response"]: return from_nullable_channel(await self._channel.send("response")) @@ -189,7 +216,7 @@ def _set_response_end_timing(self, response_end_timing: float) -> None: @property def headers(self) -> Headers: - override = self._fallback_overrides.get("headers") + override = self._fallback_overrides.headers if override: return RawHeaders._from_headers_dict_lossy(override).headers() return self._provisional_headers.headers() @@ -204,7 +231,7 @@ async def header_value(self, name: str) -> Optional[str]: return (await self._actual_headers()).get(name) async def _actual_headers(self) -> "RawHeaders": - override = self._fallback_overrides.get("headers") + override = self._fallback_overrides.headers if override: return RawHeaders(serialize_headers(override)) if not self._all_headers_future: @@ -254,6 +281,7 @@ async def fulfill( status: int = None, headers: Dict[str, str] = None, body: Union[str, bytes] = None, + json: Any = None, path: Union[str, Path] = None, contentType: str = None, response: "APIResponse" = None, @@ -270,6 +298,8 @@ async def fulfill( ) from playwright._impl._fetch import APIResponse + if json is not None: + body = json.dumps(json) if body is None and path is None and isinstance(response, APIResponse): if response._request._connection is self._connection: params["fetchResponseUid"] = response._fetch_uid @@ -295,6 +325,8 @@ async def fulfill( headers = {k.lower(): str(v) for k, v in params.get("headers", {}).items()} if params.get("contentType"): headers["content-type"] = params["contentType"] + elif json: + headers["content-type"] = "application/json" elif path: headers["content-type"] = ( mimetypes.guess_type(str(Path(path)))[0] or "application/octet-stream" @@ -305,12 +337,24 @@ async def fulfill( await self._race_with_page_close(self._channel.send("fulfill", params)) self._report_handled(True) + async def fetch( + self, + url: str = None, + method: str = None, + headers: Dict[str, str] = None, + postData: Union[Any, str, bytes] = None, + ) -> "APIResponse": + page = self.request.frame._page + return await page.context.request._inner_fetch( + self.request, url, method, headers, postData + ) + async def fallback( self, url: str = None, method: str = None, headers: Dict[str, str] = None, - postData: Union[str, bytes] = None, + postData: Union[Any, str, bytes] = None, ) -> None: overrides = cast(FallbackOverrideParameters, locals_to_params(locals())) self._check_not_handled() @@ -322,7 +366,7 @@ async def continue_( url: str = None, method: str = None, headers: Dict[str, str] = None, - postData: Union[str, bytes] = None, + postData: Union[Any, str, bytes] = None, ) -> None: overrides = cast(FallbackOverrideParameters, locals_to_params(locals())) self._check_not_handled() @@ -335,23 +379,18 @@ def _internal_continue( ) -> Coroutine[Any, Any, None]: async def continue_route() -> None: try: - post_data_for_wire: Optional[str] = None - post_data_from_overrides = self.request._fallback_overrides.get( - "postData" - ) - if post_data_from_overrides is not None: - post_data_for_wire = ( - base64.b64encode(post_data_from_overrides.encode()).decode() - if isinstance(post_data_from_overrides, str) - else base64.b64encode(post_data_from_overrides).decode() - ) - params = locals_to_params( - cast(Dict[str, str], self.request._fallback_overrides) - ) + params: Dict[str, Any] = {} + params["url"] = self.request._fallback_overrides.url + params["method"] = self.request._fallback_overrides.method + params["headers"] = self.request._fallback_overrides.headers + if self.request._fallback_overrides.post_data_buffer is not None: + params["postData"] = base64.b64encode( + self.request._fallback_overrides.post_data_buffer + ).decode() + params = locals_to_params(params) + if "headers" in params: params["headers"] = serialize_headers(params["headers"]) - if post_data_for_wire is not None: - params["postData"] = post_data_for_wire await self._connection.wrap_api_call( lambda: self._race_with_page_close( self._channel.send( diff --git a/playwright/_impl/_page.py b/playwright/_impl/_page.py index f2e05acdf..da524d4b8 100644 --- a/playwright/_impl/_page.py +++ b/playwright/_impl/_page.py @@ -788,7 +788,7 @@ def get_by_role( exact=exact, ) - def get_by_test_id(self, testId: str) -> "Locator": + def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator": return self._main_frame.get_by_test_id(testId) def get_by_text( diff --git a/playwright/async_api/_generated.py b/playwright/async_api/_generated.py index 499701797..24efc0ceb 100644 --- a/playwright/async_api/_generated.py +++ b/playwright/async_api/_generated.py @@ -668,6 +668,7 @@ async def fulfill( status: typing.Optional[int] = None, headers: typing.Optional[typing.Dict[str, str]] = None, body: typing.Optional[typing.Union[str, bytes]] = None, + json: typing.Optional[typing.Any] = None, path: typing.Optional[typing.Union[str, pathlib.Path]] = None, content_type: typing.Optional[str] = None, response: typing.Optional["APIResponse"] = None @@ -712,6 +713,8 @@ async def fulfill( Response headers. Header values will be converted to a string. body : Union[bytes, str, None] Response body. + json : Union[Any, None] + JSON response. This method will set the content type to `application/json` if not set. path : Union[pathlib.Path, str, None] File path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to the current working directory. @@ -727,19 +730,82 @@ async def fulfill( status=status, headers=mapping.to_impl(headers), body=body, + json=mapping.to_impl(json), path=path, contentType=content_type, response=response._impl_obj if response else None, ) ) + async def fetch( + self, + *, + url: typing.Optional[str] = None, + method: typing.Optional[str] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None + ) -> "APIResponse": + """Route.fetch + + Performs the request and fetches result without fulfilling it, so that the response could be modified and then + fulfilled. + + **Usage** + + ```py + async def handle(route): + response = await route.fulfill() + json = await response.json() + json[\"message\"][\"big_red_dog\"] = [] + await route.fulfill(response=response, json=json) + + await page.route(\"https://dog.ceo/api/breeds/list/all\", handle) + ``` + + ```py + def handle(route): + response = route.fulfill() + json = response.json() + json[\"message\"][\"big_red_dog\"] = [] + route.fulfill(response=response, json=json) + + page.route(\"https://dog.ceo/api/breeds/list/all\", handle) + ``` + + Parameters + ---------- + url : Union[str, None] + If set changes the request URL. New URL must have same protocol as original one. + method : Union[str, None] + If set changes the request method (e.g. GET or POST). + headers : Union[Dict[str, str], None] + If set changes the request HTTP headers. Header values will be converted to a string. + post_data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + + Returns + ------- + APIResponse + """ + + return mapping.from_impl( + await self._impl_obj.fetch( + url=url, + method=method, + headers=mapping.to_impl(headers), + postData=mapping.to_impl(post_data), + ) + ) + async def fallback( self, *, url: typing.Optional[str] = None, method: typing.Optional[str] = None, headers: typing.Optional[typing.Dict[str, str]] = None, - post_data: typing.Optional[typing.Union[str, bytes]] = None + post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None ) -> None: """Route.fallback @@ -819,7 +885,7 @@ async def handle(route, request): \"bar\": None # remove \"bar\" header } await route.fallback(headers=headers) - } + await page.route(\"**/*\", handle) ``` @@ -832,7 +898,7 @@ def handle(route, request): \"bar\": None # remove \"bar\" header } route.fallback(headers=headers) - } + page.route(\"**/*\", handle) ``` @@ -842,11 +908,11 @@ def handle(route, request): If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the route matching, all the routes are matched using the original request URL. method : Union[str, None] - If set changes the request method (e.g. GET or POST) + If set changes the request method (e.g. GET or POST). headers : Union[Dict[str, str], None] If set changes the request HTTP headers. Header values will be converted to a string. - post_data : Union[bytes, str, None] - If set changes the post data of request + post_data : Union[Any, bytes, str, None] + If set changes the post data of request. """ return mapping.from_maybe_impl( @@ -854,7 +920,7 @@ def handle(route, request): url=url, method=method, headers=mapping.to_impl(headers), - postData=post_data, + postData=mapping.to_impl(post_data), ) ) @@ -864,7 +930,7 @@ async def continue_( url: typing.Optional[str] = None, method: typing.Optional[str] = None, headers: typing.Optional[typing.Dict[str, str]] = None, - post_data: typing.Optional[typing.Union[str, bytes]] = None + post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None ) -> None: """Route.continue_ @@ -881,7 +947,7 @@ async def handle(route, request): \"bar\": None # remove \"bar\" header } await route.continue_(headers=headers) - } + await page.route(\"**/*\", handle) ``` @@ -894,7 +960,7 @@ def handle(route, request): \"bar\": None # remove \"bar\" header } route.continue_(headers=headers) - } + page.route(\"**/*\", handle) ``` @@ -903,11 +969,11 @@ def handle(route, request): url : Union[str, None] If set changes the request URL. New URL must have same protocol as original one. method : Union[str, None] - If set changes the request method (e.g. GET or POST) + If set changes the request method (e.g. GET or POST). headers : Union[Dict[str, str], None] If set changes the request HTTP headers. Header values will be converted to a string. - post_data : Union[bytes, str, None] - If set changes the post data of request + post_data : Union[Any, bytes, str, None] + If set changes the post data of request. """ return mapping.from_maybe_impl( @@ -915,7 +981,7 @@ def handle(route, request): url=url, method=method, headers=mapping.to_impl(headers), - postData=post_data, + postData=mapping.to_impl(post_data), ) ) @@ -2747,13 +2813,13 @@ async def screenshot( async def query_selector(self, selector: str) -> typing.Optional["ElementHandle"]: """ElementHandle.query_selector - The method finds an element matching the specified selector in the `ElementHandle`'s subtree. See - [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements match the selector, returns `null`. + The method finds an element matching the specified selector in the `ElementHandle`'s subtree. If no elements match + the selector, returns `null`. Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. Returns ------- @@ -2767,13 +2833,13 @@ async def query_selector(self, selector: str) -> typing.Optional["ElementHandle" async def query_selector_all(self, selector: str) -> typing.List["ElementHandle"]: """ElementHandle.query_selector_all - The method finds all elements matching the specified selector in the `ElementHandle`s subtree. See - [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements match the selector, returns empty array. + The method finds all elements matching the specified selector in the `ElementHandle`s subtree. If no elements match + the selector, returns empty array. Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. Returns ------- @@ -2792,8 +2858,7 @@ async def eval_on_selector( Returns the return value of `expression`. The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a - first argument to `expression`. See [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements - match the selector, the method throws an error. + first argument to `expression`. If no elements match the selector, the method throws an error. If `expression` returns a [Promise], then `element_handle.eval_on_selector()` would wait for the promise to resolve and return its value. @@ -2815,7 +2880,7 @@ async def eval_on_selector( Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. expression : str JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. @@ -2841,8 +2906,7 @@ async def eval_on_selector_all( Returns the return value of `expression`. The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array - of matched elements as a first argument to `expression`. See [Working with selectors](https://playwright.dev/python/docs/selectors) for more - details. + of matched elements as a first argument to `expression`. If `expression` returns a [Promise], then `element_handle.eval_on_selector_all()` would wait for the promise to resolve and return its value. @@ -2869,7 +2933,7 @@ async def eval_on_selector_all( Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. expression : str JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. @@ -2967,7 +3031,7 @@ async def wait_for_selector( Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. state : Union["attached", "detached", "hidden", "visible", None] Defaults to `'visible'`. Can be either: - `'attached'` - wait for element to be present in DOM. @@ -3639,13 +3703,13 @@ async def query_selector( **NOTE** The use of `ElementHandle` is discouraged, use `Locator` objects and web-first assertions instead. - The method finds an element matching the specified selector within the frame. See - [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements match the selector, returns `null`. + The method finds an element matching the specified selector within the frame. If no elements match the selector, + returns `null`. Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3666,13 +3730,13 @@ async def query_selector_all(self, selector: str) -> typing.List["ElementHandle" **NOTE** The use of `ElementHandle` is discouraged, use `Locator` objects instead. - The method finds all elements matching the specified selector within the frame. See - [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements match the selector, returns empty array. + The method finds all elements matching the specified selector within the frame. If no elements match the selector, + returns empty array. Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. Returns ------- @@ -3749,7 +3813,7 @@ def run(playwright): Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3791,7 +3855,7 @@ async def is_checked( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3825,7 +3889,7 @@ async def is_disabled( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3859,7 +3923,7 @@ async def is_editable( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3893,7 +3957,7 @@ async def is_enabled( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3928,7 +3992,7 @@ async def is_hidden( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -3961,7 +4025,7 @@ async def is_visible( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. strict : Union[bool, None] When true, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. @@ -4033,7 +4097,7 @@ async def dispatch_event( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. type : str DOM event type: `"click"`, `"dragstart"`, etc. event_init : Union[Dict, None] @@ -4069,8 +4133,7 @@ async def eval_on_selector( Returns the return value of `expression`. The method finds an element matching the specified selector within the frame and passes it as a first argument to - `expression`. See [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. If no elements match the selector, - the method throws an error. + `expression`. If no elements match the selector, the method throws an error. If `expression` returns a [Promise], then `frame.eval_on_selector()` would wait for the promise to resolve and return its value. @@ -4092,7 +4155,7 @@ async def eval_on_selector( Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. expression : str JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. @@ -4124,7 +4187,7 @@ async def eval_on_selector_all( Returns the return value of `expression`. The method finds all elements matching the specified selector within the frame and passes an array of matched - elements as a first argument to `expression`. See [Working with selectors](https://playwright.dev/python/docs/selectors) for more details. + elements as a first argument to `expression`. If `expression` returns a [Promise], then `frame.eval_on_selector_all()` would wait for the promise to resolve and return its value. @@ -4142,7 +4205,7 @@ async def eval_on_selector_all( Parameters ---------- selector : str - A selector to query for. See [working with selectors](../selectors.md) for more details. + A selector to query for. expression : str JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. @@ -4325,7 +4388,7 @@ async def click( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. modifiers : Union[List[Union["Alt", "Control", "Meta", "Shift"]], None] Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current modifiers back. If not specified, currently pressed modifiers are used. @@ -4407,7 +4470,7 @@ async def dblclick( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. modifiers : Union[List[Union["Alt", "Control", "Meta", "Shift"]], None] Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current modifiers back. If not specified, currently pressed modifiers are used. @@ -4483,7 +4546,7 @@ async def tap( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. modifiers : Union[List[Union["Alt", "Control", "Meta", "Shift"]], None] Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current modifiers back. If not specified, currently pressed modifiers are used. @@ -4547,7 +4610,7 @@ async def fill( ---------- selector : str A selector to search for an element. If there are multiple elements satisfying the selector, the first will be - used. See [working with selectors](../selectors.md) for more details. + used. value : str Value to fill for the ``, `