Skip to content

Commit bf6e6f5

Browse files
chore: roll Playwright to 1.65.0-next (eac236da28) (#3305)
Co-authored-by: microsoft-playwright-automation[bot] <203992400+microsoft-playwright-automation[bot]@users.noreply.github.com>
1 parent 9084962 commit bf6e6f5

27 files changed

Lines changed: 467 additions & 58 deletions

‎DRIVER_VERSION‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f33f0b751be0dd559d86c1ed27ca8baa5f9cb2b2
1+
eac236da288cdc3d0891278a61e1a876348950a0

‎README.md‎

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

55
| | Linux | macOS | Windows |
66
| :--- | :---: | :---: | :---: |
7-
| Chromium <!-- GEN:chromium-version -->157.0.8103.15<!-- GEN:stop --> | ✅ | ✅ | ✅ |
7+
| Chromium <!-- GEN:chromium-version -->158.0.8127.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
88
| WebKit <!-- GEN:webkit-version -->27.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
99
| Firefox <!-- GEN:firefox-version -->158.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
1010

‎playwright/_impl/clock.py‎

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,27 @@
2020
"""
2121

2222
import datetime
23-
from typing import TYPE_CHECKING, Optional, TypedDict, Union
24-
23+
import math
24+
from typing import (
25+
TYPE_CHECKING,
26+
Awaitable,
27+
Callable,
28+
Optional,
29+
TypedDict,
30+
TypeVar,
31+
Union,
32+
)
33+
34+
from playwright._impl.channel_owner import ApiCallOptions, ApiZone, api_call
35+
from playwright._impl.errors import Error
36+
from playwright._impl.isomorphic.string_utils import js_string
2537
from playwright._impl.timeout_settings import NO_TIMEOUT
2638

2739
if TYPE_CHECKING: # pragma: no cover
2840
from playwright._impl.browser_context import BrowserContext
2941

42+
R = TypeVar("R")
43+
3044

3145
class Clock:
3246
def __init__(self, browser_context: "BrowserContext") -> None:
@@ -36,6 +50,14 @@ def __init__(self, browser_context: "BrowserContext") -> None:
3650
self._loop = browser_context._loop
3751
self._dispatcher_fiber = browser_context._dispatcher_fiber
3852

53+
def _wrap_api_call(
54+
self,
55+
func: Callable[[ApiZone], Awaitable[R]],
56+
options: Optional[ApiCallOptions] = None,
57+
) -> Awaitable[R]:
58+
# Python: include the API name in errors raised before the channel call.
59+
return self._browser_context._wrap_api_call(func, options)
60+
3961
async def install(
4062
self, time: Optional[Union[float, str, datetime.datetime]]
4163
) -> None:
@@ -46,6 +68,7 @@ async def install(
4668
timeout=NO_TIMEOUT,
4769
)
4870

71+
@api_call()
4972
async def fast_forward(self, ticks: Union[int, str]) -> None:
5073
params = parse_ticks(ticks)
5174
await self._browser_context._channel.clockFastForward(
@@ -65,6 +88,7 @@ async def pause_at(self, time: Union[float, str, datetime.datetime]) -> None:
6588
async def resume(self) -> None:
6689
await self._browser_context._channel.clockResume(timeout=NO_TIMEOUT)
6790

91+
@api_call()
6892
async def run_for(self, ticks: Union[int, str]) -> None:
6993
params = parse_ticks(ticks)
7094
await self._browser_context._channel.clockRunFor(
@@ -113,6 +137,10 @@ def parse_time(time: Union[float, str, datetime.datetime]) -> _TimeParams:
113137

114138

115139
def parse_ticks(ticks: Union[int, str]) -> _TicksParams:
140+
# Python: reject non-finite ticks before JSON serialization; upstream rejects
141+
# them in the server, but JSON cannot carry NaN or Infinity to the driver.
142+
if isinstance(ticks, float) and not math.isfinite(ticks):
143+
raise Error(f"Invalid ticks: {js_string(ticks)}")
116144
return {
117145
"ticksNumber": ticks if isinstance(ticks, (int, float)) else None,
118146
"ticksString": ticks if isinstance(ticks, str) else None,

‎playwright/async_api/_generated.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4675,8 +4675,9 @@ async def fast_forward(self, ticks: typing.Union[int, str]) -> None:
46754675
Parameters
46764676
----------
46774677
ticks : Union[int, str]
4678-
Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are
4679-
"08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
4678+
Time may be a finite number of milliseconds to advance the clock by or a human-readable string. Valid string
4679+
formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten
4680+
seconds.
46804681
"""
46814682

46824683
await self._impl_obj.fast_forward(ticks=ticks)
@@ -4772,8 +4773,9 @@ async def run_for(self, ticks: typing.Union[int, str]) -> None:
47724773
Parameters
47734774
----------
47744775
ticks : Union[int, str]
4775-
Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are
4776-
"08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
4776+
Time may be a finite number of milliseconds to advance the clock by or a human-readable string. Valid string
4777+
formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten
4778+
seconds.
47774779
"""
47784780

47794781
await self._impl_obj.run_for(ticks=ticks)

‎playwright/sync_api/_generated.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4585,8 +4585,9 @@ def fast_forward(self, ticks: typing.Union[int, str]) -> None:
45854585
Parameters
45864586
----------
45874587
ticks : Union[int, str]
4588-
Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are
4589-
"08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
4588+
Time may be a finite number of milliseconds to advance the clock by or a human-readable string. Valid string
4589+
formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten
4590+
seconds.
45904591
"""
45914592

45924593
self._sync(self._impl_obj.fast_forward(ticks=ticks))
@@ -4682,8 +4683,9 @@ def run_for(self, ticks: typing.Union[int, str]) -> None:
46824683
Parameters
46834684
----------
46844685
ticks : Union[int, str]
4685-
Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are
4686-
"08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
4686+
Time may be a finite number of milliseconds to advance the clock by or a human-readable string. Valid string
4687+
formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten
4688+
seconds.
46874689
"""
46884690

46894691
self._sync(self._impl_obj.run_for(ticks=ticks))

‎tests/assets/serviceworkers/fetchdummy/sw.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
self.addEventListener('fetch', event => {
2+
if (event.request.url.endsWith('/headers')) {
3+
event.respondWith(new Response(JSON.stringify(Object.fromEntries(event.request.headers))));
4+
return;
5+
}
26
if (event.request.url.endsWith('.html') || event.request.url.includes('passthrough')) {
37
event.respondWith(fetch(event.request));
48
return;

‎tests/async/library/test_browsercontext_har.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,24 @@ async def test_HA_085_should_round_trip_har_zip(
316316
"background-color", "rgb(255, 192, 203)"
317317
)
318318

319+
# Python: zipfile builds the in-memory archive instead of yazl's output stream.
320+
output = io.BytesIO()
321+
with zipfile.ZipFile(output, "w") as zip_file:
322+
for entry in har_dir.iterdir():
323+
zip_file.write(
324+
entry, "Recording.HAR" if entry.name == "har.har" else entry.name
325+
)
326+
uppercase_har_path = tmp_path / "uppercase.har.zip"
327+
uppercase_har_path.write_bytes(output.getvalue())
328+
329+
await context2.unroute_all(behavior="wait")
330+
await context2.route_from_har(uppercase_har_path, not_found="abort")
331+
await page2.reload()
332+
assert "hello, world!" in await page2.content()
333+
await expect(page2.locator("body")).to_have_css(
334+
"background-color", "rgb(255, 192, 203)"
335+
)
336+
319337

320338
async def test_HA_114_should_reject_a_malformed_har_zip(
321339
context_factory: Callable[..., Awaitable[BrowserContext]], tmp_path: Path

‎tests/async/library/test_capabilities.py‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,33 @@ async def handle(route: Route) -> None:
620620

621621

622622
async def test_CA_029_should_not_crash_on_feature_detection_for_public_key_credential(
623-
page: Page, server: Server
623+
page: Page, server: Server, context: BrowserContext
624624
) -> None:
625625
await page.goto(server.EMPTY_PAGE)
626+
assert await page.evaluate("() => typeof PublicKeyCredential") == "function"
627+
assert (
628+
await page.evaluate("() => PublicKeyCredential.name") == "PublicKeyCredential"
629+
)
630+
assert await page.evaluate("() => ({}) instanceof PublicKeyCredential") is False
631+
assert (
632+
await page.evaluate(
633+
"""() => {
634+
try {
635+
new PublicKeyCredential();
636+
return false;
637+
} catch (e) {
638+
return e instanceof TypeError;
639+
}
640+
}"""
641+
)
642+
is True
643+
)
626644
await page.evaluate(
627645
"""async () => {
628646
await PublicKeyCredential.getClientCapabilities();
629647
await PublicKeyCredential.isConditionalMediationAvailable();
630648
await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
631649
}"""
632650
)
651+
await context.credentials.install()
652+
assert await page.evaluate("() => typeof PublicKeyCredential") == "function"

‎tests/async/library/test_page_clock.py‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ async def test_CK_011_run_for_passes_2_hours_34_minutes_and_10_seconds(
225225

226226
@pytest.mark.usefixtures("install_and_pause")
227227
async def test_CK_012_run_for_throws_for_invalid_format(
228-
page: Page, calls: Calls
228+
page: Page, calls: Calls, server: Server
229229
) -> None:
230230
await page.evaluate(
231231
"""async () => {
@@ -234,7 +234,13 @@ async def test_CK_012_run_for_throws_for_invalid_format(
234234
)
235235
with pytest.raises(Error):
236236
await page.clock.run_for("12:02:34:10")
237+
with pytest.raises(Error, match="Clock.run_for: Invalid ticks: NaN"):
238+
await page.clock.run_for(float("nan")) # type: ignore[arg-type]
239+
with pytest.raises(Error, match="Clock.fast_forward: Invalid ticks: Infinity"):
240+
await page.clock.fast_forward(float("inf")) # type: ignore[arg-type]
237241
assert calls == []
242+
await page.goto(server.EMPTY_PAGE)
243+
assert await page.evaluate("() => Date.now()") == 1000
238244

239245

240246
@pytest.mark.usefixtures("install_and_pause")
@@ -262,17 +268,22 @@ async def test_CK_014_fast_forward_ignores_timers_which_wouldn_t_be_run(
262268

263269
@pytest.mark.usefixtures("install_and_pause")
264270
async def test_CK_015_fast_forward_pushes_back_execution_time_for_skipped_timers(
265-
page: Page, calls: Calls
271+
page: Page, calls: Calls, server: Server
266272
) -> None:
273+
await page.goto(server.EMPTY_PAGE)
267274
await page.evaluate(
268275
"""async () => {
269276
setTimeout(() => {
270277
window.stub(Date.now());
271278
}, 1000);
272279
}"""
273280
)
274-
await page.clock.fast_forward(2000)
275-
assert calls == [{"params": [1000 + 2000]}]
281+
fifty_days = 50 * 24 * 60 * 60 * 1000
282+
await page.clock.fast_forward(fifty_days)
283+
assert calls == [{"params": [1000 + fifty_days]}]
284+
assert await page.evaluate("() => Date.now()") == 1000 + fifty_days
285+
await page.reload()
286+
assert await page.evaluate("() => Date.now()") == 1000 + fifty_days
276287

277288

278289
@pytest.mark.usefixtures("install_and_pause")

‎tests/async/library/test_page_close.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,24 @@ async def handler() -> None:
8282

8383

8484
async def test_PA_042_should_reject_all_promises_when_page_is_closed(
85-
page: Page,
85+
page: Page, server: Server
8686
) -> None:
87+
server.set_route("/hang", lambda request: None)
88+
request_promise = asyncio.create_task(server.wait_for_request("/hang"))
89+
await page.set_content(
90+
f'<iframe src="{server.PREFIX}/hang"></iframe>', wait_until="domcontentloaded"
91+
)
92+
await request_promise
93+
frame_error_promise = asyncio.create_task(
94+
error_of(page.frames[1].evaluate("() => new Promise(() => {})"))
95+
)
8796
error, _ = await asyncio.gather(
8897
error_of(page.evaluate("() => new Promise(r => {})")),
8998
page.close(),
9099
)
91100
assert isinstance(error, Error)
92101
assert TARGET_CLOSED_ERROR_MESSAGE in error.message
102+
assert TARGET_CLOSED_ERROR_MESSAGE in (await frame_error_promise).message
93103

94104

95105
async def test_PA_043_should_set_the_page_close_state(page: Page) -> None:

0 commit comments

Comments
 (0)