From 843d96e2e4db49274e20b591be0beee8a8c2b2a0 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 3 Nov 2022 14:28:26 -0700 Subject: [PATCH] chore(roll): roll Playwright to 1.28.0-alpha-nov-2-2022 (#1627) --- README.md | 4 +- playwright/_impl/_api_structures.py | 2 +- playwright/_impl/_browser.py | 10 +- playwright/_impl/_browser_type.py | 4 +- playwright/_impl/_element_handle.py | 9 + playwright/_impl/_frame.py | 42 +- playwright/_impl/_helper.py | 6 +- playwright/_impl/_locator.py | 28 +- playwright/_impl/_page.py | 33 +- playwright/_impl/_str_utils.py | 8 +- playwright/async_api/_generated.py | 559 +++++++++++++++---- playwright/sync_api/_generated.py | 567 ++++++++++++++++---- setup.py | 2 +- tests/async/test_accessibility.py | 70 --- tests/async/test_assertions.py | 9 - tests/async/test_browsertype_connect_cdp.py | 6 +- tests/async/test_element_handle.py | 10 + tests/async/test_fill.py | 30 ++ tests/async/test_locators.py | 47 ++ tests/async/test_network.py | 2 +- tests/async/test_page.py | 10 +- tests/async/test_popup.py | 12 +- tests/async/test_selectors_text.py | 35 ++ tests/async/test_tracing.py | 21 + tests/server.py | 12 +- tests/sync/test_accessibility.py | 72 --- tests/sync/test_assertions.py | 9 - tests/sync/test_browsertype_connect_cdp.py | 2 +- tests/sync/test_element_handle.py | 10 + tests/sync/test_fill.py | 55 ++ tests/sync/test_locators.py | 45 ++ tests/sync/test_network.py | 2 +- tests/sync/test_page.py | 8 + tests/sync/test_tracing.py | 21 + 34 files changed, 1355 insertions(+), 407 deletions(-) create mode 100644 tests/async/test_selectors_text.py create mode 100644 tests/sync/test_fill.py diff --git a/README.md b/README.md index 1afe5adfe..2731c3a28 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 107.0.5304.18 | ✅ | ✅ | ✅ | +| Chromium 108.0.5359.22 | ✅ | ✅ | ✅ | | WebKit 16.0 | ✅ | ✅ | ✅ | -| Firefox 105.0.1 | ✅ | ✅ | ✅ | +| Firefox 106.0 | ✅ | ✅ | ✅ | ## Documentation diff --git a/playwright/_impl/_api_structures.py b/playwright/_impl/_api_structures.py index 44a55cf7f..ddbf3576a 100644 --- a/playwright/_impl/_api_structures.py +++ b/playwright/_impl/_api_structures.py @@ -280,5 +280,5 @@ class FrameExpectResult(TypedDict): "tooltip", "tree", "treegrid", - "treeite", + "treeitem", ] diff --git a/playwright/_impl/_browser.py b/playwright/_impl/_browser.py index efe8de296..a59f96cc0 100644 --- a/playwright/_impl/_browser.py +++ b/playwright/_impl/_browser.py @@ -122,7 +122,7 @@ async def new_context( recordHarContent: HarContentPolicy = None, ) -> BrowserContext: params = locals_to_params(locals()) - await normalize_context_params(self._connection._is_sync, params) + await prepare_browser_context_params(params) channel = await self._channel.send("newContext", params) context = cast(BrowserContext, from_channel(channel)) @@ -219,7 +219,7 @@ async def stop_tracing(self) -> bytes: return base64.b64decode(encoded_binary) -async def normalize_context_params(is_sync: bool, params: Dict) -> None: +async def prepare_browser_context_params(params: Dict) -> None: if params.get("noViewport"): del params["noViewport"] params["noDefaultViewport"] = True @@ -242,3 +242,9 @@ async def normalize_context_params(is_sync: bool, params: Dict) -> None: params["storageState"] = json.loads( (await async_readfile(storageState)).decode() ) + if params.get("colorScheme", None) == "null": + params["colorScheme"] = "no-override" + if params.get("reducedMotion", None) == "null": + params["reducedMotion"] = "no-override" + if params.get("forcedColors", None) == "null": + params["forcedColors"] = "no-override" diff --git a/playwright/_impl/_browser_type.py b/playwright/_impl/_browser_type.py index 0eca2c6b7..aeeab8422 100644 --- a/playwright/_impl/_browser_type.py +++ b/playwright/_impl/_browser_type.py @@ -24,7 +24,7 @@ ViewportSize, ) from playwright._impl._api_types import Error -from playwright._impl._browser import Browser, normalize_context_params +from playwright._impl._browser import Browser, prepare_browser_context_params from playwright._impl._browser_context import BrowserContext from playwright._impl._connection import ( ChannelOwner, @@ -148,7 +148,7 @@ async def launch_persistent_context( ) -> BrowserContext: userDataDir = str(Path(userDataDir)) if userDataDir else "" params = locals_to_params(locals()) - await normalize_context_params(self._connection._is_sync, params) + await prepare_browser_context_params(params) normalize_launch_params(params) context = cast( BrowserContext, diff --git a/playwright/_impl/_element_handle.py b/playwright/_impl/_element_handle.py index 5803413dc..7e20dac1d 100644 --- a/playwright/_impl/_element_handle.py +++ b/playwright/_impl/_element_handle.py @@ -106,6 +106,7 @@ async def hover( modifiers: List[KeyboardModifier] = None, position: Position = None, timeout: float = None, + noWaitAfter: bool = None, force: bool = None, trial: bool = None, ) -> None: @@ -217,6 +218,14 @@ async def type( ) -> None: await self._channel.send("type", locals_to_params(locals())) + async def clear( + self, + timeout: float = None, + noWaitAfter: bool = None, + force: bool = None, + ) -> None: + await self.fill("", **locals_to_params(locals())) + async def press( self, key: str, diff --git a/playwright/_impl/_frame.py b/playwright/_impl/_frame.py index 879af3715..0f446b6f3 100644 --- a/playwright/_impl/_frame.py +++ b/playwright/_impl/_frame.py @@ -249,19 +249,23 @@ async def _wait_for_load_state_impl( raise Error( "state: expected one of (load|domcontentloaded|networkidle|commit)" ) - if state in self._load_states: - return wait_helper = self._setup_navigation_wait_helper("wait_for_load_state", timeout) - def handle_load_state_event(actual_state: str) -> bool: - wait_helper.log(f'"{actual_state}" event fired') - return actual_state == state + if state in self._load_states: + wait_helper.log(f' not waiting, "{state}" event already fired') + # TODO: align with upstream + wait_helper._fulfill(None) + else: - wait_helper.wait_for_event( - self._event_emitter, - "loadstate", - handle_load_state_event, - ) + def handle_load_state_event(actual_state: str) -> bool: + wait_helper.log(f'"{actual_state}" event fired') + return actual_state == state + + wait_helper.wait_for_event( + self._event_emitter, + "loadstate", + handle_load_state_event, + ) await wait_helper.result() async def frame_element(self) -> ElementHandle: @@ -618,6 +622,7 @@ async def hover( modifiers: List[KeyboardModifier] = None, position: Position = None, timeout: float = None, + noWaitAfter: bool = None, force: bool = None, strict: bool = None, trial: bool = None, @@ -789,5 +794,22 @@ async def set_checked( trial=trial, ) + async def clear( + self, + selector: str, + timeout: float = None, + noWaitAfter: bool = None, + force: bool = None, + strict: bool = None, + ) -> None: + await self.fill( + selector, + "", + timeout=timeout, + noWaitAfter=noWaitAfter, + force=force, + strict=strict, + ) + async def _highlight(self, selector: str) -> None: await self._channel.send("highlight", {"selector": selector}) diff --git a/playwright/_impl/_helper.py b/playwright/_impl/_helper.py index 919b57fe6..43b465c2d 100644 --- a/playwright/_impl/_helper.py +++ b/playwright/_impl/_helper.py @@ -60,9 +60,9 @@ Callable[["Route"], Any], Callable[["Route", "Request"], Any] ] -ColorScheme = Literal["dark", "light", "no-preference"] -ForcedColors = Literal["active", "none"] -ReducedMotion = Literal["no-preference", "reduce"] +ColorScheme = Literal["dark", "light", "no-preference", "null"] +ForcedColors = Literal["active", "none", "null"] +ReducedMotion = Literal["no-preference", "null", "reduce"] DocumentLoadState = Literal["commit", "domcontentloaded", "load", "networkidle"] KeyboardModifier = Literal["Alt", "Control", "Meta", "Shift"] MouseButton = Literal["left", "middle", "right"] diff --git a/playwright/_impl/_locator.py b/playwright/_impl/_locator.py index 830d68204..f1ef26186 100644 --- a/playwright/_impl/_locator.py +++ b/playwright/_impl/_locator.py @@ -79,10 +79,7 @@ def __init__( self._dispatcher_fiber = frame._connection._dispatcher_fiber if has_text: - text_selector = "text=" + escape_for_text_selector(has_text, exact=False) - self._selector += ( - f" >> internal:has={json.dumps(text_selector, ensure_ascii=False)}" - ) + self._selector += f" >> internal:has-text={escape_for_text_selector(has_text, exact=False)}" if has: if has._frame != frame: @@ -200,6 +197,14 @@ async def fill( params = locals_to_params(locals()) return await self._frame.fill(self._selector, strict=True, **params) + async def clear( + self, + timeout: float = None, + noWaitAfter: bool = None, + force: bool = None, + ) -> None: + await self.fill("", timeout=timeout, noWaitAfter=noWaitAfter, force=force) + def locator( self, selector: str, @@ -311,6 +316,16 @@ async def focus(self, timeout: float = None) -> None: params = locals_to_params(locals()) return await self._frame.focus(self._selector, strict=True, **params) + async def blur(self, timeout: float = None) -> None: + await self._frame._channel.send( + "blur", + { + "selector": self._selector, + "strict": True, + **locals_to_params(locals()), + }, + ) + async def count( self, ) -> int: @@ -345,6 +360,7 @@ async def hover( modifiers: List[KeyboardModifier] = None, position: Position = None, timeout: float = None, + noWaitAfter: bool = None, force: bool = None, trial: bool = None, ) -> None: @@ -762,7 +778,7 @@ def get_by_placeholder_selector( def get_by_text_selector(text: Union[str, Pattern[str]], exact: bool = None) -> str: - return "text=" + escape_for_text_selector(text, exact=exact) + return "internal:text=" + escape_for_text_selector(text, exact=exact) def get_by_role_selector( @@ -801,4 +817,4 @@ def get_by_role_selector( if pressed is not None: props.append(("pressed", str(pressed))) props_str = "".join([f"[{t[0]}={t[1]}]" for t in props]) - return f"role={role}{props_str}" + return f"internal:role={role}{props_str}" diff --git a/playwright/_impl/_page.py b/playwright/_impl/_page.py index 914f32537..52c31830f 100644 --- a/playwright/_impl/_page.py +++ b/playwright/_impl/_page.py @@ -550,7 +550,20 @@ async def emulate_media( reducedMotion: ReducedMotion = None, forcedColors: ForcedColors = None, ) -> None: - await self._channel.send("emulateMedia", locals_to_params(locals())) + params = locals_to_params(locals()) + if "colorScheme" in params: + params["colorScheme"] = ( + "no-override" if params["colorScheme"] == "null" else colorScheme + ) + if "reducedMotion" in params: + params["reducedMotion"] = ( + "no-override" if params["reducedMotion"] == "null" else reducedMotion + ) + if "forcedColors" in params: + params["forcedColors"] = ( + "no-override" if params["forcedColors"] == "null" else forcedColors + ) + await self._channel.send("emulateMedia", params) async def set_viewport_size(self, viewportSize: ViewportSize) -> None: self._viewport_size = viewportSize @@ -728,6 +741,23 @@ async def fill( ) -> None: return await self._main_frame.fill(**locals_to_params(locals())) + async def clear( + self, + selector: str, + timeout: float = None, + noWaitAfter: bool = None, + force: bool = None, + strict: bool = None, + ) -> None: + await self.fill( + selector, + "", + timeout=timeout, + noWaitAfter=noWaitAfter, + force=force, + strict=strict, + ) + def locator( self, selector: str, @@ -822,6 +852,7 @@ async def hover( modifiers: List[KeyboardModifier] = None, position: Position = None, timeout: float = None, + noWaitAfter: bool = None, force: bool = None, strict: bool = None, trial: bool = None, diff --git a/playwright/_impl/_str_utils.py b/playwright/_impl/_str_utils.py index e524df7f7..45c80184f 100644 --- a/playwright/_impl/_str_utils.py +++ b/playwright/_impl/_str_utils.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import re from typing import Pattern, Union @@ -43,12 +44,7 @@ def escape_for_text_selector( ) -> str: if isinstance(text, Pattern): return f"/{text.pattern}/{escape_regex_flags(text)}" - if exact: - return '"' + text.replace('"', '\\"') + '"' - if '"' in text or ">>" in text or text[0] == "/": - suffix = "" if case_sensitive else "i" - return "/" + re.sub(r"\s+", "\\\\s+", escape_for_regex(text)) + "/" + suffix - return text + return json.dumps(text) + ("s" if exact else "i") def escape_for_attribute_selector(value: str, exact: bool = None) -> str: diff --git a/playwright/async_api/_generated.py b/playwright/async_api/_generated.py index 6dd11cc60..842544448 100644 --- a/playwright/async_api/_generated.py +++ b/playwright/async_api/_generated.py @@ -1346,7 +1346,7 @@ async def evaluate( Parameters ---------- expression : str - JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is + JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. arg : Union[Any, None] Optional argument to pass to `expression`. @@ -1382,7 +1382,7 @@ async def evaluate_handle( Parameters ---------- expression : str - JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is + JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is automatically invoked. arg : Union[Any, None] Optional argument to pass to `expression`. @@ -1423,7 +1423,7 @@ async def get_properties(self) -> typing.Dict[str, "JSHandle"]: The method returns a map with **own property names** as keys and JSHandle instances for the property values. ```py - handle = await page.evaluate_handle(\"{window, document}\") + handle = await page.evaluate_handle(\"({window, document})\") properties = await handle.get_properties() window_handle = properties.get(\"window\") document_handle = properties.get(\"document\") @@ -1716,6 +1716,7 @@ async def hover( ] = None, position: typing.Optional[Position] = None, timeout: typing.Optional[float] = None, + no_wait_after: typing.Optional[bool] = None, force: typing.Optional[bool] = None, trial: typing.Optional[bool] = None ) -> None: @@ -1743,6 +1744,10 @@ async def hover( timeout : Union[float, None] Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods. + no_wait_after : Union[bool, None] + Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can + opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to + inaccessible pages. Defaults to `false`. force : Union[bool, None] Whether to bypass the [actionability](../actionability.md) checks. Defaults to `false`. trial : Union[bool, None] @@ -1755,6 +1760,7 @@ async def hover( modifiers=mapping.to_impl(modifiers), position=position, timeout=timeout, + noWaitAfter=no_wait_after, force=force, trial=trial, ) @@ -2222,6 +2228,42 @@ async def type( ) ) + async def clear( + self, + *, + timeout: typing.Optional[float] = None, + no_wait_after: typing.Optional[bool] = None, + force: typing.Optional[bool] = None + ) -> None: + """ElementHandle.clear + + This method waits for [actionability](https://playwright.dev/python/docs/actionability) checks, focuses the element, clears it and triggers an + `input` event after clearing. + + If the target element is not an ``, `