feat: 实现 PDD 任务详情窗口 (#39)
This commit is contained in:
@@ -225,6 +225,65 @@ class PDDTaskPageEventTest(unittest.TestCase):
|
||||
self.assertFalse(page.taskModel.canFetchMore())
|
||||
page.deleteLater()
|
||||
|
||||
def test_detail_signal_opens_one_reusable_non_modal_window(self):
|
||||
self._add_task(1)
|
||||
started = self.repository.start_collect_run("PDD-001", "USB-001")
|
||||
self.repository.save_collect_result(
|
||||
"PDD-001",
|
||||
started.attempt_id,
|
||||
{
|
||||
"goods_id": "1",
|
||||
"title": "测试商品",
|
||||
"dimensions": [
|
||||
{
|
||||
"key": "color",
|
||||
"name": "颜色",
|
||||
"values": [{"text": "黑色", "available": True}],
|
||||
},
|
||||
{
|
||||
"key": "size",
|
||||
"name": "尺码",
|
||||
"values": [{"text": "M", "available": True}],
|
||||
},
|
||||
],
|
||||
"skus": [
|
||||
{
|
||||
"options": {"color": "黑色", "size": "M"},
|
||||
"price_cent": 3990,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(page, self.repository)
|
||||
|
||||
page.detailRequested.emit("PDD-001")
|
||||
self.app.processEvents()
|
||||
first = events._detail_windows["PDD-001"]
|
||||
self.assertTrue(first.isVisible())
|
||||
self.assertFalse(first.isModal())
|
||||
|
||||
page.detailRequested.emit("PDD-001")
|
||||
self.app.processEvents()
|
||||
self.assertIs(events._detail_windows["PDD-001"], first)
|
||||
|
||||
first.close()
|
||||
self.app.processEvents()
|
||||
self.assertNotIn("PDD-001", events._detail_windows)
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_missing_detail_does_not_open_empty_window(self):
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(page, self.repository)
|
||||
|
||||
page.detailRequested.emit("PDD-NOT-FOUND")
|
||||
self.app.processEvents()
|
||||
|
||||
self.assertEqual(events._detail_windows, {})
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_summary_to_row_does_not_copy_detail_json(self):
|
||||
summary = TaskSummary(
|
||||
id=1,
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
"""任务详情数据整理和窗口的离屏测试。"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from src.task_detail_view import TaskDetailWindow, build_task_detail_view_data
|
||||
from src.task_models import TaskDetail, TaskStatus, TaskType
|
||||
|
||||
|
||||
def make_detail(pdd_data=None) -> TaskDetail:
|
||||
return TaskDetail(
|
||||
id=1,
|
||||
remote_task_id="COL-001",
|
||||
task_type=TaskType.COLLECT,
|
||||
goods_id="123",
|
||||
goods_url="https://mobile.yangkeduo.com/goods.html?goods_id=123",
|
||||
title="本地标题",
|
||||
target_color=None,
|
||||
target_size=None,
|
||||
price_cent=None,
|
||||
quantity=None,
|
||||
status=TaskStatus.SUCCEEDED,
|
||||
current_step="completed",
|
||||
priority=0,
|
||||
version=1,
|
||||
admin_payload={},
|
||||
pdd_data=pdd_data,
|
||||
retry_count=0,
|
||||
last_error_code=None,
|
||||
last_error_message=None,
|
||||
received_at="2026-08-08T08:00:00Z",
|
||||
started_at="2026-08-08T08:01:00Z",
|
||||
finished_at="2026-08-08T08:02:00Z",
|
||||
created_at="2026-08-08T08:00:00Z",
|
||||
updated_at="2026-08-08T08:02:00Z",
|
||||
)
|
||||
|
||||
|
||||
def collected_data():
|
||||
return {
|
||||
"goods_id": "123",
|
||||
"title": "采集标题",
|
||||
"shop_name": "测试店铺",
|
||||
"captured_at": "2026-08-08T08:02:00Z",
|
||||
"metrics": {
|
||||
"sales": {"value": 1200, "raw": "已拼1.2千件"},
|
||||
"reviews": {"value": 68, "raw": "68条评价"},
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"key": "color",
|
||||
"name": "颜色",
|
||||
"values": [
|
||||
{"text": "黑色", "available": True},
|
||||
{"text": "白色", "available": False},
|
||||
{"text": "黑色", "available": True},
|
||||
],
|
||||
},
|
||||
{
|
||||
"key": "size",
|
||||
"name": "尺码",
|
||||
"values": [
|
||||
{"text": "M", "available": True},
|
||||
{"text": "L", "available": True},
|
||||
{"text": "M", "available": True},
|
||||
],
|
||||
},
|
||||
],
|
||||
"skus": [
|
||||
{"options": {"color": "黑色", "size": "M"}, "price_cent": 1000},
|
||||
{"options": {"color": "黑色", "size": "L"}, "price_cent": 1200},
|
||||
{"options": {"color": "白色", "size": "M"}, "price_cent": None},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class TaskDetailViewTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.app = QApplication.instance() or QApplication([])
|
||||
|
||||
def test_colors_keep_order_deduplicate_and_show_price_state(self):
|
||||
data = build_task_detail_view_data(make_detail(collected_data()))
|
||||
|
||||
self.assertEqual([item.text for item in data.colors], ["黑色", "白色"])
|
||||
self.assertEqual(data.colors[0].price_text, "¥10.00~¥12.00")
|
||||
self.assertTrue(data.colors[0].price_inconsistent)
|
||||
self.assertEqual(data.colors[1].price_text, "价格未采集")
|
||||
self.assertFalse(data.colors[1].available)
|
||||
self.assertEqual(data.sizes, ["M", "L"])
|
||||
|
||||
def test_old_data_can_restore_dimensions_from_skus(self):
|
||||
data = collected_data()
|
||||
data["dimensions"] = []
|
||||
|
||||
view_data = build_task_detail_view_data(make_detail(data))
|
||||
|
||||
self.assertEqual([item.text for item in view_data.colors], ["黑色", "白色"])
|
||||
self.assertEqual(view_data.sizes, ["M", "L"])
|
||||
|
||||
def test_empty_collection_data_has_clear_empty_values(self):
|
||||
data = build_task_detail_view_data(make_detail())
|
||||
|
||||
self.assertEqual(data.colors, [])
|
||||
self.assertEqual(data.sizes, [])
|
||||
self.assertEqual(data.shop_name, "未采集")
|
||||
self.assertEqual(data.sales, "未采集")
|
||||
|
||||
def test_window_builds_color_section_before_size_section(self):
|
||||
window = TaskDetailWindow(make_detail(collected_data()))
|
||||
|
||||
self.assertEqual(len(window.colorItems), 2)
|
||||
self.assertEqual(len(window.sizeItems), 2)
|
||||
self.assertIn("COL-001", window.windowTitle())
|
||||
self.assertTrue(window.isWindow())
|
||||
window.close()
|
||||
self.app.processEvents()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user