feat: 完成T-205账号就绪引导保护
CollectWorker 增加采集前账号就绪预检:无账号、匹配账号 CDP 端口未响应或未登录时返回 blocked,不进入逐条采集,也不写 skipped/failed。 CollectTab 收到 blocked 后弹窗汇总原因,并跳转/引导到④账号管理配置账号、启动对应 Chrome、人工登录;MainWindow 为①传入打开④的回调。 新增 GUI 测试覆盖无账号、Chrome 未启动、未登录和弹窗引导;同步 T-205 状态、api、current-state 与 progress。
This commit is contained in:
+144
-1
@@ -33,6 +33,12 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
def setUpClass(cls):
|
||||
cls.app = QApplication.instance() or QApplication([])
|
||||
|
||||
def tearDown(self):
|
||||
for widget in QApplication.topLevelWidgets():
|
||||
widget.close()
|
||||
widget.deleteLater()
|
||||
self.app.processEvents()
|
||||
|
||||
def make_config(self, temp_dir):
|
||||
return {
|
||||
"chrome_path": "chrome.exe",
|
||||
@@ -369,7 +375,12 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
with mock.patch("app.gui.accounts.detect_login", side_effect=fake_login), \
|
||||
mock.patch("app.gui.editor.collect", side_effect=fake_collect) as collect:
|
||||
summary = CollectWorker(tasks, db_path=cfg["db_path"], config=cfg).execute()
|
||||
summary = CollectWorker(
|
||||
tasks,
|
||||
db_path=cfg["db_path"],
|
||||
config=cfg,
|
||||
preflight=False,
|
||||
).execute()
|
||||
|
||||
self.assertEqual({"ok": True, "total": 3, "done": 3, "collected": 1, "skipped": 2, "failed": 0}, summary)
|
||||
collect.assert_called_once()
|
||||
@@ -453,6 +464,138 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_worker_preflight_blocks_when_no_accounts(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
db.init_db(cfg["db_path"])
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
}
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
|
||||
summary = CollectWorker(tasks, db_path=cfg["db_path"], config=cfg).execute()
|
||||
|
||||
self.assertTrue(summary["blocked"])
|
||||
self.assertTrue(summary["no_accounts"])
|
||||
self.assertEqual("NO_ACCOUNTS", summary["reason"])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_worker_preflight_blocks_when_chrome_not_running(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
}
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
|
||||
with mock.patch("app.gui.chrome.is_running", return_value=False) as is_running, \
|
||||
mock.patch("app.gui.accounts.detect_login") as detect_login, \
|
||||
mock.patch("app.gui.editor.collect") as collect:
|
||||
summary = CollectWorker(tasks, db_path=cfg["db_path"], config=cfg).execute()
|
||||
|
||||
self.assertTrue(summary["blocked"])
|
||||
self.assertEqual("ACCOUNT_NOT_READY", summary["reason"])
|
||||
self.assertEqual("alias-a", summary["not_running"][0]["alias"])
|
||||
is_running.assert_called_once_with(9222)
|
||||
detect_login.assert_not_called()
|
||||
collect.assert_not_called()
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_worker_preflight_blocks_when_account_not_logged_in(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
}
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
|
||||
with mock.patch("app.gui.chrome.is_running", return_value=True), \
|
||||
mock.patch(
|
||||
"app.gui.accounts.detect_login",
|
||||
return_value={"logged_in": False, "reason": "LOGIN_PAGE"},
|
||||
), mock.patch("app.gui.editor.collect") as collect:
|
||||
summary = CollectWorker(tasks, db_path=cfg["db_path"], config=cfg).execute()
|
||||
|
||||
self.assertTrue(summary["blocked"])
|
||||
self.assertEqual("alias-a", summary["logged_out"][0]["alias"])
|
||||
self.assertIn("账号未登录", summary["logged_out"][0]["reason"])
|
||||
collect.assert_not_called()
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_tab_blocked_preflight_guides_to_accounts_tab(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
opened = []
|
||||
statuses = []
|
||||
tab = CollectTab(
|
||||
config=self.make_config(temp_dir),
|
||||
status_callback=statuses.append,
|
||||
open_accounts_callback=lambda: opened.append(True),
|
||||
)
|
||||
self.addCleanup(tab.close)
|
||||
payload = {
|
||||
"blocked": True,
|
||||
"not_running": [
|
||||
{
|
||||
"account_name": "主店",
|
||||
"alias": "alias-a",
|
||||
"reason": "CDP 端口未响应",
|
||||
}
|
||||
],
|
||||
"logged_out": [],
|
||||
}
|
||||
|
||||
with mock.patch("app.gui.QMessageBox.warning") as warning:
|
||||
tab._on_collect_finished(payload)
|
||||
|
||||
message = warning.call_args[0][2]
|
||||
self.assertIn("Chrome 未启动", message)
|
||||
self.assertIn("④ 账号管理", message)
|
||||
self.assertEqual([True], opened)
|
||||
self.assertIn("④ 账号管理", statuses[-1])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_write_back_worker_calls_excel_write_back(self):
|
||||
with mock.patch(
|
||||
"app.gui.excel.write_back",
|
||||
|
||||
Reference in New Issue
Block a user