mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-30 11:49:50 +02:00
65 lines
3.2 KiB
Python
65 lines
3.2 KiB
Python
"""Container-scoped submit tier: the middle rung between the below-composer index pick and the
|
|
by-name 'Send' last resort, plus the expression builder's escaping. The JS itself is proven live
|
|
(X modal resolves tweetButton, inline resolves tweetButtonInline at hop 20); these tests pin the
|
|
tier ORDER and the fail-safe parse."""
|
|
import pytest
|
|
|
|
from backend.apps.agents.browser import browser_send_script as ss
|
|
from backend.apps.agents.browser import browser_submit_click as sc
|
|
from backend.apps.agents.browser.browser_agent import send_submit_index_in_state
|
|
|
|
# Committed fill whose submit ranks OUT of the capped listing (the shape that starves the picker).
|
|
COMPOSER_FILLED_NO_SEND = '[1]<textbox "I\'m looking for…">\n[24]<textbox "Write a message" value="[test] hello world r9-os">'
|
|
COMPOSER_SENT = '[2]<textbox "Write a message">\n[9]<button "Attach">'
|
|
|
|
|
|
def make_exec(eval_result):
|
|
calls = {"clicks": []}
|
|
|
|
async def execute(tool, params, bid, tid):
|
|
if tool == "BrowserListInteractives":
|
|
return {"text": COMPOSER_SENT}
|
|
calls["clicks"].append((tool, params))
|
|
if tool == "BrowserEvaluate":
|
|
return eval_result
|
|
return {"ok": True}
|
|
return execute, calls
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_container_submit_tier_between_index_and_by_name():
|
|
"""X's compose modal: covered feed rows behind the overlay eat the 60-row cap, so the modal's
|
|
own Post never reaches the picker (live 0/2 deliveries). The container-scoped JS tier clicks
|
|
the submit inside the composer's own container; by-name stays the last resort."""
|
|
execute, calls = make_exec({"value": {"ok": True, "name": "post"}})
|
|
r = await ss.complete_send("[test] hello world r9-os", COMPOSER_FILLED_NO_SEND,
|
|
"b1", "", execute, send_submit_index_in_state, composer_index=24)
|
|
assert r["clicked"] is True and r["sent"] is True
|
|
tools = [c[0] for c in calls["clicks"]]
|
|
assert "BrowserEvaluate" in tools and "BrowserClickByName" not in tools
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_container_submit_miss_falls_to_by_name():
|
|
execute, calls = make_exec({"value": {"ok": False, "why": "no submit control in the composer container"}})
|
|
r = await ss.complete_send("[test] hello world r9-os", COMPOSER_FILLED_NO_SEND,
|
|
"b1", "", execute, send_submit_index_in_state, composer_index=24)
|
|
assert r["clicked"] is True
|
|
tools = [c[0] for c in calls["clicks"]]
|
|
assert tools.index("BrowserEvaluate") < tools.index("BrowserClickByName")
|
|
|
|
|
|
def test_container_submit_expression_escapes_and_truncates():
|
|
expr = sc.container_submit_expression('he said "hi" ' + "x" * 60)
|
|
assert '\\"hi\\"' in expr # payload lands as a JS string literal, quotes escaped
|
|
assert "x" * 30 not in expr # truncated to the 24-char prefix the fill verifier uses
|
|
assert '"post"' in expr and '"send"' in expr
|
|
|
|
|
|
def test_parse_eval_value_reads_value_text_and_garbage():
|
|
assert sc.parse_eval_value({"value": {"ok": True}}) == {"ok": True}
|
|
assert sc.parse_eval_value({"text": '{"ok": false, "why": "x"}'}) == {"ok": False, "why": "x"}
|
|
assert sc.parse_eval_value({"text": "not json"}) is None
|
|
assert sc.parse_eval_value({"error": "boom"}) is None
|
|
assert sc.parse_eval_value("weird") is None
|