"""uiautomator2 采购演练 Adapter 测试;不连接真实手机。""" import unittest from src.pdd_device_service import PddDeviceService from src.pdd_purchase_adapter import PddPurchaseError from src.pdd_u2_purchase_adapter import U2PddPurchaseAdapter GOODS_URL = "https://mobile.yangkeduo.com/goods.html?goods_id=753136429979" def home_xml() -> str: return """ """ def panel_xml(quantity: int = 1) -> str: return f""" """ class FakeEditor: def __init__(self, device) -> None: self.device = device self.count = 1 def set_text(self, value: str) -> None: self.device.quantity = int(value) class FakeDevice: def __init__(self, initial_xml: str = "") -> None: self.mode = "special" if initial_xml else "home" self.special_xml = initial_xml self.quantity = 1 self.clicks = [] self.opened_urls = [] def app_current(self): return {"package": "com.xunmeng.pinduoduo"} def app_start(self, _package): pass def app_wait(self, _package, timeout=10): return True def open_url(self, url): self.opened_urls.append(url) def dump_hierarchy(self): if self.mode == "special": return self.special_xml return home_xml() if self.mode == "home" else panel_xml(self.quantity) def click(self, x, y): self.clicks.append((x, y)) self.mode = "panel" def __call__(self, **selector): if selector == {"className": "android.widget.EditText"}: return FakeEditor(self) raise AssertionError(f"未预期的 selector: {selector}") class U2PddPurchaseAdapterTest(unittest.TestCase): def _adapter(self, device, calls): def select_color_fn(_device, _xml, target, **_kwargs): calls.append(("color", target)) return target == "黑色" def select_size_fn(_device, _xml, target, **_kwargs): calls.append(("size", target)) return target == "3XL【140-165斤】" return U2PddPurchaseAdapter( "USB-001", device_service=PddDeviceService(connector=lambda _serial: device), sleeper=lambda _seconds: None, select_color_fn=select_color_fn, select_size_fn=select_size_fn, ) def test_dry_run_reaches_confirmation_without_clicking_submit(self): device = FakeDevice() calls = [] adapter = self._adapter(device, calls) adapter.open_goods(GOODS_URL) goods = adapter.read_state() adapter.select_options( {"color": "黑色", "size": "3XL【140-165斤】"} ) adapter.set_quantity(2) confirmation = adapter.read_state() adapter.enter_confirmation() adapter.stop_before_submit() adapter.close() self.assertEqual(goods.page_kind, "goods") self.assertEqual(goods.goods_id, "753136429979") self.assertEqual( confirmation.selected_options, {"color": "黑色", "size": "3XL【140-165斤】"}, ) self.assertEqual(confirmation.quantity, 2) self.assertEqual(confirmation.price_cent, 503) self.assertEqual(confirmation.page_kind, "order_confirmation") self.assertEqual(calls, [("color", "黑色"), ("size", "3XL【140-165斤】")]) # 只点击一次商品页采购入口;最终“提交订单”从不点击。 self.assertEqual(len(device.clicks), 1) def test_unsupported_dynamic_option_stops_before_click(self): device = FakeDevice() adapter = self._adapter(device, []) adapter.open_goods(GOODS_URL) with self.assertRaises(PddPurchaseError) as raised: adapter.select_options({"bundle": "标准版"}) self.assertEqual(raised.exception.code, "PURCHASE_OPTIONS_UNSUPPORTED") self.assertEqual(device.clicks, []) adapter.close() def test_captcha_stops_without_waiting_or_clicking(self): device = FakeDevice( '' ) adapter = self._adapter(device, []) with self.assertRaises(PddPurchaseError) as raised: adapter.open_goods(GOODS_URL) self.assertEqual(raised.exception.code, "PDD_PAGE_CAPTCHA") self.assertEqual(device.clicks, []) adapter.close() def test_invalid_non_pdd_url_is_rejected_before_connect(self): device = FakeDevice() adapter = self._adapter(device, []) with self.assertRaises(PddPurchaseError) as raised: adapter.open_goods("https://example.test/goods?goods_id=1") self.assertEqual(raised.exception.code, "PURCHASE_GOODS_URL_INVALID") self.assertEqual(device.opened_urls, []) if __name__ == "__main__": unittest.main()