Skip to content

Commit fb4a1a3

Browse files
committed
fix: order remote browser close events
1 parent e4892fa commit fb4a1a3

2 files changed

Lines changed: 53 additions & 2 deletions

File tree

playwright/_impl/_browser_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,15 +259,15 @@ def handle_transport_close(reason: Optional[str]) -> None:
259259
for page in context.pages:
260260
page._on_close()
261261
context._on_close()
262-
browser._on_close()
263262
connection.cleanup(reason)
264-
# TODO: Backport https://github.com/microsoft/playwright/commit/d8d5289e8692c9b1265d23ee66988d1ac5122f33
265263
# Give a chance to any API call promises to reject upon page/context closure.
266264
# This happens naturally when we receive page.onClose and browser.onClose from the server
267265
# in separate tasks. However, upon pipe closure we used to dispatch them all synchronously
268266
# here and promises did not have a chance to reject.
269267
# The order of rejects vs closure is a part of the API contract and our test runner
270268
# relies on it to attribute rejections to the right test.
269+
if browser:
270+
connection._loop.call_soon(browser._on_close)
271271

272272
transport.once("close", handle_transport_close)
273273

tests/async/test_browsertype_connect.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,57 @@ async def test_browser_type_connect_should_reject_navigation_when_browser_closes
180180
assert "has been closed" in exc_info.value.message
181181

182182

183+
async def test_browser_type_connect_should_reject_wait_for_event_before_browser_close_finishes(
184+
browser_type: BrowserType, launch_server: Callable[[], RemoteServer]
185+
) -> None:
186+
remote_server = launch_server()
187+
browser = await browser_type.connect(remote_server.ws_endpoint)
188+
page = await browser.new_page()
189+
190+
rejected = False
191+
192+
async def wait_for_download() -> None:
193+
nonlocal rejected
194+
try:
195+
await page.wait_for_event("download")
196+
except Error:
197+
rejected = True
198+
199+
wait_task = asyncio.create_task(wait_for_download())
200+
await asyncio.sleep(0)
201+
202+
await browser.close()
203+
assert rejected is True
204+
await wait_task
205+
206+
207+
async def test_browser_type_connect_should_reject_wait_for_event_before_disconnected(
208+
browser_type: BrowserType, launch_server: Callable[[], RemoteServer]
209+
) -> None:
210+
remote_server = launch_server()
211+
browser = await browser_type.connect(remote_server.ws_endpoint)
212+
page = await browser.new_page()
213+
log = []
214+
215+
async def wait_for_download() -> None:
216+
try:
217+
await page.wait_for_event("download")
218+
except Error:
219+
log.append("rejected")
220+
221+
wait_task = asyncio.create_task(wait_for_download())
222+
await asyncio.sleep(0)
223+
browser.on("disconnected", lambda _: log.append("disconnected"))
224+
225+
remote_server.kill()
226+
await wait_task
227+
for _ in range(10):
228+
if len(log) == 2:
229+
break
230+
await asyncio.sleep(0.1)
231+
assert log == ["rejected", "disconnected"]
232+
233+
183234
async def test_should_not_allow_getting_the_path(
184235
browser_type: BrowserType, launch_server: Callable[[], RemoteServer], server: Server
185236
) -> None:

0 commit comments

Comments
 (0)