Skip to content

Commit fb271bd

Browse files
authored
chore(roll): roll Playwright to v1.50 (#2726)
1 parent 4712d3f commit fb271bd

File tree

12 files changed

+538
-74
lines changed

12 files changed

+538
-74
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H
44

55
| | Linux | macOS | Windows |
66
| :--- | :---: | :---: | :---: |
7-
| Chromium <!-- GEN:chromium-version -->131.0.6778.33<!-- GEN:stop --> ||||
7+
| Chromium <!-- GEN:chromium-version -->133.0.6943.16<!-- GEN:stop --> ||||
88
| WebKit <!-- GEN:webkit-version -->18.2<!-- GEN:stop --> ||||
9-
| Firefox <!-- GEN:firefox-version -->132.0<!-- GEN:stop --> ||||
9+
| Firefox <!-- GEN:firefox-version -->134.0<!-- GEN:stop --> ||||
1010

1111
## Documentation
1212

playwright/_impl/_assertions.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -525,14 +525,22 @@ async def to_be_checked(
525525
self,
526526
timeout: float = None,
527527
checked: bool = None,
528+
indeterminate: bool = None,
528529
) -> None:
529530
__tracebackhide__ = True
530-
if checked is None:
531-
checked = True
532-
checked_string = "checked" if checked else "unchecked"
531+
expected_value = {}
532+
if indeterminate is not None:
533+
expected_value["indeterminate"] = indeterminate
534+
if checked is not None:
535+
expected_value["checked"] = checked
536+
checked_string: str
537+
if indeterminate:
538+
checked_string = "indeterminate"
539+
else:
540+
checked_string = "unchecked" if checked is False else "checked"
533541
await self._expect_impl(
534-
("to.be.checked" if checked else "to.be.unchecked"),
535-
FrameExpectOptions(timeout=timeout),
542+
"to.be.checked",
543+
FrameExpectOptions(timeout=timeout, expectedValue=expected_value),
536544
None,
537545
f"Locator expected to be {checked_string}",
538546
)
@@ -726,7 +734,9 @@ async def to_have_accessible_description(
726734
timeout: float = None,
727735
) -> None:
728736
__tracebackhide__ = True
729-
expected_values = to_expected_text_values([description], ignoreCase=ignoreCase)
737+
expected_values = to_expected_text_values(
738+
[description], ignoreCase=ignoreCase, normalize_white_space=True
739+
)
730740
await self._expect_impl(
731741
"to.have.accessible.description",
732742
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
@@ -750,7 +760,9 @@ async def to_have_accessible_name(
750760
timeout: float = None,
751761
) -> None:
752762
__tracebackhide__ = True
753-
expected_values = to_expected_text_values([name], ignoreCase=ignoreCase)
763+
expected_values = to_expected_text_values(
764+
[name], ignoreCase=ignoreCase, normalize_white_space=True
765+
)
754766
await self._expect_impl(
755767
"to.have.accessible.name",
756768
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
@@ -779,6 +791,34 @@ async def to_have_role(self, role: AriaRole, timeout: float = None) -> None:
779791
"Locator expected to have accessible role",
780792
)
781793

794+
async def to_have_accessible_error_message(
795+
self,
796+
errorMessage: Union[str, Pattern[str]],
797+
ignoreCase: bool = None,
798+
timeout: float = None,
799+
) -> None:
800+
__tracebackhide__ = True
801+
expected_values = to_expected_text_values(
802+
[errorMessage], ignoreCase=ignoreCase, normalize_white_space=True
803+
)
804+
await self._expect_impl(
805+
"to.have.accessible.error.message",
806+
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
807+
None,
808+
"Locator expected to have accessible error message",
809+
)
810+
811+
async def not_to_have_accessible_error_message(
812+
self,
813+
errorMessage: Union[str, Pattern[str]],
814+
ignoreCase: bool = None,
815+
timeout: float = None,
816+
) -> None:
817+
__tracebackhide__ = True
818+
await self._not.to_have_accessible_error_message(
819+
errorMessage=errorMessage, ignoreCase=ignoreCase, timeout=timeout
820+
)
821+
782822
async def not_to_have_role(self, role: AriaRole, timeout: float = None) -> None:
783823
__tracebackhide__ = True
784824
await self._not.to_have_role(role, timeout)

playwright/_impl/_network.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ def __init__(
131131
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
132132
) -> None:
133133
super().__init__(parent, type, guid, initializer)
134+
self._channel.mark_as_internal_type()
134135
self._redirected_from: Optional["Request"] = from_nullable_channel(
135136
initializer.get("redirectedFrom")
136137
)
@@ -767,6 +768,7 @@ def __init__(
767768
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
768769
) -> None:
769770
super().__init__(parent, type, guid, initializer)
771+
self._channel.mark_as_internal_type()
770772
self._request: Request = from_channel(self._initializer["request"])
771773
timing = self._initializer["timing"]
772774
self._request._timing["startTime"] = timing["startTime"]

playwright/async_api/_generated.py

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6879,6 +6879,18 @@ async def pause_at(self, time: typing.Union[float, str, datetime.datetime]) -> N
68796879
await page.clock.pause_at(\"2020-02-02\")
68806880
```
68816881

6882+
For best results, install the clock before navigating the page and set it to a time slightly before the intended
6883+
test time. This ensures that all timers run normally during page loading, preventing the page from getting stuck.
6884+
Once the page has fully loaded, you can safely use `clock.pause_at()` to pause the clock.
6885+
6886+
```py
6887+
# Initialize clock with some time before the test time and let the page load
6888+
# naturally. `Date.now` will progress as the timers fire.
6889+
await page.clock.install(time=datetime.datetime(2024, 12, 10, 8, 0, 0))
6890+
await page.goto(\"http://localhost:3333\")
6891+
await page.clock.pause_at(datetime.datetime(2024, 12, 10, 10, 0, 0))
6892+
```
6893+
68826894
Parameters
68836895
----------
68846896
time : Union[datetime.datetime, float, str]
@@ -8036,7 +8048,7 @@ def set_default_timeout(self, timeout: float) -> None:
80368048
Parameters
80378049
----------
80388050
timeout : float
8039-
Maximum time in milliseconds
8051+
Maximum time in milliseconds. Pass `0` to disable timeout.
80408052
"""
80418053

80428054
return mapping.from_maybe_impl(
@@ -11497,8 +11509,6 @@ async def pdf(
1149711509

1149811510
Returns the PDF buffer.
1149911511

11500-
**NOTE** Generating a pdf is currently only supported in Chromium headless.
11501-
1150211512
`page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call
1150311513
`page.emulate_media()` before calling `page.pdf()`:
1150411514

@@ -12750,7 +12760,7 @@ def set_default_timeout(self, timeout: float) -> None:
1275012760
Parameters
1275112761
----------
1275212762
timeout : float
12753-
Maximum time in milliseconds
12763+
Maximum time in milliseconds. Pass `0` to disable timeout.
1275412764
"""
1275512765

1275612766
return mapping.from_maybe_impl(
@@ -12858,9 +12868,13 @@ async def grant_permissions(
1285812868
Parameters
1285912869
----------
1286012870
permissions : Sequence[str]
12861-
A permission or an array of permissions to grant. Permissions can be one of the following values:
12871+
A list of permissions to grant.
12872+
12873+
**NOTE** Supported permissions differ between browsers, and even between different versions of the same browser.
12874+
Any permission may stop working after an update.
12875+
12876+
Here are some permissions that may be supported by some browsers:
1286212877
- `'accelerometer'`
12863-
- `'accessibility-events'`
1286412878
- `'ambient-light-sensor'`
1286512879
- `'background-sync'`
1286612880
- `'camera'`
@@ -14161,9 +14175,9 @@ async def close(self, *, reason: typing.Optional[str] = None) -> None:
1416114175
In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from
1416214176
the browser server.
1416314177

14164-
**NOTE** This is similar to force quitting the browser. Therefore, you should call `browser_context.close()`
14165-
on any `BrowserContext`'s you explicitly created earlier with `browser.new_context()` **before** calling
14166-
`browser.close()`.
14178+
**NOTE** This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close
14179+
events, call `browser_context.close()` on any `BrowserContext` instances you explicitly created earlier
14180+
using `browser.new_context()` **before** calling `browser.close()`.
1416714181

1416814182
The `Browser` object itself is considered to be disposed and cannot be used anymore.
1416914183

@@ -14346,7 +14360,7 @@ async def launch(
1434614360
channel : Union[str, None]
1434714361
Browser distribution channel.
1434814362

14349-
Use "chromium" to [opt in to new headless mode](../browsers.md#opt-in-to-new-headless-mode).
14363+
Use "chromium" to [opt in to new headless mode](../browsers.md#chromium-new-headless-mode).
1435014364

1435114365
Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or
1435214366
"msedge-canary" to use branded [Google Chrome and Microsoft Edge](../browsers.md#google-chrome--microsoft-edge).
@@ -14504,7 +14518,7 @@ async def launch_persistent_context(
1450414518
channel : Union[str, None]
1450514519
Browser distribution channel.
1450614520

14507-
Use "chromium" to [opt in to new headless mode](../browsers.md#opt-in-to-new-headless-mode).
14521+
Use "chromium" to [opt in to new headless mode](../browsers.md#chromium-new-headless-mode).
1450814522

1450914523
Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or
1451014524
"msedge-canary" to use branded [Google Chrome and Microsoft Edge](../browsers.md#google-chrome--microsoft-edge).
@@ -15522,7 +15536,6 @@ async def dispatch_event(
1552215536
You can also specify `JSHandle` as the property value if you want live objects to be passed into the event:
1552315537

1552415538
```py
15525-
# note you can only create data_transfer in chromium and firefox
1552615539
data_transfer = await page.evaluate_handle(\"new DataTransfer()\")
1552715540
await locator.dispatch_event(\"#source\", \"dragstart\", {\"dataTransfer\": data_transfer})
1552815541
```
@@ -16445,18 +16458,22 @@ def or_(self, locator: "Locator") -> "Locator":
1644516458

1644616459
Creates a locator matching all elements that match one or both of the two locators.
1644716460

16448-
Note that when both locators match something, the resulting locator will have multiple matches and violate
16449-
[locator strictness](https://playwright.dev/python/docs/locators#strictness) guidelines.
16461+
Note that when both locators match something, the resulting locator will have multiple matches, potentially causing
16462+
a [locator strictness](https://playwright.dev/python/docs/locators#strictness) violation.
1645016463

1645116464
**Usage**
1645216465

1645316466
Consider a scenario where you'd like to click on a \"New email\" button, but sometimes a security settings dialog
1645416467
shows up instead. In this case, you can wait for either a \"New email\" button, or a dialog and act accordingly.
1645516468

16469+
**NOTE** If both \"New email\" button and security dialog appear on screen, the \"or\" locator will match both of them,
16470+
possibly throwing the [\"strict mode violation\" error](https://playwright.dev/python/docs/locators#strictness). In this case, you can use
16471+
`locator.first()` to only match one of them.
16472+
1645616473
```py
1645716474
new_email = page.get_by_role(\"button\", name=\"New\")
1645816475
dialog = page.get_by_text(\"Confirm security settings\")
16459-
await expect(new_email.or_(dialog)).to_be_visible()
16476+
await expect(new_email.or_(dialog).first).to_be_visible()
1646016477
if (await dialog.is_visible()):
1646116478
await page.get_by_role(\"button\", name=\"Dismiss\").click()
1646216479
await new_email.click()
@@ -16877,7 +16894,9 @@ async def is_disabled(self, *, timeout: typing.Optional[float] = None) -> bool:
1687716894
async def is_editable(self, *, timeout: typing.Optional[float] = None) -> bool:
1687816895
"""Locator.is_editable
1687916896

16880-
Returns whether the element is [editable](https://playwright.dev/python/docs/actionability#editable).
16897+
Returns whether the element is [editable](https://playwright.dev/python/docs/actionability#editable). If the target element is not an `<input>`,
16898+
`<textarea>`, `<select>`, `[contenteditable]` and does not have a role allowing `[aria-readonly]`, this method
16899+
throws an error.
1688116900

1688216901
**NOTE** If you need to assert that an element is editable, prefer `locator_assertions.to_be_editable()` to
1688316902
avoid flakiness. See [assertions guide](https://playwright.dev/python/docs/test-assertions) for more details.
@@ -19056,24 +19075,26 @@ async def to_have_class(
1905619075
) -> None:
1905719076
"""LocatorAssertions.to_have_class
1905819077

19059-
Ensures the `Locator` points to an element with given CSS classes. This needs to be a full match or using a relaxed
19060-
regular expression.
19078+
Ensures the `Locator` points to an element with given CSS classes. When a string is provided, it must fully match
19079+
the element's `class` attribute. To match individual classes or perform partial matches, use a regular expression:
1906119080

1906219081
**Usage**
1906319082

1906419083
```html
19065-
<div class='selected row' id='component'></div>
19084+
<div class='middle selected row' id='component'></div>
1906619085
```
1906719086

1906819087
```py
1906919088
from playwright.async_api import expect
1907019089

1907119090
locator = page.locator(\"#component\")
19072-
await expect(locator).to_have_class(re.compile(r\"selected\"))
19073-
await expect(locator).to_have_class(\"selected row\")
19091+
await expect(locator).to_have_class(re.compile(r\"(^|\\\\s)selected(\\\\s|$)\"))
19092+
await expect(locator).to_have_class(\"middle selected row\")
1907419093
```
1907519094

19076-
Note that if array is passed as an expected value, entire lists of elements can be asserted:
19095+
When an array is passed, the method asserts that the list of elements located matches the corresponding list of
19096+
expected class values. Each element's class attribute is matched against the corresponding string or regular
19097+
expression in the array:
1907719098

1907819099
```py
1907919100
from playwright.async_api import expect
@@ -19656,6 +19677,7 @@ async def to_be_checked(
1965619677
*,
1965719678
timeout: typing.Optional[float] = None,
1965819679
checked: typing.Optional[bool] = None,
19680+
indeterminate: typing.Optional[bool] = None,
1965919681
) -> None:
1966019682
"""LocatorAssertions.to_be_checked
1966119683

@@ -19675,11 +19697,18 @@ async def to_be_checked(
1967519697
timeout : Union[float, None]
1967619698
Time to retry the assertion for in milliseconds. Defaults to `5000`.
1967719699
checked : Union[bool, None]
19700+
Provides state to assert for. Asserts for input to be checked by default. This option can't be used when
19701+
`indeterminate` is set to true.
19702+
indeterminate : Union[bool, None]
19703+
Asserts that the element is in the indeterminate (mixed) state. Only supported for checkboxes and radio buttons.
19704+
This option can't be true when `checked` is provided.
1967819705
"""
1967919706
__tracebackhide__ = True
1968019707

1968119708
return mapping.from_maybe_impl(
19682-
await self._impl_obj.to_be_checked(timeout=timeout, checked=checked)
19709+
await self._impl_obj.to_be_checked(
19710+
timeout=timeout, checked=checked, indeterminate=indeterminate
19711+
)
1968319712
)
1968419713

1968519714
async def not_to_be_attached(
@@ -20373,6 +20402,72 @@ async def to_have_role(
2037320402
await self._impl_obj.to_have_role(role=role, timeout=timeout)
2037420403
)
2037520404

20405+
async def to_have_accessible_error_message(
20406+
self,
20407+
error_message: typing.Union[str, typing.Pattern[str]],
20408+
*,
20409+
ignore_case: typing.Optional[bool] = None,
20410+
timeout: typing.Optional[float] = None,
20411+
) -> None:
20412+
"""LocatorAssertions.to_have_accessible_error_message
20413+
20414+
Ensures the `Locator` points to an element with a given
20415+
[aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
20416+
20417+
**Usage**
20418+
20419+
```py
20420+
locator = page.get_by_test_id(\"username-input\")
20421+
await expect(locator).to_have_accessible_error_message(\"Username is required.\")
20422+
```
20423+
20424+
Parameters
20425+
----------
20426+
error_message : Union[Pattern[str], str]
20427+
Expected accessible error message.
20428+
ignore_case : Union[bool, None]
20429+
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
20430+
expression flag if specified.
20431+
timeout : Union[float, None]
20432+
Time to retry the assertion for in milliseconds. Defaults to `5000`.
20433+
"""
20434+
__tracebackhide__ = True
20435+
20436+
return mapping.from_maybe_impl(
20437+
await self._impl_obj.to_have_accessible_error_message(
20438+
errorMessage=error_message, ignoreCase=ignore_case, timeout=timeout
20439+
)
20440+
)
20441+
20442+
async def not_to_have_accessible_error_message(
20443+
self,
20444+
error_message: typing.Union[str, typing.Pattern[str]],
20445+
*,
20446+
ignore_case: typing.Optional[bool] = None,
20447+
timeout: typing.Optional[float] = None,
20448+
) -> None:
20449+
"""LocatorAssertions.not_to_have_accessible_error_message
20450+
20451+
The opposite of `locator_assertions.to_have_accessible_error_message()`.
20452+
20453+
Parameters
20454+
----------
20455+
error_message : Union[Pattern[str], str]
20456+
Expected accessible error message.
20457+
ignore_case : Union[bool, None]
20458+
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
20459+
expression flag if specified.
20460+
timeout : Union[float, None]
20461+
Time to retry the assertion for in milliseconds. Defaults to `5000`.
20462+
"""
20463+
__tracebackhide__ = True
20464+
20465+
return mapping.from_maybe_impl(
20466+
await self._impl_obj.not_to_have_accessible_error_message(
20467+
errorMessage=error_message, ignoreCase=ignore_case, timeout=timeout
20468+
)
20469+
)
20470+
2037620471
async def not_to_have_role(
2037720472
self,
2037820473
role: Literal[

0 commit comments

Comments
 (0)