"""Validation and dispatch tests for MCP browser tools."""
from __future__ import annotations
from types import SimpleNamespace
import unittest
from src.browser_session import neverCancelled
from src.tool_handlers import InvalidArgumentsError, ToolHandlers
class FakeBrowser:
"""Record JavaScript dispatch without a browser connection."""
def __init__(self) -> None:
self.config = SimpleNamespace(request_timeout_ms=30000)
self.calls: list[tuple[object, ...]] = []
async def runJavaScript(self, script, timeout_ms, cancelled):
"""Return a deterministic JavaScript result."""
self.calls.append((script, timeout_ms, cancelled))
return {"result": 4, "result_type": "number"}
class ToolHandlersTest(unittest.IsolatedAsyncioTestCase):
"""Verify run_javascript arguments before browser dispatch."""
async def test_dispatches_javascript_with_default_timeout(self) -> None:
browser = FakeBrowser()
handlers = ToolHandlers(browser)
result = await handlers.call(
"run_javascript",
{"script": "2 + 2"},
neverCancelled,
)
self.assertEqual(
result["structuredContent"],
{"result": 4, "result_type": "number"},
)
self.assertEqual(
browser.calls,
[("2 + 2", 30000, neverCancelled)],
)
async def test_rejects_invalid_javascript_arguments(self) -> None:
handlers = ToolHandlers(FakeBrowser())
cases = (
{},
{"script": ""},
{"script": "1", "timeout_ms": 0},
{"script": "1", "extra": True},
)
for arguments in cases:
with self.subTest(arguments=arguments):
with self.assertRaises(InvalidArgumentsError):
await handlers.call(
"run_javascript",
arguments,
neverCancelled,
)
if __name__ == "__main__":
unittest.main()