Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .claude/skills/playwright-roll/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: playwright-roll
description: Roll Playwright Python to a new version
---

Help the user roll to a new version of Playwright.
../../../ROLLING.md contains general instructions and scripts.

Start with updating the version and generating the API to see the state of things.

Afterwards, work through the list of changes that need to be backported.
You can find a list of pull requests that might need to be taking into account in the issue titled "Backport changes".
Work through them one-by-one and check off the items that you have handled.
Not all of them will be relevant, some might have partially been reverted, etc. - so feel free to check with the upstream release branch.

Rolling includes:
- updating client implementation to match changes in the upstream JS implementation (see ../playwright/packages/playwright-core/src/client)
- adding a couple of new tests to verify new/changed functionality

## Tips & Tricks
- Project checkouts are in the parent directory (`../`).
- when updating checkboxes, store the issue content into /tmp and edit it there, then update the issue based on the file
- use the "gh" cli to interact with GitHub
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 -->143.0.7499.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Chromium <!-- GEN:chromium-version -->145.0.7632.6<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit <!-- GEN:webkit-version -->26.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->144.0.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->146.0.1<!-- GEN:stop --> | ✅ | ✅ | ✅ |

## Documentation

Expand Down
3 changes: 1 addition & 2 deletions playwright/_impl/_browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ async def launch(
timeout: float = None,
env: Env = None,
headless: bool = None,
devtools: bool = None,
proxy: ProxySettings = None,
downloadsPath: Union[str, Path] = None,
slowMo: float = None,
Expand Down Expand Up @@ -118,7 +117,6 @@ async def launch_persistent_context(
timeout: float = None,
env: Env = None,
headless: bool = None,
devtools: bool = None,
proxy: ProxySettings = None,
downloadsPath: Union[str, Path] = None,
slowMo: float = None,
Expand Down Expand Up @@ -200,6 +198,7 @@ async def connect_over_cdp(
timeout: float = None,
slowMo: float = None,
headers: Dict[str, str] = None,
isLocal: bool = None,
) -> Browser:
params = locals_to_params(locals())
if params.get("headers"):
Expand Down
1 change: 1 addition & 0 deletions playwright/_impl/_console_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def type(self) -> Union[
Literal["startGroup"],
Literal["startGroupCollapsed"],
Literal["table"],
Literal["time"],
Literal["timeEnd"],
Literal["trace"],
Literal["warning"],
Expand Down
40 changes: 17 additions & 23 deletions playwright/async_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,12 @@ async def handle(route, request):
`route.continue_()` will immediately send the request to the network, other matching handlers won't be
invoked. Use `route.fallback()` If you want next matching handler in the chain to be invoked.

**NOTE** The `Cookie` header cannot be overridden using this method. If a value is provided, it will be ignored,
and the cookie will be loaded from the browser's cookie store. To set custom cookies, use
`browser_context.add_cookies()`.
**NOTE** Some request headers are **forbidden** and cannot be overridden (for example, `Cookie`, `Host`,
`Content-Length` and others, see
[this MDN page](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header) for full list). If an
override is provided for a forbidden header, it will be ignored and the original request header will be used.

To set custom cookies, use `browser_context.add_cookies()`.

Parameters
----------
Expand Down Expand Up @@ -7039,6 +7042,7 @@ def type(
Literal["startGroup"],
Literal["startGroupCollapsed"],
Literal["table"],
Literal["time"],
Literal["timeEnd"],
Literal["trace"],
Literal["warning"],
Expand All @@ -7047,7 +7051,7 @@ def type(

Returns
-------
Union["assert", "clear", "count", "debug", "dir", "dirxml", "endGroup", "error", "info", "log", "profile", "profileEnd", "startGroup", "startGroupCollapsed", "table", "timeEnd", "trace", "warning"]
Union["assert", "clear", "count", "debug", "dir", "dirxml", "endGroup", "error", "info", "log", "profile", "profileEnd", "startGroup", "startGroupCollapsed", "table", "time", "timeEnd", "trace", "warning"]
"""
return mapping.from_maybe_impl(self._impl_obj.type)

Expand Down Expand Up @@ -14440,7 +14444,6 @@ async def launch(
timeout: typing.Optional[float] = None,
env: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None,
headless: typing.Optional[bool] = None,
devtools: typing.Optional[bool] = None,
proxy: typing.Optional[ProxySettings] = None,
downloads_path: typing.Optional[typing.Union[pathlib.Path, str]] = None,
slow_mo: typing.Optional[float] = None,
Expand Down Expand Up @@ -14514,12 +14517,7 @@ async def launch(
headless : Union[bool, None]
Whether to run browser in headless mode. More details for
[Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true` unless the
`devtools` option is `true`.
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.
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true`.
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 @@ -14557,7 +14555,6 @@ async def launch(
timeout=timeout,
env=mapping.to_impl(env),
headless=headless,
devtools=devtools,
proxy=proxy,
downloadsPath=downloads_path,
slowMo=slow_mo,
Expand All @@ -14583,7 +14580,6 @@ async def launch_persistent_context(
timeout: typing.Optional[float] = None,
env: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None,
headless: typing.Optional[bool] = None,
devtools: typing.Optional[bool] = None,
proxy: typing.Optional[ProxySettings] = None,
downloads_path: typing.Optional[typing.Union[pathlib.Path, str]] = None,
slow_mo: typing.Optional[float] = None,
Expand Down Expand Up @@ -14691,12 +14687,7 @@ async def launch_persistent_context(
headless : Union[bool, None]
Whether to run browser in headless mode. More details for
[Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true` unless the
`devtools` option is `true`.
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.
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true`.
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 @@ -14858,7 +14849,6 @@ async def launch_persistent_context(
timeout=timeout,
env=mapping.to_impl(env),
headless=headless,
devtools=devtools,
proxy=proxy,
downloadsPath=downloads_path,
slowMo=slow_mo,
Expand Down Expand Up @@ -14908,6 +14898,7 @@ async def connect_over_cdp(
timeout: typing.Optional[float] = None,
slow_mo: typing.Optional[float] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
is_local: typing.Optional[bool] = None,
) -> "Browser":
"""BrowserType.connect_over_cdp

Expand Down Expand Up @@ -14942,6 +14933,9 @@ async def connect_over_cdp(
on. Defaults to 0.
headers : Union[Dict[str, str], None]
Additional HTTP headers to be sent with connect request. Optional.
is_local : Union[bool, None]
Tells Playwright that it runs on the same host as the CDP server. It will enable certain optimizations that rely
upon the file system being the same between Playwright and the Browser.

Returns
-------
Expand All @@ -14954,6 +14948,7 @@ async def connect_over_cdp(
timeout=timeout,
slowMo=slow_mo,
headers=mapping.to_impl(headers),
isLocal=is_local,
)
)

Expand Down Expand Up @@ -15397,8 +15392,7 @@ def description(self) -> typing.Optional[str]:
"""Locator.description

Returns locator description previously set with `locator.describe()`. Returns `null` if no custom
description has been set. Prefer `Locator.toString()` for a human-readable representation, as it uses the
description when available.
description has been set.

**Usage**

Expand Down Expand Up @@ -19176,7 +19170,7 @@ async def to_contain_text(
from playwright.async_api import expect

# ✓ Contains the right items in the right order
await expect(page.locator(\"ul > li\")).to_contain_text([\"Text 1\", \"Text 3\", \"Text 4\"])
await expect(page.locator(\"ul > li\")).to_contain_text([\"Text 1\", \"Text 3\"])

# ✖ Wrong order
await expect(page.locator(\"ul > li\")).to_contain_text([\"Text 3\", \"Text 2\"])
Expand Down
40 changes: 17 additions & 23 deletions playwright/sync_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,9 +960,12 @@ def handle(route, request):
`route.continue_()` will immediately send the request to the network, other matching handlers won't be
invoked. Use `route.fallback()` If you want next matching handler in the chain to be invoked.

**NOTE** The `Cookie` header cannot be overridden using this method. If a value is provided, it will be ignored,
and the cookie will be loaded from the browser's cookie store. To set custom cookies, use
`browser_context.add_cookies()`.
**NOTE** Some request headers are **forbidden** and cannot be overridden (for example, `Cookie`, `Host`,
`Content-Length` and others, see
[this MDN page](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header) for full list). If an
override is provided for a forbidden header, it will be ignored and the original request header will be used.

To set custom cookies, use `browser_context.add_cookies()`.

Parameters
----------
Expand Down Expand Up @@ -7129,6 +7132,7 @@ def type(
Literal["startGroup"],
Literal["startGroupCollapsed"],
Literal["table"],
Literal["time"],
Literal["timeEnd"],
Literal["trace"],
Literal["warning"],
Expand All @@ -7137,7 +7141,7 @@ def type(

Returns
-------
Union["assert", "clear", "count", "debug", "dir", "dirxml", "endGroup", "error", "info", "log", "profile", "profileEnd", "startGroup", "startGroupCollapsed", "table", "timeEnd", "trace", "warning"]
Union["assert", "clear", "count", "debug", "dir", "dirxml", "endGroup", "error", "info", "log", "profile", "profileEnd", "startGroup", "startGroupCollapsed", "table", "time", "timeEnd", "trace", "warning"]
"""
return mapping.from_maybe_impl(self._impl_obj.type)

Expand Down Expand Up @@ -14459,7 +14463,6 @@ def launch(
timeout: typing.Optional[float] = None,
env: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None,
headless: typing.Optional[bool] = None,
devtools: typing.Optional[bool] = None,
proxy: typing.Optional[ProxySettings] = None,
downloads_path: typing.Optional[typing.Union[pathlib.Path, str]] = None,
slow_mo: typing.Optional[float] = None,
Expand Down Expand Up @@ -14533,12 +14536,7 @@ def launch(
headless : Union[bool, None]
Whether to run browser in headless mode. More details for
[Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true` unless the
`devtools` option is `true`.
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.
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true`.
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 @@ -14577,7 +14575,6 @@ def launch(
timeout=timeout,
env=mapping.to_impl(env),
headless=headless,
devtools=devtools,
proxy=proxy,
downloadsPath=downloads_path,
slowMo=slow_mo,
Expand All @@ -14604,7 +14601,6 @@ def launch_persistent_context(
timeout: typing.Optional[float] = None,
env: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None,
headless: typing.Optional[bool] = None,
devtools: typing.Optional[bool] = None,
proxy: typing.Optional[ProxySettings] = None,
downloads_path: typing.Optional[typing.Union[pathlib.Path, str]] = None,
slow_mo: typing.Optional[float] = None,
Expand Down Expand Up @@ -14712,12 +14708,7 @@ def launch_persistent_context(
headless : Union[bool, None]
Whether to run browser in headless mode. More details for
[Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true` unless the
`devtools` option is `true`.
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.
[Firefox](https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/). Defaults to `true`.
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 @@ -14880,7 +14871,6 @@ def launch_persistent_context(
timeout=timeout,
env=mapping.to_impl(env),
headless=headless,
devtools=devtools,
proxy=proxy,
downloadsPath=downloads_path,
slowMo=slow_mo,
Expand Down Expand Up @@ -14931,6 +14921,7 @@ def connect_over_cdp(
timeout: typing.Optional[float] = None,
slow_mo: typing.Optional[float] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
is_local: typing.Optional[bool] = None,
) -> "Browser":
"""BrowserType.connect_over_cdp

Expand Down Expand Up @@ -14965,6 +14956,9 @@ def connect_over_cdp(
on. Defaults to 0.
headers : Union[Dict[str, str], None]
Additional HTTP headers to be sent with connect request. Optional.
is_local : Union[bool, None]
Tells Playwright that it runs on the same host as the CDP server. It will enable certain optimizations that rely
upon the file system being the same between Playwright and the Browser.

Returns
-------
Expand All @@ -14978,6 +14972,7 @@ def connect_over_cdp(
timeout=timeout,
slowMo=slow_mo,
headers=mapping.to_impl(headers),
isLocal=is_local,
)
)
)
Expand Down Expand Up @@ -15423,8 +15418,7 @@ def description(self) -> typing.Optional[str]:
"""Locator.description

Returns locator description previously set with `locator.describe()`. Returns `null` if no custom
description has been set. Prefer `Locator.toString()` for a human-readable representation, as it uses the
description when available.
description has been set.

**Usage**

Expand Down Expand Up @@ -19289,7 +19283,7 @@ def to_contain_text(
from playwright.sync_api import expect

# ✓ Contains the right items in the right order
expect(page.locator(\"ul > li\")).to_contain_text([\"Text 1\", \"Text 3\", \"Text 4\"])
expect(page.locator(\"ul > li\")).to_contain_text([\"Text 1\", \"Text 3\"])

# ✖ Wrong order
expect(page.locator(\"ul > li\")).to_contain_text([\"Text 3\", \"Text 2\"])
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import zipfile
from typing import Dict

driver_version = "1.57.0-beta-1764944708000"
driver_version = "1.58.0"

base_wheel_bundles = [
{
Expand Down
2 changes: 1 addition & 1 deletion tests/async/test_expect_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async def test_to_be_in_viewport_should_have_good_stack(
page: Page, server: Server
) -> None:
with pytest.raises(AssertionError) as exc_info:
await expect(page.locator("body")).not_to_be_in_viewport(timeout=100)
await expect(page.locator("body")).not_to_be_in_viewport(timeout=1000)
assert 'unexpected value "viewport ratio' in str(exc_info.value)


Expand Down
6 changes: 4 additions & 2 deletions tests/async/test_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ async def test_workers_should_report_network_activity_on_worker_creation(


async def test_workers_should_format_number_using_context_locale(
browser: Browser, server: Server
browser: Browser, server: Server, browser_name: str
) -> None:
context = await browser.new_context(locale="ru-RU")
page = await context.new_page()
Expand All @@ -199,7 +199,9 @@ async def test_workers_should_format_number_using_context_locale(
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"
)
worker = await worker_info.value
assert await worker.evaluate("() => (10000.20).toLocaleString()") == "10\u00a0000,2"
# https://github.com/microsoft/playwright/issues/38919
expected = "10,000.2" if browser_name == "firefox" else "10\u00a0000,2"
assert await worker.evaluate("() => (10000.20).toLocaleString()") == expected
await context.close()


Expand Down
2 changes: 1 addition & 1 deletion tests/sync/test_expect_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_to_be_in_viewport_should_respect_ratio_option(

def test_to_be_in_viewport_should_have_good_stack(page: Page, server: Server) -> None:
with pytest.raises(AssertionError) as exc_info:
expect(page.locator("body")).not_to_be_in_viewport(timeout=100)
expect(page.locator("body")).not_to_be_in_viewport(timeout=1000)
assert 'unexpected value "viewport ratio' in str(exc_info.value)


Expand Down
Loading