peijun1's picture
Deploy AI Studio Proxy API to Hugging Face Spaces
a5784e9
Raw
History Blame Contribute Delete
7.95 kB
"""
Tests for browser_utils/initialization/debug.py
Target coverage: >80% (from baseline 10%)
"""
from unittest.mock import Mock, PropertyMock, patch
import pytest
from browser_utils.initialization.debug import setup_debug_listeners
@pytest.fixture
def mock_page():
"""Create mock page"""
page = Mock()
page.on = Mock()
return page
@pytest.fixture
def mock_state_with_logs():
"""Create a mock state with console_logs and network_log that we can inspect."""
mock_state = Mock()
mock_state.console_logs = []
mock_state.network_log = {"requests": [], "responses": []}
with patch("api_utils.server_state.state", mock_state):
yield mock_state
@pytest.fixture
def mock_console_message():
"""Create mock console message"""
msg = Mock()
msg.type = "log"
msg.text = "test message"
msg.location = {"url": "https://example.com/page.js", "lineNumber": 42}
return msg
@pytest.fixture
def mock_request():
"""Create mock network request"""
req = Mock()
req.url = "https://example.com/api/data"
req.method = "GET"
req.resource_type = "xhr"
return req
@pytest.fixture
def mock_response():
"""Create mock network response"""
resp = Mock()
resp.url = "https://example.com/api/data"
resp.status = 200
resp.status_text = "OK"
return resp
def test_listeners_attached(mock_page, mock_state_with_logs):
"""Test all listeners attached"""
setup_debug_listeners(mock_page)
assert mock_page.on.call_count == 3
listener_names = [call_args[0][0] for call_args in mock_page.on.call_args_list]
assert "console" in listener_names
assert "request" in listener_names
assert "response" in listener_names
def test_console_handler_log(mock_page, mock_state_with_logs, mock_console_message):
"""Test console log captured"""
setup_debug_listeners(mock_page)
# Extract console handler
console_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "console":
console_handler = call_args[0][1]
break
assert console_handler is not None
# Trigger handler (datetime is imported inside the handler, no need to mock)
console_handler(mock_console_message)
# Verify log captured
assert len(mock_state_with_logs.console_logs) == 1
log_entry = mock_state_with_logs.console_logs[0]
assert log_entry["type"] == "log"
assert log_entry["text"] == "test message"
assert "timestamp" in log_entry
assert "location" in log_entry
def test_console_handler_error(mock_page, mock_state_with_logs):
"""Test console error captured"""
setup_debug_listeners(mock_page)
console_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "console":
console_handler = call_args[0][1]
break
error_msg = Mock()
error_msg.type = "error"
error_msg.text = "Critical error"
error_msg.location = {"url": "test.js", "lineNumber": 1}
assert console_handler is not None
console_handler(error_msg)
assert len(mock_state_with_logs.console_logs) == 1
assert mock_state_with_logs.console_logs[0]["type"] == "error"
def test_request_handler_xhr(mock_page, mock_state_with_logs, mock_request):
"""Test XHR request captured"""
setup_debug_listeners(mock_page)
request_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "request":
request_handler = call_args[0][1]
break
assert request_handler is not None
request_handler(mock_request)
assert len(mock_state_with_logs.network_log["requests"]) == 1
req_entry = mock_state_with_logs.network_log["requests"][0]
assert req_entry["url"] == "https://example.com/api/data"
assert req_entry["method"] == "GET"
assert "timestamp" in req_entry
def test_request_handler_image_filtered(mock_page, mock_state_with_logs):
"""Test image request filtered out"""
setup_debug_listeners(mock_page)
request_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "request":
request_handler = call_args[0][1]
break
image_req = Mock()
image_req.url = "https://example.com/logo.png"
image_req.method = "GET"
image_req.resource_type = "image"
assert request_handler is not None
request_handler(image_req)
assert len(mock_state_with_logs.network_log["requests"]) == 0
def test_request_handler_css_filtered(mock_page, mock_state_with_logs):
"""Test CSS request filtered out"""
setup_debug_listeners(mock_page)
request_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "request":
request_handler = call_args[0][1]
break
css_req = Mock()
css_req.url = "https://example.com/styles.css"
css_req.method = "GET"
css_req.resource_type = "stylesheet"
assert request_handler is not None
request_handler(css_req)
assert len(mock_state_with_logs.network_log["requests"]) == 0
def test_response_handler_success(mock_page, mock_state_with_logs, mock_response):
"""Test successful response captured"""
setup_debug_listeners(mock_page)
response_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "response":
response_handler = call_args[0][1]
break
assert response_handler is not None
response_handler(mock_response)
assert len(mock_state_with_logs.network_log["responses"]) == 1
resp_entry = mock_state_with_logs.network_log["responses"][0]
assert resp_entry["status"] == 200
assert resp_entry["url"] == "https://example.com/api/data"
assert "timestamp" in resp_entry
def test_response_handler_error_status(mock_page, mock_state_with_logs):
"""Test error response captured"""
setup_debug_listeners(mock_page)
response_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "response":
response_handler = call_args[0][1]
break
error_resp = Mock()
error_resp.url = "https://example.com/api/error"
error_resp.status = 404
error_resp.status_text = "Not Found"
assert response_handler is not None
response_handler(error_resp)
assert len(mock_state_with_logs.network_log["responses"]) == 1
assert mock_state_with_logs.network_log["responses"][0]["status"] == 404
def test_console_handler_exception_caught(mock_page, mock_state_with_logs):
"""Test exception in console handler caught"""
setup_debug_listeners(mock_page)
console_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "console":
console_handler = call_args[0][1]
break
bad_msg = Mock()
# Use PropertyMock to raise exception when .text is accessed as property
type(bad_msg).text = PropertyMock(side_effect=RuntimeError("Extraction failed"))
assert console_handler is not None
with patch("browser_utils.initialization.debug.logger") as mock_logger:
# Should not raise
console_handler(bad_msg)
# Verify error logged
assert mock_logger.error.called
def test_request_handler_exception_caught(mock_page, mock_state_with_logs):
"""Test exception in request handler caught"""
setup_debug_listeners(mock_page)
request_handler = None
for call_args in mock_page.on.call_args_list:
if call_args[0][0] == "request":
request_handler = call_args[0][1]
break
bad_req = Mock()
bad_req.url = Mock(side_effect=RuntimeError("URL access failed"))
assert request_handler is not None
with patch("browser_utils.initialization.debug.logger") as mock_logger:
request_handler(bad_req)
assert mock_logger.error.called