fix: 兼容非滚动图片颜色采购选择 (#178)

This commit is contained in:
chengma
2026-08-12 10:48:36 +08:00
parent 69b3200665
commit cd9c552a77
4 changed files with 287 additions and 3 deletions
@@ -240,6 +240,21 @@ class ContextualConfirmPanelDevice(FakeDevice):
self.mode = "panel"
class SubmitHintPanelDevice(FakeDevice):
"""模拟带提交提示的非滚动图片颜色面板。"""
def __init__(self, panel_data: str) -> None:
super().__init__()
self.panel_data = panel_data
def dump_hierarchy(self):
if not self.has_opened:
return '<hierarchy><node package="com.xunmeng.pinduoduo" /></hierarchy>'
if self.mode == "panel":
return self.panel_data
return home_xml()
def address_confirmation_xml(address: str) -> str:
return f"""<hierarchy>
<node package="com.xunmeng.pinduoduo" bounds="[0,0][1080,2376]">
@@ -827,6 +842,40 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
self.assertIn("[已脱敏]", content)
adapter.close()
def test_color_mismatch_reports_reason_and_saves_sanitized_tree(self):
panel_data = (
FIXTURES / "pdd_spec_panel_submit_hint.xml"
).read_text(encoding="utf-8")
device = SubmitHintPanelDevice(panel_data)
with tempfile.TemporaryDirectory() as directory:
adapter = U2PddPurchaseAdapter(
"USB-001",
device_service=PddDeviceService(
connector=lambda _serial: device
),
sleeper=lambda _seconds: None,
select_color_fn=lambda *_args, **_kwargs: False,
artifact_directory=Path(directory),
)
adapter.open_goods(GOODS_URL)
with self.assertRaises(PddPurchaseError) as raised:
adapter.select_options({"color": "测试黑色"})
self.assertEqual(
raised.exception.code, "PURCHASE_OPTIONS_MISMATCH"
)
self.assertIn("点击颜色后", raised.exception.message)
self.assertEqual(
raised.exception.diagnostics["selection_failure"],
"selection_unconfirmed",
)
artifact = raised.exception.diagnostics["artifacts"][0]
content = Path(artifact["path"]).read_text(encoding="utf-8")
self.assertNotIn("测试黑色", content)
self.assertIn("[已脱敏]", content)
adapter.close()
def test_invalid_non_pdd_url_is_rejected_before_connect(self):
device = FakeDevice()
adapter = self._adapter(device, [])
+127
View File
@@ -0,0 +1,127 @@
"""采购规格颜色选择测试;只使用脱敏 XML,不连接真机。"""
from pathlib import Path
import unittest
import xml.etree.ElementTree as ET
from src.util.select_color_size import (
color_selection_failure_reason,
select_color,
)
FIXTURES = Path(__file__).parent / "fixtures"
class StaticColorDevice:
"""模拟没有滚动属性的图片颜色规格面板。"""
def __init__(self, xml_data: str, confirm_selection: bool = True) -> None:
self.xml_data = xml_data
self.confirm_selection = confirm_selection
self.clicks = []
self.swipes = []
def dump_hierarchy(self) -> str:
return self.xml_data
def click(self, x: int, y: int) -> None:
self.clicks.append((x, y))
if not self.confirm_selection:
return
root = ET.fromstring(self.xml_data)
for node in root.iter("node"):
if node.get("text", "").strip() == "测试黑色":
node.set("selected", "true")
if node.get("text", "").strip().startswith("请选择"):
node.set("text", "已选: 测试黑色")
self.xml_data = ET.tostring(root, encoding="unicode")
def swipe(self, *args, **kwargs) -> None:
self.swipes.append((args, kwargs))
class StaticColorSelectionTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.panel_xml = (
FIXTURES / "pdd_spec_panel_submit_hint.xml"
).read_text(encoding="utf-8")
def test_tall_static_color_card_is_clicked_and_confirmed(self):
device = StaticColorDevice(self.panel_xml)
selected = select_color(
device,
self.panel_xml,
"测试黑色",
action_delay=0.001,
)
self.assertTrue(selected)
self.assertEqual(device.clicks, [(194, 1389)])
self.assertEqual(device.swipes, [])
def test_static_card_stops_when_click_is_not_confirmed(self):
device = StaticColorDevice(self.panel_xml, confirm_selection=False)
selected = select_color(
device,
self.panel_xml,
"测试黑色",
action_delay=0.001,
)
self.assertFalse(selected)
self.assertEqual(device.clicks, [(194, 1389)])
self.assertEqual(device.swipes, [])
self.assertEqual(
color_selection_failure_reason(
device.dump_hierarchy(), "测试黑色"
),
"selection_unconfirmed",
)
def test_partially_visible_static_card_is_not_clicked(self):
partial_xml = self.panel_xml.replace(
"[36,1188][352,1591]", "[0,1188][60,1591]"
).replace(
"[36,1188][352,1504]", "[0,1188][60,1504]"
).replace(
"[36,1483][352,1591]", "[0,1483][60,1591]"
)
device = StaticColorDevice(partial_xml)
selected = select_color(
device, partial_xml, "测试黑色", action_delay=0.001
)
self.assertFalse(selected)
self.assertEqual(device.clicks, [])
self.assertEqual(device.swipes, [])
self.assertEqual(
color_selection_failure_reason(partial_xml, "测试黑色"),
"safe_target_missing",
)
def test_card_crossing_size_heading_is_not_clicked(self):
crossing_xml = self.panel_xml.replace(
"[36,1188][352,1591]", "[36,1188][352,1700]"
).replace(
"[36,1188][352,1504]", "[36,1188][352,1660]"
).replace(
"[36,1483][352,1591]", "[36,1592][352,1700]"
)
device = StaticColorDevice(crossing_xml)
selected = select_color(
device, crossing_xml, "测试黑色", action_delay=0.001
)
self.assertFalse(selected)
self.assertEqual(device.clicks, [])
self.assertEqual(device.swipes, [])
if __name__ == "__main__":
unittest.main()