Skip to content

Commit ba0dd58

Browse files
committed
♻️ refactor: Cleaned up code and added tests.
1 parent 9abc555 commit ba0dd58

File tree

3 files changed

+140
-19
lines changed

3 files changed

+140
-19
lines changed

pydoll/browser/base.py

+32-18
Original file line numberDiff line numberDiff line change
@@ -256,26 +256,15 @@ async def get_window_id(self):
256256

257257
if response.get('error'):
258258
pages = await self.get_targets()
259-
valid_page = next(
260-
(page for page in pages if page.get('type') == 'page' and page.get('attached')),
261-
None
259+
target_id = await self._get_valid_target_id(pages)
260+
response = await self._execute_command(
261+
BrowserCommands.get_window_id_by_target(target_id)
262262
)
263263

264-
if not valid_page:
265-
raise RuntimeError("No valid attached browser page found.")
264+
if window_id := response.get('result', {}).get('windowId'):
265+
return window_id
266266

267-
target_id = valid_page.get('targetId')
268-
if not target_id:
269-
raise RuntimeError("Valid page found but missing 'targetId'.")
270-
271-
command = BrowserCommands.get_window_id_by_target(target_id)
272-
response = await self._execute_command(command)
273-
274-
try:
275-
return response['result']['windowId']
276-
except KeyError:
277-
error_message = response.get('error', {}).get('message', "Unknown error")
278-
raise RuntimeError(f"Failed to get window ID: {error_message}")
267+
raise RuntimeError(response.get('error', {}))
279268

280269
async def set_window_bounds(self, bounds: dict):
281270
"""
@@ -548,7 +537,7 @@ def _is_valid_page(page: dict) -> bool:
548537
'url', ''
549538
)
550539

551-
async def _get_valid_page(self, pages) -> str:
540+
async def _get_valid_page(self, pages: list) -> str:
552541
"""
553542
Gets the ID of a valid page or creates a new one.
554543
@@ -570,6 +559,31 @@ async def _get_valid_page(self, pages) -> str:
570559

571560
return await self.new_page()
572561

562+
@staticmethod
563+
async def _get_valid_target_id(pages: list) -> str:
564+
"""
565+
Retrieves the target ID of a valid attached browser page.
566+
567+
Returns:
568+
str: The target ID of a valid page.
569+
570+
"""
571+
572+
valid_page = next(
573+
(page for page in pages
574+
if page.get('type') == 'page' and page.get('attached')),
575+
None
576+
)
577+
578+
if not valid_page:
579+
raise RuntimeError("No valid attached browser page found.")
580+
581+
target_id = valid_page.get('targetId')
582+
if not target_id:
583+
raise RuntimeError("Valid page found but missing 'targetId'.")
584+
585+
return target_id
586+
573587
async def _is_browser_running(self, timeout: int = 10) -> bool:
574588
"""
575589
Checks if the browser process is currently running.

pydoll/browser/page.py

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ def __init__(self, connection_port: int, page_id: str):
3232
self._network_events_enabled = False
3333
self._fetch_events_enabled = False
3434
self._dom_events_enabled = False
35-
self._page_id = page_id
3635

3736
@property
3837
def page_events_enabled(self) -> bool:

tests/test_browser_window.py

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import pytest
2+
import pytest_asyncio
3+
from unittest.mock import AsyncMock, MagicMock, patch
4+
from pydoll.browser.base import Browser
5+
from pydoll.commands.browser import BrowserCommands
6+
7+
8+
class ConcreteBrowser(Browser):
9+
def _get_default_binary_location(self) -> str:
10+
return '/fake/path/to/browser'
11+
12+
13+
@pytest_asyncio.fixture
14+
async def mock_browser():
15+
with patch.multiple(
16+
Browser,
17+
_get_default_binary_location=MagicMock(
18+
return_value='/fake/path/to/browser'
19+
),
20+
), patch(
21+
'pydoll.connection.connection.ConnectionHandler',
22+
autospec=True,
23+
) as mock_conn_handler:
24+
browser = ConcreteBrowser()
25+
browser._connection_handler = mock_conn_handler.return_value
26+
browser._connection_handler.execute_command = AsyncMock()
27+
browser._connection_handler.register_callback = AsyncMock()
28+
29+
browser._pages = ['page1']
30+
31+
yield browser
32+
33+
34+
@pytest.mark.asyncio
35+
async def test_get_window_id_success(mock_browser):
36+
mock_browser._connection_handler.execute_command.return_value = {
37+
'result': {'windowId': 123}
38+
}
39+
result = await mock_browser.get_window_id()
40+
assert result == 123
41+
42+
43+
@pytest.mark.asyncio
44+
async def test_get_window_id_with_error_and_retry(mock_browser):
45+
mock_browser._execute_command = AsyncMock(side_effect=[
46+
{'error': 'some error'},
47+
{'result': {
48+
'targetInfos': [{
49+
'type': 'page',
50+
'attached': True,
51+
'targetId': 'target1'
52+
}]
53+
}},
54+
{'result': {'windowId': 123}}
55+
])
56+
57+
result = await mock_browser.get_window_id()
58+
assert result == 123
59+
60+
61+
@pytest.mark.asyncio
62+
async def test_get_window_id_failure(mock_browser):
63+
mock_browser._connection_handler.execute_command.return_value = {
64+
'error': 'some error'
65+
}
66+
mock_browser.get_targets = AsyncMock(return_value=[])
67+
with pytest.raises(RuntimeError):
68+
await mock_browser.get_window_id()
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_get_valid_target_id_success(mock_browser):
73+
pages = [{
74+
'type': 'page',
75+
'attached': True,
76+
'targetId': 'target1'
77+
}]
78+
result = await mock_browser._get_valid_target_id(pages)
79+
assert result == 'target1'
80+
81+
82+
@pytest.mark.asyncio
83+
async def test_get_valid_target_id_no_valid_page(mock_browser):
84+
pages = []
85+
with pytest.raises(RuntimeError, match="No valid attached browser page found."):
86+
await mock_browser._get_valid_target_id(pages)
87+
88+
89+
@pytest.mark.asyncio
90+
async def test_get_valid_target_id_missing_target_id(mock_browser):
91+
pages = [{
92+
'type': 'page',
93+
'attached': True,
94+
'targetId': None
95+
}]
96+
with pytest.raises(RuntimeError, match="Valid page found but missing 'targetId'."):
97+
await mock_browser._get_valid_target_id(pages)
98+
99+
100+
@pytest.mark.asyncio
101+
async def test_get_window_id_by_target(mock_browser):
102+
expected_command = {
103+
'method': 'Browser.getWindowForTarget',
104+
'params': {
105+
'targetId': 'target1',
106+
},
107+
}
108+
assert BrowserCommands.get_window_id_by_target('target1') == expected_command

0 commit comments

Comments
 (0)