fix: 商品页就绪后立即进入规格面板 (#36)

This commit is contained in:
chengma
2026-08-07 18:13:10 +08:00
parent 09b27cec42
commit e65cc2afda
6 changed files with 114 additions and 79 deletions
+63 -4
View File
@@ -33,6 +33,7 @@ class FakeCollectDevice:
self.panel_open = False
self.clicks = []
self.swipes = []
self.swipe_panel_states = []
def app_current(self):
return {"package": "com.xunmeng.pinduoduo"}
@@ -56,6 +57,7 @@ class FakeCollectDevice:
def swipe(self, *args, **kwargs):
self.swipes.append((args, kwargs))
self.swipe_panel_states.append(self.panel_open)
class LoadingDevice(FakeCollectDevice):
@@ -85,6 +87,11 @@ class FocusMismatchDevice(FakeCollectDevice):
self.app_started = True
class PanelDoesNotOpenDevice(FakeCollectDevice):
def click(self, x, y):
self.clicks.append((x, y))
def keep_only_one_sku(xml_data: str) -> str:
"""从脱敏固件中删除蓝色和 L,只保留一个组合。"""
@@ -176,7 +183,6 @@ class PddCollectParserTest(unittest.TestCase):
"client-001",
sleeper=lambda _seconds: None,
now=lambda: datetime(2026, 8, 7, 8, 0, tzinfo=timezone.utc),
max_page_swipes=1,
max_spec_swipes=1,
)
@@ -213,7 +219,6 @@ class PddCollectParserTest(unittest.TestCase):
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
max_page_swipes=0,
max_spec_swipes=0,
)
@@ -231,7 +236,6 @@ class PddCollectParserTest(unittest.TestCase):
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
max_page_swipes=0,
max_spec_swipes=0,
)
@@ -375,7 +379,6 @@ class PddCollectParserTest(unittest.TestCase):
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
max_page_swipes=0,
)
result = service.collect(
@@ -383,6 +386,62 @@ class PddCollectParserTest(unittest.TestCase):
)
self.assertIsNone(result.shop_name)
def test_missing_reviews_does_not_scroll_before_opening_spec_panel(self):
home_without_reviews = self.home_xml.replace(
'<node class="android.widget.TextView" text="2356条评价" '
'bounds="[330,950][600,1010]" visible-to-user="true" '
'enabled="true" />',
"",
)
device = FakeCollectDevice(
home_without_reviews, keep_only_one_sku(self.spec_xml)
)
service = PddCollectService(
PddDeviceService(lambda _serial: device),
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
max_spec_swipes=0,
)
result = service.collect(
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
)
self.assertIsNone(result.reviews.raw)
self.assertTrue(device.clicks)
self.assertTrue(all(device.swipe_panel_states))
def test_spec_panel_timeout_has_stable_code_and_xml_evidence(self):
with tempfile.TemporaryDirectory() as directory:
device = PanelDoesNotOpenDevice(self.home_xml, self.spec_xml)
tick = {"value": -0.5}
def clock():
tick["value"] += 0.5
return tick["value"]
service = PddCollectService(
PddDeviceService(lambda _serial: device),
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
monotonic=clock,
spec_panel_timeout=1.0,
artifact_directory=Path(directory),
)
with self.assertRaises(PddCollectError) as raised:
service.collect(
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
)
self.assertEqual(
raised.exception.code, "PDD_PAGE_SPEC_PANEL_TIMEOUT"
)
artifacts = raised.exception.diagnostics["artifacts"]
self.assertTrue(Path(artifacts[0]["path"]).is_file())
if __name__ == "__main__":
unittest.main()
@@ -9,6 +9,7 @@ from src.pdd_collect_service import (
parse_spec_panel,
)
from src.pdd_device_service import PddDeviceService
from src.util.get_size_panle_coord import get_size_panel_coord
REAL_XML = Path(__file__).parents[1] / "image_xml"
@@ -74,6 +75,14 @@ class PddRealXmlFixtureTest(unittest.TestCase):
self.assertEqual(result.price_cent, 470)
self.assertEqual(result.list_price_cent, 1990)
def test_real_home_xml_has_immediate_spec_entry(self):
xml_data = (REAL_XML / "737116531267_home.xml").read_text(
encoding="utf-8"
)
coordinate = get_size_panel_coord(xml_data)
self.assertIsNotNone(coordinate)
self.assertGreater(coordinate[1], 2000)
if __name__ == "__main__":
unittest.main()