@@ -6879,6 +6879,18 @@ async def pause_at(self, time: typing.Union[float, str, datetime.datetime]) -> N
6879
6879
await page.clock.pause_at(\"2020-02-02\")
6880
6880
```
6881
6881
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
+
6882
6894
Parameters
6883
6895
----------
6884
6896
time : Union[datetime.datetime, float, str]
@@ -8036,7 +8048,7 @@ def set_default_timeout(self, timeout: float) -> None:
8036
8048
Parameters
8037
8049
----------
8038
8050
timeout : float
8039
- Maximum time in milliseconds
8051
+ Maximum time in milliseconds. Pass `0` to disable timeout.
8040
8052
"""
8041
8053
8042
8054
return mapping.from_maybe_impl(
@@ -11497,8 +11509,6 @@ async def pdf(
11497
11509
11498
11510
Returns the PDF buffer.
11499
11511
11500
- **NOTE** Generating a pdf is currently only supported in Chromium headless.
11501
-
11502
11512
`page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call
11503
11513
`page.emulate_media()` before calling `page.pdf()`:
11504
11514
@@ -12750,7 +12760,7 @@ def set_default_timeout(self, timeout: float) -> None:
12750
12760
Parameters
12751
12761
----------
12752
12762
timeout : float
12753
- Maximum time in milliseconds
12763
+ Maximum time in milliseconds. Pass `0` to disable timeout.
12754
12764
"""
12755
12765
12756
12766
return mapping.from_maybe_impl(
@@ -12858,9 +12868,13 @@ async def grant_permissions(
12858
12868
Parameters
12859
12869
----------
12860
12870
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:
12862
12877
- `'accelerometer'`
12863
- - `'accessibility-events'`
12864
12878
- `'ambient-light-sensor'`
12865
12879
- `'background-sync'`
12866
12880
- `'camera'`
@@ -14161,9 +14175,9 @@ async def close(self, *, reason: typing.Optional[str] = None) -> None:
14161
14175
In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from
14162
14176
the browser server.
14163
14177
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()`.
14167
14181
14168
14182
The `Browser` object itself is considered to be disposed and cannot be used anymore.
14169
14183
@@ -14346,7 +14360,7 @@ async def launch(
14346
14360
channel : Union[str, None]
14347
14361
Browser distribution channel.
14348
14362
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).
14350
14364
14351
14365
Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or
14352
14366
"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(
14504
14518
channel : Union[str, None]
14505
14519
Browser distribution channel.
14506
14520
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).
14508
14522
14509
14523
Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or
14510
14524
"msedge-canary" to use branded [Google Chrome and Microsoft Edge](../browsers.md#google-chrome--microsoft-edge).
@@ -15522,7 +15536,6 @@ async def dispatch_event(
15522
15536
You can also specify `JSHandle` as the property value if you want live objects to be passed into the event:
15523
15537
15524
15538
```py
15525
- # note you can only create data_transfer in chromium and firefox
15526
15539
data_transfer = await page.evaluate_handle(\"new DataTransfer()\")
15527
15540
await locator.dispatch_event(\"#source\", \"dragstart\", {\"dataTransfer\": data_transfer})
15528
15541
```
@@ -16445,18 +16458,22 @@ def or_(self, locator: "Locator") -> "Locator":
16445
16458
16446
16459
Creates a locator matching all elements that match one or both of the two locators.
16447
16460
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 .
16450
16463
16451
16464
**Usage**
16452
16465
16453
16466
Consider a scenario where you'd like to click on a \"New email\" button, but sometimes a security settings dialog
16454
16467
shows up instead. In this case, you can wait for either a \"New email\" button, or a dialog and act accordingly.
16455
16468
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
+
16456
16473
```py
16457
16474
new_email = page.get_by_role(\"button\", name=\"New\")
16458
16475
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()
16460
16477
if (await dialog.is_visible()):
16461
16478
await page.get_by_role(\"button\", name=\"Dismiss\").click()
16462
16479
await new_email.click()
@@ -16877,7 +16894,9 @@ async def is_disabled(self, *, timeout: typing.Optional[float] = None) -> bool:
16877
16894
async def is_editable(self, *, timeout: typing.Optional[float] = None) -> bool:
16878
16895
"""Locator.is_editable
16879
16896
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.
16881
16900
16882
16901
**NOTE** If you need to assert that an element is editable, prefer `locator_assertions.to_be_editable()` to
16883
16902
avoid flakiness. See [assertions guide](https://playwright.dev/python/docs/test-assertions) for more details.
@@ -19056,24 +19075,26 @@ async def to_have_class(
19056
19075
) -> None:
19057
19076
"""LocatorAssertions.to_have_class
19058
19077
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:
19061
19080
19062
19081
**Usage**
19063
19082
19064
19083
```html
19065
- <div class='selected row' id='component'></div>
19084
+ <div class='middle selected row' id='component'></div>
19066
19085
```
19067
19086
19068
19087
```py
19069
19088
from playwright.async_api import expect
19070
19089
19071
19090
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\")
19074
19093
```
19075
19094
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:
19077
19098
19078
19099
```py
19079
19100
from playwright.async_api import expect
@@ -19656,6 +19677,7 @@ async def to_be_checked(
19656
19677
*,
19657
19678
timeout: typing.Optional[float] = None,
19658
19679
checked: typing.Optional[bool] = None,
19680
+ indeterminate: typing.Optional[bool] = None,
19659
19681
) -> None:
19660
19682
"""LocatorAssertions.to_be_checked
19661
19683
@@ -19675,11 +19697,18 @@ async def to_be_checked(
19675
19697
timeout : Union[float, None]
19676
19698
Time to retry the assertion for in milliseconds. Defaults to `5000`.
19677
19699
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.
19678
19705
"""
19679
19706
__tracebackhide__ = True
19680
19707
19681
19708
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
+ )
19683
19712
)
19684
19713
19685
19714
async def not_to_be_attached(
@@ -20373,6 +20402,72 @@ async def to_have_role(
20373
20402
await self._impl_obj.to_have_role(role=role, timeout=timeout)
20374
20403
)
20375
20404
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
+
20376
20471
async def not_to_have_role(
20377
20472
self,
20378
20473
role: Literal[
0 commit comments