Skip to content

Commit 5f8baea

Browse files
committed
Add test
1 parent 6f182b0 commit 5f8baea

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

tests/unit/browsers/test_playwright_browser_controller.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import asyncio
44
from datetime import datetime, timedelta, timezone
5-
from typing import TYPE_CHECKING
5+
from typing import TYPE_CHECKING, Any
6+
from unittest import mock
7+
from unittest.mock import AsyncMock
68

79
import pytest
810
from playwright.async_api import Browser, Playwright, async_playwright
911

10-
from crawlee.browsers import PlaywrightBrowserController
12+
from crawlee.browsers import PlaywrightBrowserController, PlaywrightBrowserPlugin, PlaywrightPersistentBrowser
1113

1214
if TYPE_CHECKING:
1315
from collections.abc import AsyncGenerator
@@ -106,3 +108,28 @@ async def test_close_browser_with_open_pages(browser: Browser) -> None:
106108

107109
assert controller.pages_count == 0
108110
assert not controller.is_browser_connected
111+
112+
113+
async def test_memory_leak_on_concurrent_context_creation() -> None:
114+
"""Test that only one browser context is created when multiple pages are opened concurrently."""
115+
116+
# Prepare mocked browser with relevant methods and attributes
117+
mocked_browser = AsyncMock()
118+
mocked_context_launcher = AsyncMock()
119+
async def delayed_launch_persistent_context(*args: Any, **kwargs: Any) -> AsyncMock:
120+
"""Ensure that both calls to create context overlap in time."""
121+
await asyncio.sleep(5) # Simulate delay in creation to make sure race condition happens
122+
return await mocked_context_launcher(*args, **kwargs)
123+
mocked_browser.launch_persistent_context = delayed_launch_persistent_context
124+
125+
# Create minimal instance of PlaywrightBrowserController with mocked browser
126+
controller = PlaywrightBrowserController(
127+
PlaywrightPersistentBrowser(mocked_browser,None, {}),
128+
header_generator=None,
129+
fingerprint_generator=None
130+
)
131+
132+
# Both calls will try to create browser context at the same time, but only one context should be created.
133+
await asyncio.gather(controller.new_page(), controller.new_page())
134+
135+
assert mocked_context_launcher.call_count == 1

0 commit comments

Comments
 (0)