Skip to content

Commit 88eafe1

Browse files
chore: roll Playwright to 1.66.0-next (8534271f04) (#3342)
Co-authored-by: microsoft-playwright-automation[bot] <203992400+microsoft-playwright-automation[bot]@users.noreply.github.com>
1 parent f68f05c commit 88eafe1

10 files changed

Lines changed: 189 additions & 13 deletions

File tree

‎DRIVER_VERSION‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3b438229c6a2ccdbe2d3572755935892203d83c3
1+
8534271f0413bae6a455b7cf43b2637391bc614b

‎playwright/async_api/_generated.py‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,10 +3552,17 @@ async def set_offline(self, offline: bool) -> None:
35523552
offline : bool
35533553
Whether to emulate network being offline for the browser context.
35543554

3555-
**NOTE** Offline emulation only affects requests that go through the browser's regular network stack, such as page
3556-
navigations, `fetch()`, `XMLHttpRequest` and WebSockets. It does not affect WebRTC traffic: established
3557-
`RTCPeerConnection`s keep sending and receiving media over UDP. To test WebRTC connection loss, interrupt the
3558-
connection outside the browser, for example by stopping the TURN server or using an OS-level firewall.
3555+
**NOTE** Offline emulation affects HTTP requests, such as page navigations, `fetch()` and `XMLHttpRequest`.
3556+
3557+
WebSocket behavior depends on the browser and whether the connection is already established. Chromium and Firefox
3558+
fail new WebSocket connections while offline, but do not close already-open connections. Chromium can defer
3559+
incoming messages until the context goes back online, rather than lose them; Firefox can continue delivering
3560+
messages while offline. WebKit can allow both new WebSocket connections and traffic on established connections
3561+
while offline. Do not rely on offline emulation to test WebSocket message loss or connection closure.
3562+
3563+
Offline emulation does not affect WebRTC traffic: established `RTCPeerConnection`s keep sending and receiving media
3564+
over UDP. To test WebRTC connection loss, interrupt the connection outside the browser, for example by stopping the
3565+
TURN server or using an OS-level firewall.
35593566

35603567
"""
35613568

‎playwright/sync_api/_generated.py‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3470,10 +3470,17 @@ def set_offline(self, offline: bool) -> None:
34703470
offline : bool
34713471
Whether to emulate network being offline for the browser context.
34723472

3473-
**NOTE** Offline emulation only affects requests that go through the browser's regular network stack, such as page
3474-
navigations, `fetch()`, `XMLHttpRequest` and WebSockets. It does not affect WebRTC traffic: established
3475-
`RTCPeerConnection`s keep sending and receiving media over UDP. To test WebRTC connection loss, interrupt the
3476-
connection outside the browser, for example by stopping the TURN server or using an OS-level firewall.
3473+
**NOTE** Offline emulation affects HTTP requests, such as page navigations, `fetch()` and `XMLHttpRequest`.
3474+
3475+
WebSocket behavior depends on the browser and whether the connection is already established. Chromium and Firefox
3476+
fail new WebSocket connections while offline, but do not close already-open connections. Chromium can defer
3477+
incoming messages until the context goes back online, rather than lose them; Firefox can continue delivering
3478+
messages while offline. WebKit can allow both new WebSocket connections and traffic on established connections
3479+
while offline. Do not rely on offline emulation to test WebSocket message loss or connection closure.
3480+
3481+
Offline emulation does not affect WebRTC traffic: established `RTCPeerConnection`s keep sending and receiving media
3482+
over UDP. To test WebRTC connection loss, interrupt the connection outside the browser, for example by stopping the
3483+
TURN server or using an OS-level firewall.
34773484

34783485
"""
34793486

‎tests/async/library/test_tracing.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ async def test_TR_001_should_collect_trace_with_resources_but_no_js(
138138
assetdir: Path,
139139
tmp_path: Path,
140140
) -> None:
141+
# Python: the driver is out of process, so the in-process internalBody hook
142+
# and its fetchedBodies checks do not apply (mode !== 'default' upstream).
141143
await context.tracing.start(screenshots=True, snapshots=True)
142144
await page.goto(server.PREFIX + "/frames/frame.html")
143145
await page.set_content("<button>Click</button>")
@@ -177,6 +179,8 @@ async def test_TR_001_should_collect_trace_with_resources_but_no_js(
177179
script = resource_snapshot(events, "script.js")
178180
assert script
179181
assert "_file" not in script["snapshot"]["response"]["content"]
182+
assert script["snapshot"]["response"]["bodySize"] > 0
183+
assert script["snapshot"]["response"]["headersSize"] > 0
180184

181185

182186
async def test_TR_002_should_use_the_correct_title_for_event_driven_callbacks(

‎tests/async/page/test_page_evaluate.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import asyncio
1818
import datetime
19+
import json
1920
import math
2021
import os
2122
import re
@@ -324,12 +325,33 @@ async def test_EV_031_should_include_a_non_error_rejection_value_in_the_error_me
324325
assert "null" in exc_info.value.message
325326

326327

328+
@pytest.mark.xfail(
329+
reason="python: protocol validation exceeds the recursion limit for a 200-level evaluation argument",
330+
strict=True,
331+
)
327332
async def test_EV_032_should_return_complex_objects(page: Page) -> None:
328333
object = {"foo": "bar!"}
329334
result = await page.evaluate("a => a", object)
330335
assert result is not object
331336
assert result == object
332337

338+
argument: Any = 0
339+
# Chromium rejects protocol arguments at 60 levels, WebKit at 200.
340+
for _ in range(200):
341+
argument = {"children": [argument]}
342+
assert await page.evaluate(
343+
"value => JSON.stringify(value).length", argument
344+
) == len(json.dumps(argument, separators=(",", ":")))
345+
346+
# An argument that is too deep rejects and does not hang.
347+
for _ in range(800):
348+
argument = {"children": [argument]}
349+
with pytest.raises(Error) as exc_info:
350+
await page.evaluate("value => JSON.stringify(value).length", argument)
351+
assert re.search(
352+
"Maximum call stack size exceeded|too much recursion", exc_info.value.message
353+
)
354+
333355

334356
async def test_EV_033_should_return_na_n(page: Page) -> None:
335357
result = await page.evaluate("() => NaN")

‎tests/async/page/test_page_event_pageerror.py‎

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
"""Port of tests/page/page-event-pageerror.spec.ts."""
1616

1717

18-
from typing import Optional
18+
import asyncio
19+
from typing import List, Optional
1920

2021
import pytest
2122

2223
from playwright.async_api import Page
23-
from tests.server import Server, TestServerRequest
24+
from tests.server import Server, TestServerRequest, reactor
2425

2526

2627
def expect_failure(request: pytest.FixtureRequest, reason: str) -> None:
@@ -349,3 +350,53 @@ def handle(request: TestServerRequest) -> None:
349350
assert "Invalid character" in error.message
350351
else:
351352
assert "illegal character" in error.message
353+
354+
355+
async def test_ER_022_should_not_fire_for_a_caught_fetch_rejected_by_a_pending_navigation(
356+
page: Page, server: Server
357+
) -> None:
358+
await page.goto(server.EMPTY_PAGE)
359+
errors: List[str] = []
360+
page.on("pageerror", lambda error: errors.append(error.message))
361+
loop = asyncio.get_running_loop()
362+
wait_response: asyncio.Future[TestServerRequest] = loop.create_future()
363+
replacement_response: asyncio.Future[TestServerRequest] = loop.create_future()
364+
# Python: the server handlers run on the reactor thread.
365+
server.set_route(
366+
"/wait",
367+
lambda request: loop.call_soon_threadsafe(wait_response.set_result, request),
368+
)
369+
server.set_route(
370+
"/replacement",
371+
lambda request: loop.call_soon_threadsafe(
372+
replacement_response.set_result, request
373+
),
374+
)
375+
async with page.expect_event(
376+
"console", predicate=lambda message: message.text == "fetch done"
377+
) as fetch_done:
378+
# Chromium does not run evaluate during a pending navigation, so the page starts the second fetch.
379+
await page.evaluate(
380+
"""() => {
381+
void fetch('/wait').catch(() => {}).then(() => fetch('/empty.html')).catch(() => {}).then(() => console.log('fetch done'));
382+
}"""
383+
)
384+
navigation = asyncio.create_task(page.goto(server.PREFIX + "/replacement"))
385+
response = await replacement_response
386+
# WebKit rejects the second fetch, because the document is about to go away.
387+
reactor.callFromThread((await wait_response).finish)
388+
await fetch_done.value
389+
390+
def finish() -> None:
391+
response.write(b"replacement")
392+
response.finish()
393+
394+
reactor.callFromThread(finish)
395+
await navigation
396+
async with page.expect_event("pageerror") as error_info:
397+
await page.evaluate(
398+
"() => setTimeout(() => { throw new Error('genuine error'); }, 0)"
399+
)
400+
error = await error_info.value
401+
assert error.message == "genuine error"
402+
assert errors == ["genuine error"]

‎tests/sync/library/test_tracing.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ def test_TR_001_should_collect_trace_with_resources_but_no_js(
152152
assetdir: Path,
153153
tmp_path: Path,
154154
) -> None:
155+
# Python: the driver is out of process, so the in-process internalBody hook
156+
# and its fetchedBodies checks do not apply (mode !== 'default' upstream).
155157
context.tracing.start(screenshots=True, snapshots=True)
156158
page.goto(server.PREFIX + "/frames/frame.html")
157159
page.set_content("<button>Click</button>")
@@ -189,6 +191,8 @@ def test_TR_001_should_collect_trace_with_resources_but_no_js(
189191
script = resource_snapshot(events, "script.js")
190192
assert script
191193
assert "_file" not in script["snapshot"]["response"]["content"]
194+
assert script["snapshot"]["response"]["bodySize"] > 0
195+
assert script["snapshot"]["response"]["headersSize"] > 0
192196

193197

194198
def test_TR_002_should_use_the_correct_title_for_event_driven_callbacks(

‎tests/sync/page/test_page_evaluate.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Port of tests/page/page-evaluate.spec.ts."""
1616

1717
import datetime
18+
import json
1819
import math
1920
import os
2021
import re
@@ -327,12 +328,33 @@ def test_EV_031_should_include_a_non_error_rejection_value_in_the_error_message(
327328
assert "null" in exc_info.value.message
328329

329330

331+
@pytest.mark.xfail(
332+
reason="python: protocol validation exceeds the recursion limit for a 200-level evaluation argument",
333+
strict=True,
334+
)
330335
def test_EV_032_should_return_complex_objects(page: Page) -> None:
331336
object = {"foo": "bar!"}
332337
result = page.evaluate("a => a", object)
333338
assert result is not object
334339
assert result == object
335340

341+
argument: Any = 0
342+
# Chromium rejects protocol arguments at 60 levels, WebKit at 200.
343+
for _ in range(200):
344+
argument = {"children": [argument]}
345+
assert page.evaluate("value => JSON.stringify(value).length", argument) == len(
346+
json.dumps(argument, separators=(",", ":"))
347+
)
348+
349+
# An argument that is too deep rejects and does not hang.
350+
for _ in range(800):
351+
argument = {"children": [argument]}
352+
with pytest.raises(Error) as exc_info:
353+
page.evaluate("value => JSON.stringify(value).length", argument)
354+
assert re.search(
355+
"Maximum call stack size exceeded|too much recursion", exc_info.value.message
356+
)
357+
336358

337359
def test_EV_033_should_return_na_n(page: Page) -> None:
338360
result = page.evaluate("() => NaN")

‎tests/sync/page/test_page_event_pageerror.py‎

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
"""Port of tests/page/page-event-pageerror.spec.ts."""
1616

1717

18-
from typing import Optional
18+
import asyncio
19+
from typing import Any, Callable, List, Optional
1920

2021
import pytest
2122

23+
from playwright._impl._greenlets import wait_for_future
2224
from playwright.sync_api import Page
23-
from tests.server import Server, TestServerRequest
25+
from tests.server import Server, TestServerRequest, reactor
2426

2527

2628
def expect_failure(request: pytest.FixtureRequest, reason: str) -> None:
@@ -349,3 +351,59 @@ def handle(request: TestServerRequest) -> None:
349351
assert "Invalid character" in error.message
350352
else:
351353
assert "illegal character" in error.message
354+
355+
356+
def test_ER_022_should_not_fire_for_a_caught_fetch_rejected_by_a_pending_navigation(
357+
page: Page, server: Server, sync_gather: Callable[..., List[Any]]
358+
) -> None:
359+
page.goto(server.EMPTY_PAGE)
360+
errors: List[str] = []
361+
page.on("pageerror", lambda error: errors.append(error.message))
362+
loop = page._loop
363+
wait_response: asyncio.Future[TestServerRequest] = loop.create_future()
364+
replacement_response: asyncio.Future[TestServerRequest] = loop.create_future()
365+
# Python: the server handlers run on the reactor thread.
366+
server.set_route(
367+
"/wait",
368+
lambda request: loop.call_soon_threadsafe(wait_response.set_result, request),
369+
)
370+
server.set_route(
371+
"/replacement",
372+
lambda request: loop.call_soon_threadsafe(
373+
replacement_response.set_result, request
374+
),
375+
)
376+
with page.expect_event(
377+
"console", predicate=lambda message: message.text == "fetch done"
378+
) as fetch_done:
379+
# Chromium does not run evaluate during a pending navigation, so the page starts the second fetch.
380+
page.evaluate(
381+
"""() => {
382+
void fetch('/wait').catch(() => {}).then(() => fetch('/empty.html')).catch(() => {}).then(() => console.log('fetch done'));
383+
}"""
384+
)
385+
386+
def finish_navigation() -> None:
387+
wait_for_future(loop, page._dispatcher_fiber, replacement_response)
388+
response = replacement_response.result()
389+
# WebKit rejects the second fetch, because the document is about to go away.
390+
wait_for_future(loop, page._dispatcher_fiber, wait_response)
391+
reactor.callFromThread(wait_response.result().finish)
392+
fetch_done.value
393+
394+
def finish() -> None:
395+
response.write(b"replacement")
396+
response.finish()
397+
398+
reactor.callFromThread(finish)
399+
400+
sync_gather(
401+
lambda: page.goto(server.PREFIX + "/replacement"), finish_navigation
402+
)
403+
with page.expect_event("pageerror") as error_info:
404+
page.evaluate(
405+
"() => setTimeout(() => { throw new Error('genuine error'); }, 0)"
406+
)
407+
error = error_info.value
408+
assert error.message == "genuine error"
409+
assert errors == ["genuine error"]

‎tests/upstream_registry.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,6 +2064,7 @@ subsystem, add a row to the Subsystems table. Then update this file:
20642064
| `ER-019` | `library/page-event-crash.spec.ts` | should be able to close context when page crashes |
20652065
| `ER-020` | `library/page-event-crash.spec.ts` | should be able to close page after crash |
20662066
| `ER-021` | `library/page-event-crash.spec.ts` | should reject in-flight worker.evaluate when page crashes |
2067+
| `ER-022` | `page/page-event-pageerror.spec.ts` | should not fire for a caught fetch rejected by a pending navigation |
20672068

20682069
### ES — Eval on selector
20692070

0 commit comments

Comments
 (0)