Skip to content

Commit c6cc4c9

Browse files
authored
chore(roll): roll Playwright to 1.45.0-alpha-2024-06-14 (#2464)
1 parent b331b8e commit c6cc4c9

29 files changed

+2055
-122
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 -->125.0.6422.26<!-- GEN:stop --> ||||
7+
| Chromium <!-- GEN:chromium-version -->127.0.6533.5<!-- GEN:stop --> ||||
88
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> ||||
9-
| Firefox <!-- GEN:firefox-version -->125.0.1<!-- GEN:stop --> ||||
9+
| Firefox <!-- GEN:firefox-version -->127.0<!-- GEN:stop --> ||||
1010

1111
## Documentation
1212

playwright/_impl/_api_structures.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class HttpCredentials(TypedDict, total=False):
6363
username: str
6464
password: str
6565
origin: Optional[str]
66+
send: Optional[Literal["always", "unauthorized"]]
6667

6768

6869
class LocalStorageEntry(TypedDict):

playwright/_impl/_browser_context.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
)
4040
from playwright._impl._artifact import Artifact
4141
from playwright._impl._cdp_session import CDPSession
42+
from playwright._impl._clock import Clock
4243
from playwright._impl._connection import (
4344
ChannelOwner,
4445
from_channel,
@@ -114,6 +115,7 @@ def __init__(
114115
self._tracing = cast(Tracing, from_channel(initializer["tracing"]))
115116
self._har_recorders: Dict[str, HarRecordingMetadata] = {}
116117
self._request: APIRequestContext = from_channel(initializer["requestContext"])
118+
self._clock = Clock(self)
117119
self._channel.on(
118120
"bindingCall",
119121
lambda params: self._on_binding(from_channel(params["binding"])),
@@ -519,6 +521,10 @@ async def close(self, reason: str = None) -> None:
519521
self._close_reason = reason
520522
self._close_was_called = True
521523

524+
await self._channel._connection.wrap_api_call(
525+
lambda: self.request.dispose(reason=reason), True
526+
)
527+
522528
async def _inner_close() -> None:
523529
for har_id, params in self._har_recorders.items():
524530
har = cast(
@@ -679,3 +685,7 @@ def tracing(self) -> Tracing:
679685
@property
680686
def request(self) -> "APIRequestContext":
681687
return self._request
688+
689+
@property
690+
def clock(self) -> Clock:
691+
return self._clock

playwright/_impl/_clock.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright (c) Microsoft Corporation.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import datetime
16+
from typing import TYPE_CHECKING, Dict, Union
17+
18+
if TYPE_CHECKING:
19+
from playwright._impl._browser_context import BrowserContext
20+
21+
22+
class Clock:
23+
def __init__(self, browser_context: "BrowserContext") -> None:
24+
self._browser_context = browser_context
25+
self._loop = browser_context._loop
26+
self._dispatcher_fiber = browser_context._dispatcher_fiber
27+
28+
async def install(self, time: Union[int, str, datetime.datetime] = None) -> None:
29+
await self._browser_context._channel.send(
30+
"clockInstall", parse_time(time) if time is not None else {}
31+
)
32+
33+
async def fast_forward(
34+
self,
35+
ticks: Union[int, str],
36+
) -> None:
37+
await self._browser_context._channel.send(
38+
"clockFastForward", parse_ticks(ticks)
39+
)
40+
41+
async def pause_at(
42+
self,
43+
time: Union[int, str, datetime.datetime],
44+
) -> None:
45+
await self._browser_context._channel.send("clockPauseAt", parse_time(time))
46+
47+
async def resume(
48+
self,
49+
) -> None:
50+
await self._browser_context._channel.send("clockResume")
51+
52+
async def run_for(
53+
self,
54+
ticks: Union[int, str],
55+
) -> None:
56+
await self._browser_context._channel.send("clockRunFor", parse_ticks(ticks))
57+
58+
async def set_fixed_time(
59+
self,
60+
time: Union[int, str, datetime.datetime],
61+
) -> None:
62+
await self._browser_context._channel.send("clockSetFixedTime", parse_time(time))
63+
64+
async def set_system_time(
65+
self,
66+
time: Union[int, str, datetime.datetime],
67+
) -> None:
68+
await self._browser_context._channel.send(
69+
"clockSetSystemTime", parse_time(time)
70+
)
71+
72+
73+
def parse_time(time: Union[int, str, datetime.datetime]) -> Dict[str, Union[int, str]]:
74+
if isinstance(time, int):
75+
return {"timeNumber": time}
76+
if isinstance(time, str):
77+
return {"timeString": time}
78+
return {"timeNumber": int(time.timestamp())}
79+
80+
81+
def parse_ticks(ticks: Union[int, str]) -> Dict[str, Union[int, str]]:
82+
if isinstance(ticks, int):
83+
return {"ticksNumber": ticks}
84+
return {"ticksString": ticks}

playwright/_impl/_fetch.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from playwright._impl._helper import (
3535
Error,
3636
NameValue,
37+
TargetClosedError,
3738
async_readfile,
3839
async_writefile,
3940
is_file_payload,
@@ -93,9 +94,16 @@ def __init__(
9394
) -> None:
9495
super().__init__(parent, type, guid, initializer)
9596
self._tracing: Tracing = from_channel(initializer["tracing"])
97+
self._close_reason: Optional[str] = None
9698

97-
async def dispose(self) -> None:
98-
await self._channel.send("dispose")
99+
async def dispose(self, reason: str = None) -> None:
100+
self._close_reason = reason
101+
try:
102+
await self._channel.send("dispose", {"reason": reason})
103+
except Error as e:
104+
if is_target_closed_error(e):
105+
return
106+
raise e
99107
self._tracing._reset_stack_counter()
100108

101109
async def delete(
@@ -313,6 +321,8 @@ async def _inner_fetch(
313321
ignoreHTTPSErrors: bool = None,
314322
maxRedirects: int = None,
315323
) -> "APIResponse":
324+
if self._close_reason:
325+
raise TargetClosedError(self._close_reason)
316326
assert (
317327
(1 if data else 0) + (1 if form else 0) + (1 if multipart else 0)
318328
) <= 1, "Only one of 'data', 'form' or 'multipart' can be specified"

playwright/_impl/_helper.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@
3737
from urllib.parse import urljoin
3838

3939
from playwright._impl._api_structures import NameValue
40-
from playwright._impl._errors import Error, TargetClosedError, TimeoutError
40+
from playwright._impl._errors import (
41+
Error,
42+
TargetClosedError,
43+
TimeoutError,
44+
is_target_closed_error,
45+
rewrite_error,
46+
)
4147
from playwright._impl._glob import glob_to_regex
4248
from playwright._impl._greenlets import RouteGreenlet
4349
from playwright._impl._str_utils import escape_regex_flags
@@ -287,6 +293,14 @@ async def handle(self, route: "Route") -> bool:
287293
# If the handler was stopped (without waiting for completion), we ignore all exceptions.
288294
if self._ignore_exception:
289295
return False
296+
if is_target_closed_error(e):
297+
# We are failing in the handler because the target has closed.
298+
# Give user a hint!
299+
optional_async_prefix = "await " if not self._is_sync else ""
300+
raise rewrite_error(
301+
e,
302+
f"\"{str(e)}\" while running route callback.\nConsider awaiting `{optional_async_prefix}page.unroute_all(behavior='ignoreErrors')`\nbefore the end of the test to ignore remaining routes in flight.",
303+
)
290304
raise e
291305
finally:
292306
handler_invocation.complete.set_result(None)

playwright/_impl/_network.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@ def __init__(
111111
self._fallback_overrides: SerializedFallbackOverrides = (
112112
SerializedFallbackOverrides()
113113
)
114-
base64_post_data = initializer.get("postData")
115-
if base64_post_data is not None:
116-
self._fallback_overrides.post_data_buffer = base64.b64decode(
117-
base64_post_data
118-
)
119114

120115
def __repr__(self) -> str:
121116
return f"<Request url={self.url!r} method={self.method!r}>"
@@ -159,9 +154,12 @@ async def sizes(self) -> RequestSizes:
159154
@property
160155
def post_data(self) -> Optional[str]:
161156
data = self._fallback_overrides.post_data_buffer
162-
if not data:
163-
return None
164-
return data.decode()
157+
if data:
158+
return data.decode()
159+
base64_post_data = self._initializer.get("postData")
160+
if base64_post_data is not None:
161+
return base64.b64decode(base64_post_data).decode()
162+
return None
165163

166164
@property
167165
def post_data_json(self) -> Optional[Any]:
@@ -178,7 +176,11 @@ def post_data_json(self) -> Optional[Any]:
178176

179177
@property
180178
def post_data_buffer(self) -> Optional[bytes]:
181-
return self._fallback_overrides.post_data_buffer
179+
if self._fallback_overrides.post_data_buffer:
180+
return self._fallback_overrides.post_data_buffer
181+
if self._initializer.get("postData"):
182+
return base64.b64decode(self._initializer["postData"])
183+
return None
182184

183185
async def response(self) -> Optional["Response"]:
184186
return from_nullable_channel(await self._channel.send("response"))

playwright/_impl/_page.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
ViewportSize,
4444
)
4545
from playwright._impl._artifact import Artifact
46+
from playwright._impl._clock import Clock
4647
from playwright._impl._connection import (
4748
ChannelOwner,
4849
from_channel,
@@ -336,6 +337,10 @@ def _on_video(self, params: Any) -> None:
336337
def context(self) -> "BrowserContext":
337338
return self._browser_context
338339

340+
@property
341+
def clock(self) -> Clock:
342+
return self._browser_context.clock
343+
339344
async def opener(self) -> Optional["Page"]:
340345
if self._opener and self._opener.is_closed():
341346
return None

0 commit comments

Comments
 (0)