"""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()