11from __future__ import annotations
22
3+ import asyncio
34import logging
45import shutil
56from datetime import timedelta
67from pathlib import Path
78from typing import TYPE_CHECKING , Any
8- from unittest .mock import Mock
9+ from unittest .mock import AsyncMock , Mock
910
1011import pytest
1112from playwright .async_api import async_playwright
@@ -48,9 +49,7 @@ async def test_delete_temp_folder_with_close_browser(playwright: Playwright) ->
4849 assert not current_temp_dir .exists ()
4950
5051
51- async def test_delete_temp_folder_when_files_are_locked (
52- playwright : Playwright , monkeypatch : pytest .MonkeyPatch
53- ) -> None :
52+ async def test_delete_temp_folder_when_files_are_locked (monkeypatch : pytest .MonkeyPatch ) -> None :
5453 """The temp directory is removed even when the first delete attempts fail, as Windows locks the browser files."""
5554 monkeypatch .setattr (PlaywrightPersistentBrowser , '_TMP_DIR_DELETE_INTERVAL' , timedelta (0 ))
5655
@@ -66,14 +65,26 @@ def rmtree_locked_at_first(path: Any, **kwargs: Any) -> None:
6665 rmtree .side_effect = rmtree_locked_at_first
6766 monkeypatch .setattr (shutil , 'rmtree' , rmtree )
6867
69- persist_browser = PlaywrightPersistentBrowser (
70- playwright .chromium , user_data_dir = None , browser_launch_options = {'headless' : True }
71- )
68+ # A real browser on Windows can hold the files longer than the whole retry budget, so a fake context stands in.
69+ # Like Playwright, it runs the `close` listener as a separate task.
70+ context = Mock ()
71+ listener_tasks = list [asyncio .Task ]()
72+
73+ async def close_context () -> None :
74+ listener = context .on .call_args .args [1 ]
75+ listener_tasks .append (asyncio .create_task (listener (context )))
76+
77+ context .close = close_context
78+ browser_type = Mock ()
79+ browser_type .launch_persistent_context = AsyncMock (return_value = context )
80+
81+ persist_browser = PlaywrightPersistentBrowser (browser_type , user_data_dir = None , browser_launch_options = {})
7282 await persist_browser .new_context ()
7383 assert isinstance (persist_browser ._temp_dir , Path )
7484 current_temp_dir = persist_browser ._temp_dir
7585 assert current_temp_dir .exists ()
7686 await persist_browser .close ()
87+ await asyncio .gather (* listener_tasks )
7788 # The context's `close` event and `close` itself both ask for the removal, but only one of them retries.
7889 assert rmtree .call_count == locked_attempts + 1
7990 assert not current_temp_dir .exists ()
0 commit comments