fix(chv-muse-round12): 移植 round-11 的 Page.aria_snapshot() 纠正到 CDP broker

Playwright 1.64.1 没有 page.accessibility(Puppeteer 的 API),
broker 的 snapshot 调它必走异常分支。改调 Page.aria_snapshot()
(字符串);guard 的 truncate_a11y 换成字符串版 truncate_aria
(179a86d 原样),detect_injection/detect_form_risk 加字符串
分支(dict 分支保留);两边 fake 与 P4 文档同步改。a11y-only
契约不变:不读原始 DOM、不走 JS eval。

测试:test_chv_muse_p2 + test_chv_muse_p4 114 OK;全量 2523 OK
(skipped=10)。
This commit is contained in:
host committed 2026-11-07 18:24:58 +00:00
1 parent 9da74c2a78
commit 114b444554
6 files changed
+209 -129

No files matched your search

+25 -24
View File
@@ -384,26 +384,27 @@ class BrowserTest(unittest.TestCase):
ok, _ = GUARD.validate_url(bad)
self.assertFalse(ok, bad)
def test_truncate_a11y_small_tree_untouched(self):
tree = {"role": "WebArea", "name": "Example",
"children": [{"role": "heading", "name": "Hi"}]}
out, truncated = GUARD.truncate_a11y(tree)
def test_truncate_aria_small_snapshot_untouched(self):
text = ("- generic [ref=e1]:\n"
" - heading \"Example Domain\" [level=1] [ref=e2]")
out, truncated = GUARD.truncate_aria(text)
self.assertFalse(truncated)
self.assertEqual(out, tree)
self.assertEqual(out, text)
def test_truncate_a11y_node_cap(self):
tree = {"role": "WebArea",
"children": [{"role": "link", "name": "l%d" % i}
for i in range(300)]}
out, truncated = GUARD.truncate_a11y(tree)
def test_truncate_aria_node_cap(self):
text = "\n".join("- link \"l%d\" [ref=e%d]" % (i, i)
for i in range(300))
out, truncated = GUARD.truncate_aria(text)
self.assertTrue(truncated)
self.assertLessEqual(len(out["children"]), 200)
nodes = [ln for ln in out.splitlines()
if ln.lstrip().startswith("- ")]
self.assertLessEqual(len(nodes), 200)
def test_truncate_a11y_char_cap(self):
tree = {"role": "WebArea", "name": "x" * 70000, "children": []}
out, truncated = GUARD.truncate_a11y(tree)
def test_truncate_aria_char_cap(self):
text = "- paragraph \"" + "x" * 70000 + "\" [ref=e1]"
out, truncated = GUARD.truncate_aria(text)
self.assertTrue(truncated)
self.assertTrue(out.get("truncated_chars"))
self.assertLessEqual(len(out), GUARD.MAX_A11Y_CHARS)
def test_forbidden_ops_never_execute(self):
agent = mock.Mock()
@@ -439,11 +440,11 @@ class BrowserTest(unittest.TestCase):
self.assertTrue(resp["ok"])
self.assertEqual(resp["title"], "Example Domain")
self.assertEqual(resp["url"], "https://example.com/")
# P4:a11y 是 broker 回包的 dict 树(经 guard 截断)。
# round-11 的 ARIA 字符串纠正(Page.aria_snapshot())
# 在 P4 架构里应落在 chv-cdp-broker.py 的 snapshot,
# 本轮合入未移植(见合入报告未决问题),此处不断言 str。
self.assertEqual(resp["a11y"]["role"], "WebArea")
# round-12 移植 round-11 的 ARIA 字符串纠正
#(Page.aria_snapshot()):a11y 是 ARIA 快照字符串,
# 不是 dict 树;快照走 chv-cdp-broker.py 的 snapshot。
self.assertIsInstance(resp["a11y"], str)
self.assertIn("Example Domain", resp["a11y"])
self.assertFalse(resp["truncated"])
snap = agent.snapshot()
self.assertTrue(snap["ok"])
@@ -495,17 +496,17 @@ class FakeCdpBroker:
def __call__(self, req):
self.calls.append(req.get("op"))
op = req.get("op")
tree = {"role": "WebArea", "name": "Example Domain",
"children": [{"role": "heading", "name": "Example"}]}
aria = ("- generic [ref=e1]:\n"
" - heading \"Example Domain\" [level=1] [ref=e2]")
if op == "open":
self._open = True
return {"ok": True, "title": "Example Domain",
"url": "https://example.com/", "a11y": tree}
"url": "https://example.com/", "a11y": aria}
if op == "snapshot":
if not self._open:
return {"ok": False, "error": "尚未 open"}
return {"ok": True, "title": "Example Domain",
"url": "https://example.com/", "a11y": tree}
"url": "https://example.com/", "a11y": aria}
if op == "screenshot":
if not self._open:
return {"ok": False, "error": "尚未 open"}