fix: capture invalid product toast and close failed tabs

This commit is contained in:
chengma
2026-07-02 21:46:32 +08:00
parent f3e0956cf6
commit b9f614b8e7
11 changed files with 378 additions and 28 deletions
+97 -1
View File
@@ -39,10 +39,23 @@ class FakeCDP:
class FakeProductCDP:
def __init__(self, ws):
def __init__(self, ws, ready=True, toasts=None):
self.ws = ws
self.ready = ready
self.toasts = list(toasts or [])
self.closed = False
self.sent = []
self.toast_observer_installed = False
def val(self, expr):
if expr == editor.JS_READY:
return self.ready
if expr == editor.JS_INSTALL_TOAST_OBSERVER:
self.toast_observer_installed = True
return True
if expr == editor.JS_PAGE_TOASTS:
return json.dumps(self.toasts)
return None
def send(self, method, params=None):
self.sent.append((method, params or {}))
@@ -439,6 +452,89 @@ class EditorLoginTests(unittest.TestCase):
self.assertEqual("127.0.0.1:9223", cdp.cdp_host)
create_tab_info.assert_called_once()
def test_open_product_installs_toast_observer(self):
fake = FakeProductCDP("ws-new", ready=True)
with mock.patch("app.editor.find_product_tab", return_value=None), mock.patch(
"app.editor.create_tab_info",
return_value={"id": "target-new", "webSocketDebuggerUrl": "ws-new"},
), mock.patch("app.editor.CDP", return_value=fake), mock.patch(
"app.editor._ensure_page_domains"
), mock.patch("app.editor.time.sleep"):
cdp = editor.open_product({"debug_port": 9223}, "51100639511")
self.assertIs(fake, cdp)
self.assertTrue(fake.toast_observer_installed)
self.assertIn(
("Page.addScriptToEvaluateOnNewDocument", {"source": editor.JS_TOAST_OBSERVER_SOURCE}),
fake.sent,
)
def test_wait_ready_raises_product_unavailable_from_hidden_toast(self):
fake = FakeProductCDP(
"ws-new",
ready=False,
toasts=[
{
"text": "please input correct product id",
"html": "<div class='eds-toast__content'>please input correct product id</div>",
"url": "https://seller.shopee.tw/portal/product/invalid",
"visible": False,
"created_at": "2026-07-02T00:00:00Z",
}
],
)
with self.assertRaises(editor.EditorError) as ctx:
editor._wait_ready(fake, timeout=0)
self.assertIn("商品失效", str(ctx.exception))
self.assertIn("please input correct product id", str(ctx.exception))
toasts = editor.read_page_toasts(fake)
self.assertEqual("please input correct product id", toasts[0]["text"])
self.assertFalse(toasts[0]["visible"])
def test_open_product_closes_auto_created_tab_when_unavailable(self):
fake = FakeProductCDP(
"ws-new",
ready=False,
toasts=[{"text": "please input correct product id", "visible": False}],
)
with mock.patch("app.editor.find_product_tab", return_value=None), mock.patch(
"app.editor.create_tab_info",
return_value={"id": "target-new", "webSocketDebuggerUrl": "ws-new"},
), mock.patch("app.editor.CDP", return_value=fake), mock.patch(
"app.editor._ensure_page_domains"
), mock.patch("app.editor.close_tab", return_value=True) as close_tab:
with self.assertRaises(editor.EditorError) as ctx:
editor.open_product({"debug_port": 9223}, "bad-item")
self.assertIn("商品失效", str(ctx.exception))
self.assertTrue(fake.closed)
close_tab.assert_called_once_with("target-new", host="127.0.0.1:9223")
def test_open_product_keeps_reused_tab_when_unavailable(self):
fake = FakeProductCDP(
"ws-existing",
ready=False,
toasts=[{"text": "please input correct product id", "visible": False}],
)
with mock.patch(
"app.editor.find_product_tab",
return_value={"id": "target-existing", "webSocketDebuggerUrl": "ws-existing"},
), mock.patch("app.editor.create_tab_info") as create_tab_info, mock.patch(
"app.editor.CDP",
return_value=fake,
), mock.patch("app.editor._ensure_page_domains"), mock.patch(
"app.editor.close_tab",
return_value=True,
) as close_tab:
with self.assertRaises(editor.EditorError):
editor.open_product({"debug_port": 9223}, "bad-item")
self.assertTrue(fake.closed)
close_tab.assert_not_called()
create_tab_info.assert_not_called()
def test_collect_closes_only_auto_created_product_tab(self):
cdp = FakeProductCDP("ws-new")
cdp.target_id = "target-new"