Skip to content

Commit 9d7aded

Browse files
Skn0ttCopilot
andauthored
chore: roll to 1.62.0-alpha-1784109367000 (#3134)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 72fb0e0 commit 9d7aded

27 files changed

Lines changed: 1227 additions & 140 deletions

DRIVER_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.61.1-beta-1782139630000
1+
1.62.0-alpha-2026-07-16

NODE_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
24.17.0
1+
24.18.0

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 -->149.0.7827.55<!-- GEN:stop --> ||||
7+
| Chromium <!-- GEN:chromium-version -->151.0.7922.19<!-- GEN:stop --> ||||
88
| WebKit <!-- GEN:webkit-version -->26.5<!-- GEN:stop --> ||||
9-
| Firefox <!-- GEN:firefox-version -->151.0<!-- GEN:stop --> ||||
9+
| Firefox <!-- GEN:firefox-version -->152.0.4<!-- GEN:stop --> ||||
1010

1111
## Documentation
1212

playwright/_impl/_browser_context.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
WebSocketRouteHandlerCallback,
6767
async_readfile,
6868
async_writefile,
69+
create_task_and_ignore_exception,
6970
locals_to_params,
7071
parse_error,
7172
to_impl,
@@ -260,10 +261,11 @@ async def _on_route(self, route: Route) -> None:
260261
handled = await route_handler.handle(route)
261262
finally:
262263
if len(self._routes) == 0:
263-
asyncio.create_task(
264+
create_task_and_ignore_exception(
265+
self._loop,
264266
self._connection.wrap_api_call(
265267
lambda: self._update_interception_patterns(), True
266-
)
268+
),
267269
)
268270
if handled:
269271
return
@@ -497,6 +499,7 @@ async def route_from_har(
497499
update: bool = None,
498500
updateContent: Literal["attach", "embed"] = None,
499501
updateMode: HarMode = None,
502+
interceptAPIRequests: bool = None,
500503
) -> None:
501504
if update:
502505
await self._tracing._record_into_har(
@@ -515,6 +518,8 @@ async def route_from_har(
515518
)
516519
self._har_routers.append(router)
517520
await router.add_context_route(self)
521+
if interceptAPIRequests:
522+
await router.add_api_request_route(self)
518523

519524
async def _update_interception_patterns(self) -> None:
520525
patterns = RouteHandler.prepare_interception_patterns(self._routes)
@@ -586,10 +591,13 @@ async def _inner_close() -> None:
586591
await self._closed_future
587592

588593
async def storage_state(
589-
self, path: Union[str, Path] = None, indexedDB: bool = None
594+
self,
595+
path: Union[str, Path] = None,
596+
indexedDB: bool = None,
597+
credentials: bool = None,
590598
) -> StorageState:
591599
result = await self._channel.send_return_as_dict(
592-
"storageState", None, {"indexedDB": indexedDB}
600+
"storageState", None, {"indexedDB": indexedDB, "credentials": credentials}
593601
)
594602
if path:
595603
await async_writefile(path, json.dumps(result))
@@ -685,9 +693,9 @@ def _on_dialog(self, dialog: Dialog) -> None:
685693
# a) removing "dialog" listener subscription (client->server)
686694
# b) actual "dialog" event (server->client)
687695
if dialog.type == "beforeunload":
688-
asyncio.create_task(dialog.accept())
696+
create_task_and_ignore_exception(self._loop, dialog.accept())
689697
else:
690-
asyncio.create_task(dialog.dismiss())
698+
create_task_and_ignore_exception(self._loop, dialog.dismiss())
691699

692700
def _on_page_error(
693701
self, error: Error, page: Optional[Page], location: WebErrorLocation

playwright/_impl/_browser_type.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,20 @@ async def connect(
220220
) -> Browser:
221221
if slowMo is None:
222222
slowMo = 0
223+
if timeout is None:
224+
timeout = 0
223225

224226
headers = {**(headers if headers else {}), "x-playwright-browser": self.name}
225227
local_utils = self._connection.local_utils
226228
pipe_channel = (
227229
await local_utils._channel.send_return_as_dict(
228230
"connect",
229-
None,
231+
lambda t: t or 0,
230232
{
231233
"endpoint": endpoint,
232234
"headers": headers,
233235
"slowMo": slowMo,
234-
"timeout": timeout if timeout is not None else 0,
236+
"timeout": timeout,
235237
"exposeNetwork": exposeNetwork,
236238
},
237239
)
@@ -272,7 +274,7 @@ def handle_transport_close(reason: Optional[str]) -> None:
272274
playwright_future = connection.playwright_future
273275

274276
timeout_future = throw_on_timeout(
275-
timeout if timeout is not None else PLAYWRIGHT_MAX_DEADLINE,
277+
timeout if timeout else PLAYWRIGHT_MAX_DEADLINE,
276278
Error("Connection timed out"),
277279
)
278280
done, pending = await asyncio.wait(

playwright/_impl/_connection.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
List,
2929
Mapping,
3030
Optional,
31+
Tuple,
3132
TypedDict,
3233
Union,
3334
cast,
@@ -40,7 +41,12 @@
4041
import playwright._impl._impl_to_api_mapping
4142
from playwright._impl._errors import TargetClosedError, rewrite_error
4243
from playwright._impl._greenlets import EventGreenlet
43-
from playwright._impl._helper import Error, ParsedMessagePayload, parse_error
44+
from playwright._impl._helper import (
45+
Error,
46+
ParsedMessagePayload,
47+
create_task_and_ignore_exception,
48+
parse_error,
49+
)
4450
from playwright._impl._transport import Transport
4551

4652
if TYPE_CHECKING:
@@ -72,6 +78,19 @@ async def send(
7278
title,
7379
)
7480

81+
def send_may_fail(
82+
self,
83+
method: str,
84+
timeout_calculator: TimeoutCalculator,
85+
params: Dict = None,
86+
is_internal: bool = False,
87+
title: str = None,
88+
) -> None:
89+
create_task_and_ignore_exception(
90+
self._connection._loop,
91+
self.send(method, timeout_calculator, params, is_internal, title),
92+
)
93+
7594
async def send_return_as_dict(
7695
self,
7796
method: str,
@@ -95,11 +114,13 @@ def send_no_reply(
95114
title: str = None,
96115
) -> None:
97116
# No reply messages are used to e.g. __waitInfo__(after).
117+
augmented_params, timeout = _augment_params(params, timeout_calculator)
98118
self._connection.wrap_api_call_sync(
99119
lambda: self._connection._send_message_to_server(
100120
self._object,
101121
method,
102-
_augment_params(params, timeout_calculator),
122+
augmented_params,
123+
timeout,
103124
True,
104125
),
105126
is_internal,
@@ -117,8 +138,9 @@ async def _inner_send(
117138
error = self._connection._error
118139
self._connection._error = None
119140
raise error
141+
augmented_params, timeout = _augment_params(params, timeout_calculator)
120142
callback = self._connection._send_message_to_server(
121-
self._object, method, _augment_params(params, timeout_calculator)
143+
self._object, method, augmented_params, timeout
122144
)
123145
done, _ = await asyncio.wait(
124146
{
@@ -352,7 +374,12 @@ def set_is_tracing(self, is_tracing: bool) -> None:
352374
self._tracing_count -= 1
353375

354376
def _send_message_to_server(
355-
self, object: ChannelOwner, method: str, params: Dict, no_reply: bool = False
377+
self,
378+
object: ChannelOwner,
379+
method: str,
380+
params: Dict,
381+
timeout: float,
382+
no_reply: bool = False,
356383
) -> ProtocolCallback:
357384
if self._closed_error:
358385
raise self._closed_error
@@ -384,6 +411,7 @@ def _send_message_to_server(
384411
"wallTime": int(datetime.datetime.now().timestamp() * 1000),
385412
"apiName": stack_trace_information["apiName"],
386413
"internal": not stack_trace_information["apiName"],
414+
"timeout": timeout,
387415
}
388416
if location:
389417
metadata["location"] = location # type: ignore
@@ -652,12 +680,14 @@ def _extract_stack_trace_information_from_stack(
652680
def _augment_params(
653681
params: Optional[Dict],
654682
timeout_calculator: Optional[Callable[[Optional[float]], float]],
655-
) -> Dict:
683+
) -> Tuple[Dict, float]:
656684
if params is None:
657685
params = {}
686+
timeout_param = params.pop("timeout", None)
687+
timeout: float = 0
658688
if timeout_calculator:
659-
params["timeout"] = timeout_calculator(params.get("timeout"))
660-
return _filter_none(params)
689+
timeout = timeout_calculator(timeout_param)
690+
return _filter_none(params), timeout
661691

662692

663693
def _filter_none(d: Mapping) -> Dict:

playwright/_impl/_element_handle.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
import base64
16-
import mimetypes
1716
from pathlib import Path
1817
from typing import (
1918
TYPE_CHECKING,
@@ -122,6 +121,7 @@ async def hover(
122121
noWaitAfter: bool = None,
123122
force: bool = None,
124123
trial: bool = None,
124+
scroll: Literal["auto", "none"] = None,
125125
) -> None:
126126
await self._channel.send(
127127
"hover", self._frame._timeout, locals_to_params(locals())
@@ -139,6 +139,7 @@ async def click(
139139
noWaitAfter: bool = None,
140140
trial: bool = None,
141141
steps: int = None,
142+
scroll: Literal["auto", "none"] = None,
142143
) -> None:
143144
await self._channel.send(
144145
"click", self._frame._timeout, locals_to_params(locals())
@@ -155,6 +156,7 @@ async def dblclick(
155156
noWaitAfter: bool = None,
156157
trial: bool = None,
157158
steps: int = None,
159+
scroll: Literal["auto", "none"] = None,
158160
) -> None:
159161
await self._channel.send(
160162
"dblclick", self._frame._timeout, locals_to_params(locals())
@@ -187,6 +189,7 @@ async def tap(
187189
force: bool = None,
188190
noWaitAfter: bool = None,
189191
trial: bool = None,
192+
scroll: Literal["auto", "none"] = None,
190193
) -> None:
191194
await self._channel.send(
192195
"tap", self._frame._timeout, locals_to_params(locals())
@@ -267,20 +270,23 @@ async def set_checked(
267270
force: bool = None,
268271
noWaitAfter: bool = None,
269272
trial: bool = None,
273+
scroll: Literal["auto", "none"] = None,
270274
) -> None:
271275
if checked:
272276
await self.check(
273277
position=position,
274278
timeout=timeout,
275279
force=force,
276280
trial=trial,
281+
scroll=scroll,
277282
)
278283
else:
279284
await self.uncheck(
280285
position=position,
281286
timeout=timeout,
282287
force=force,
283288
trial=trial,
289+
scroll=scroll,
284290
)
285291

286292
async def check(
@@ -290,6 +296,7 @@ async def check(
290296
force: bool = None,
291297
noWaitAfter: bool = None,
292298
trial: bool = None,
299+
scroll: Literal["auto", "none"] = None,
293300
) -> None:
294301
await self._channel.send(
295302
"check", self._frame._timeout, locals_to_params(locals())
@@ -302,6 +309,7 @@ async def uncheck(
302309
force: bool = None,
303310
noWaitAfter: bool = None,
304311
trial: bool = None,
312+
scroll: Literal["auto", "none"] = None,
305313
) -> None:
306314
await self._channel.send(
307315
"uncheck", self._frame._timeout, locals_to_params(locals())
@@ -313,7 +321,7 @@ async def bounding_box(self) -> Optional[FloatRect]:
313321
async def screenshot(
314322
self,
315323
timeout: float = None,
316-
type: Literal["jpeg", "png"] = None,
324+
type: Literal["jpeg", "png", "webp"] = None,
317325
path: Union[str, Path] = None,
318326
quality: int = None,
319327
omitBackground: bool = None,
@@ -457,10 +465,16 @@ def convert_select_option_values(
457465
return dict(options=options, elements=elements)
458466

459467

460-
def determine_screenshot_type(path: Union[str, Path]) -> Literal["jpeg", "png"]:
461-
mime_type, _ = mimetypes.guess_type(path)
462-
if mime_type == "image/png":
468+
def determine_screenshot_type(path: Union[str, Path]) -> Literal["jpeg", "png", "webp"]:
469+
# Detect by file extension rather than mimetypes.guess_type, whose result is
470+
# OS-dependent (e.g. Windows does not register image/webp), mirroring
471+
# upstream's getMimeTypeForPath extension map:
472+
# https://github.com/microsoft/playwright/blob/e0e814deed7b0a4c4d2bdf98481e6be7419cda16/packages/isomorphic/mimeType.ts#L28
473+
suffix = Path(path).suffix.lower()
474+
if suffix == ".png":
463475
return "png"
464-
if mime_type == "image/jpeg":
476+
if suffix in (".jpeg", ".jpg"):
465477
return "jpeg"
466-
raise Error(f'Unsupported screenshot mime type for path "{path}": {mime_type}')
478+
if suffix == ".webp":
479+
return "webp"
480+
raise Error(f'path: unsupported mime type "{suffix}"')

playwright/_impl/_fetch.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
HttpCredentials,
3030
ProxySettings,
3131
RemoteAddr,
32+
ResourceTiming,
3233
SecurityDetails,
3334
ServerFilePayload,
3435
StorageState,
@@ -531,6 +532,24 @@ def headers(self) -> Headers:
531532
def headers_array(self) -> network.HeadersArray:
532533
return self._headers.headers_array()
533534

535+
@property
536+
def timing(self) -> ResourceTiming:
537+
return cast(
538+
ResourceTiming,
539+
{
540+
"startTime": -1,
541+
"domainLookupStart": -1,
542+
"domainLookupEnd": -1,
543+
"connectStart": -1,
544+
"secureConnectionStart": -1,
545+
"connectEnd": -1,
546+
"requestStart": -1,
547+
"responseStart": -1,
548+
**self._initializer.get("timing", {}),
549+
"responseEnd": self._initializer.get("responseEndTiming", -1),
550+
},
551+
)
552+
534553
async def body(self) -> bytes:
535554
try:
536555
result = await self._request._connection.wrap_api_call(

0 commit comments

Comments
 (0)