Skip to content

Commit

Permalink
feat(roll): roll Playwright to 1.43.0-beta-1711484700000 (#2381)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxschmitt committed Mar 27, 2024
1 parent 6a84c65 commit 7e5f197
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 37 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->123.0.6312.4<!-- GEN:stop --> ||||
| Chromium <!-- GEN:chromium-version -->124.0.6367.8<!-- GEN:stop --> ||||
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->123.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->124.0<!-- GEN:stop --> ||||

## Documentation

Expand Down
31 changes: 29 additions & 2 deletions playwright/_impl/_browser_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
)
from playwright._impl._network import Request, Response, Route, serialize_headers
from playwright._impl._page import BindingCall, Page, Worker
from playwright._impl._str_utils import escape_regex_flags
from playwright._impl._tracing import Tracing
from playwright._impl._waiter import Waiter
from playwright._impl._web_error import WebError
Expand Down Expand Up @@ -302,8 +303,34 @@ async def cookies(self, urls: Union[str, Sequence[str]] = None) -> List[Cookie]:
async def add_cookies(self, cookies: Sequence[SetCookieParam]) -> None:
await self._channel.send("addCookies", dict(cookies=cookies))

async def clear_cookies(self) -> None:
await self._channel.send("clearCookies")
async def clear_cookies(
self,
name: Union[str, Pattern[str]] = None,
domain: Union[str, Pattern[str]] = None,
path: Union[str, Pattern[str]] = None,
) -> None:
await self._channel.send(
"clearCookies",
{
"name": name if isinstance(name, str) else None,
"nameRegexSource": name.pattern if isinstance(name, Pattern) else None,
"nameRegexFlags": escape_regex_flags(name)
if isinstance(name, Pattern)
else None,
"domain": domain if isinstance(domain, str) else None,
"domainRegexSource": domain.pattern
if isinstance(domain, Pattern)
else None,
"domainRegexFlags": escape_regex_flags(domain)
if isinstance(domain, Pattern)
else None,
"path": path if isinstance(path, str) else None,
"pathRegexSource": path.pattern if isinstance(path, Pattern) else None,
"pathRegexFlags": escape_regex_flags(path)
if isinstance(path, Pattern)
else None,
},
)

async def grant_permissions(
self, permissions: Sequence[str], origin: str = None
Expand Down
7 changes: 6 additions & 1 deletion playwright/_impl/_js_handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from urllib.parse import ParseResult, urlparse, urlunparse

from playwright._impl._connection import Channel, ChannelOwner, from_channel
from playwright._impl._errors import is_target_closed_error
from playwright._impl._map import Map

if TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -102,7 +103,11 @@ def as_element(self) -> Optional["ElementHandle"]:
return None

async def dispose(self) -> None:
await self._channel.send("dispose")
try:
await self._channel.send("dispose")
except Exception as e:
if not is_target_closed_error(e):
raise e

async def json_value(self) -> Any:
return parse_result(await self._channel.send("jsonValue"))
Expand Down
8 changes: 8 additions & 0 deletions playwright/_impl/_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ def last(self) -> "Locator":
def nth(self, index: int) -> "Locator":
return Locator(self._frame, f"{self._selector} >> nth={index}")

@property
def content_frame(self) -> "FrameLocator":
return FrameLocator(self._frame, self._selector)

def filter(
self,
hasText: Union[str, Pattern[str]] = None,
Expand Down Expand Up @@ -817,6 +821,10 @@ def first(self) -> "FrameLocator":
def last(self) -> "FrameLocator":
return FrameLocator(self._frame, f"{self._frame_selector} >> nth=-1")

@property
def owner(self) -> "Locator":
return Locator(self._frame, self._frame_selector)

def nth(self, index: int) -> "FrameLocator":
return FrameLocator(self._frame, f"{self._frame_selector} >> nth={index}")

Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def post_data_json(self) -> Optional[Any]:
if not post_data:
return None
content_type = self.headers["content-type"]
if content_type == "application/x-www-form-urlencoded":
if "application/x-www-form-urlencoded" in content_type:
return dict(parse.parse_qsl(post_data))
try:
return json.loads(post_data)
Expand Down
105 changes: 95 additions & 10 deletions playwright/async_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -5862,6 +5862,32 @@ def last(self) -> "FrameLocator":
"""
return mapping.from_impl(self._impl_obj.last)

@property
def owner(self) -> "Locator":
"""FrameLocator.owner

Returns a `Locator` object pointing to the same `iframe` as this frame locator.

Useful when you have a `FrameLocator` object obtained somewhere, and later on would like to interact with the
`iframe` element.

For a reverse operation, use `locator.content_frame()`.

**Usage**

```py
frame_locator = page.frame_locator(\"iframe[name=\\\"embedded\\\"]\")
# ...
locator = frame_locator.owner
await expect(locator).to_be_visible()
```

Returns
-------
Locator
"""
return mapping.from_impl(self._impl_obj.owner)

def locator(
self,
selector_or_locator: typing.Union["Locator", str],
Expand Down Expand Up @@ -11669,9 +11695,11 @@ async def add_locator_handler(
) -> None:
"""Page.add_locator_handler

When testing a web page, sometimes unexpected overlays like a coookie consent dialog appear and block actions you
want to automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time,
making them tricky to handle in automated tests.
**NOTE** This method is experimental and its behavior may change in the upcoming releases.

When testing a web page, sometimes unexpected overlays like a \"Sign up\" dialog appear and block actions you want to
automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time, making
them tricky to handle in automated tests.

This method lets you set up a special function, called a handler, that activates when it detects that overlay is
visible. The handler's job is to remove the overlay, allowing your test to continue as if the overlay wasn't there.
Expand All @@ -11681,7 +11709,9 @@ async def add_locator_handler(
a part of your normal test flow, instead of using `page.add_locator_handler()`.
- Playwright checks for the overlay every time before executing or retrying an action that requires an
[actionability check](https://playwright.dev/python/docs/actionability), or before performing an auto-waiting assertion check. When overlay
is visible, Playwright calls the handler first, and then proceeds with the action/assertion.
is visible, Playwright calls the handler first, and then proceeds with the action/assertion. Note that the
handler is only called when you perform an action/assertion - if the overlay becomes visible but you don't
perform any actions, the handler will not be triggered.
- The execution time of the handler counts towards the timeout of the action/assertion that executed the handler.
If your handler takes too long, it might cause timeouts.
- You can register multiple handlers. However, only a single handler will be running at a time. Make sure the
Expand All @@ -11699,13 +11729,13 @@ async def add_locator_handler(

**Usage**

An example that closes a cookie consent dialog when it appears:
An example that closes a \"Sign up to the newsletter\" dialog when it appears:

```py
# Setup the handler.
def handler():
page.get_by_role(\"button\", name=\"Reject all cookies\").click()
page.add_locator_handler(page.get_by_role(\"button\", name=\"Accept all cookies\"), handler)
page.get_by_role(\"button\", name=\"No thanks\").click()
page.add_locator_handler(page.get_by_text(\"Sign up to the newsletter\"), handler)

# Write the test as usual.
page.goto(\"https://example.com\")
Expand Down Expand Up @@ -12319,13 +12349,40 @@ async def add_cookies(self, cookies: typing.Sequence[SetCookieParam]) -> None:
await self._impl_obj.add_cookies(cookies=mapping.to_impl(cookies))
)

async def clear_cookies(self) -> None:
async def clear_cookies(
self,
*,
name: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None,
domain: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None,
path: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None
) -> None:
"""BrowserContext.clear_cookies

Clears context cookies.
Removes cookies from context. Accepts optional filter.

**Usage**

```py
await context.clear_cookies()
await context.clear_cookies(name=\"session-id\")
await context.clear_cookies(domain=\"my-origin.com\")
await context.clear_cookies(path=\"/api/v1\")
await context.clear_cookies(name=\"session-id\", domain=\"my-origin.com\")
```

Parameters
----------
name : Union[Pattern[str], str, None]
Only removes cookies with the given name.
domain : Union[Pattern[str], str, None]
Only removes cookies with the given domain.
path : Union[Pattern[str], str, None]
Only removes cookies with the given path.
"""

return mapping.from_maybe_impl(await self._impl_obj.clear_cookies())
return mapping.from_maybe_impl(
await self._impl_obj.clear_cookies(name=name, domain=domain, path=path)
)

async def grant_permissions(
self, permissions: typing.Sequence[str], *, origin: typing.Optional[str] = None
Expand Down Expand Up @@ -13798,6 +13855,7 @@ async def launch(
devtools : Union[bool, None]
**Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the
`headless` option will be set `false`.
Deprecated: Use [debugging tools](../debug.md) instead.
proxy : Union[{server: str, bypass: Union[str, None], username: Union[str, None], password: Union[str, None]}, None]
Network proxy settings.
downloads_path : Union[pathlib.Path, str, None]
Expand Down Expand Up @@ -13955,6 +14013,7 @@ async def launch_persistent_context(
devtools : Union[bool, None]
**Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the
`headless` option will be set `false`.
Deprecated: Use [debugging tools](../debug.md) instead.
proxy : Union[{server: str, bypass: Union[str, None], username: Union[str, None], password: Union[str, None]}, None]
Network proxy settings.
downloads_path : Union[pathlib.Path, str, None]
Expand Down Expand Up @@ -14538,6 +14597,32 @@ def last(self) -> "Locator":
"""
return mapping.from_impl(self._impl_obj.last)

@property
def content_frame(self) -> "FrameLocator":
"""Locator.content_frame

Returns a `FrameLocator` object pointing to the same `iframe` as this locator.

Useful when you have a `Locator` object obtained somewhere, and later on would like to interact with the content
inside the frame.

For a reverse operation, use `frame_locator.owner()`.

**Usage**

```py
locator = page.locator(\"iframe[name=\\\"embedded\\\"]\")
# ...
frame_locator = locator.content_frame
await frame_locator.get_by_role(\"button\").click()
```

Returns
-------
FrameLocator
"""
return mapping.from_impl(self._impl_obj.content_frame)

async def bounding_box(
self, *, timeout: typing.Optional[float] = None
) -> typing.Optional[FloatRect]:
Expand Down

0 comments on commit 7e5f197

Please sign in to comment.