more extensive tests for edge cases

This commit is contained in:
STJ 2026-03-16 20:01:07 -07:00
parent 3982d50573
commit 6ae56c0cbb
2 changed files with 105 additions and 13 deletions

View file

@ -10,7 +10,7 @@ class Browser:
self._agent_id = agent_id
self._agent_state = agent_state
def __getattr__(self, action):
def _call(self, action, **kwargs):
import asyncio
from strix.tools.browser.browser_actions import browser_action
@ -18,21 +18,25 @@ class Browser:
from .conftest import _bg_loop
def call(**kwargs):
async def _run():
set_current_agent_id(self._agent_id)
return await browser_action(
agent_state=self._agent_state,
action=action,
**kwargs,
)
async def _run():
set_current_agent_id(self._agent_id)
return await browser_action(
agent_state=self._agent_state,
action=action,
**kwargs,
)
future = asyncio.run_coroutine_threadsafe(_run(), _bg_loop)
result = future.result(timeout=120)
future = asyncio.run_coroutine_threadsafe(_run(), _bg_loop)
result = future.result(timeout=120)
if "screenshot" in result:
result["screenshot"] = "[Image]"
return result
def __getattr__(self, action):
def call(**kwargs):
result = self._call(action, **kwargs)
if "error" in result:
Fail(result).error(result["error"])
if "screenshot" in result:
result["screenshot"] = "[Image]"
return result
return call

View file

@ -1,3 +1,5 @@
from concurrent.futures import ThreadPoolExecutor
import pytest
from . import console as ui
@ -147,3 +149,89 @@ def test_relaunch_parallel_no_side_effects(browsers: list[Browser]) -> None:
Fail(a_state).expected("agent A on example.com").got(a_state.get("url"))
if "iana.org" not in b_state.get("url", ""):
Fail(b_state).expected("agent B on iana.org").got(b_state.get("url"))
def test_dialog_does_not_block_other_agent(browsers: list[Browser]) -> None:
a, b = browsers
a.navigate(url="https://example.com")
b.navigate(url="https://example.com")
a._call("evaluate", code="setTimeout(() => alert('blocked'), 0)")
result = b._call("evaluate", code="document.title")
ui.log(f"agent B after A's alert: {result}")
if "error" in result:
Fail(result).error(f"agent B blocked by A's dialog: {result['error']}")
def test_close_during_active_operation(browsers: list[Browser]) -> None:
a, b = browsers
a.navigate(url="https://example.com")
b.navigate(url="https://example.com")
def slow_b():
return b._call(
"evaluate", code="new Promise(r => setTimeout(() => r(document.title), 2000))"
)
def close_a():
import time
time.sleep(0.5)
return a._call("close_browser")
with ThreadPoolExecutor(max_workers=2) as pool:
fut_b = pool.submit(slow_b)
fut_a = pool.submit(close_a)
fut_a.result(timeout=10)
result_b = fut_b.result(timeout=10)
ui.log(f"agent B after A closed mid-action: {result_b}")
if "error" in result_b:
Fail(result_b).error(f"agent B broke when A closed mid-action: {result_b['error']}")
def test_concurrent_context_disposal(browsers: list[Browser]) -> None:
a, b = browsers
a.navigate(url="https://example.com")
b.navigate(url="https://example.com")
def dispose_a():
return a._call("close_browser")
def new_tab_b():
return b._call(
"evaluate", code="window.open('https://example.com', '_blank'); document.title"
)
with ThreadPoolExecutor(max_workers=2) as pool:
fut_a = pool.submit(dispose_a)
fut_b = pool.submit(new_tab_b)
fut_a.result(timeout=10)
result_b = fut_b.result(timeout=10)
ui.log(f"agent B after concurrent disposal: {result_b}")
if "error" in result_b:
Fail(result_b).error(f"B's tab creation broke during A's disposal: {result_b['error']}")
def test_duplicate_launch_race(browsers: list[Browser]) -> None:
a, _ = browsers
a.close_browser()
def launch():
return a._call("launch")
with ThreadPoolExecutor(max_workers=2) as pool:
results = [f.result(timeout=30) for f in [pool.submit(launch), pool.submit(launch)]]
ui.log(f"race launch results: {[r.get('message') for r in results]}")
for r in results:
if "error" in r:
Fail(r).error(f"race launch failed: {r['error']}")
result = a._call("navigate", url="https://example.com")
if "error" in result:
Fail(result).error(f"session unusable after race: {result['error']}")
if "example.com" not in result.get("url", ""):
Fail(result).expected("url containing 'example.com'").got(result.get("url"))