fix: 等待多地址列表稳定加载 (#189)
This commit is contained in:
@@ -460,6 +460,50 @@ class MultipleAddressFlowDevice(AddressFlowDevice):
|
||||
super().click(x, y)
|
||||
|
||||
|
||||
class DelayedMultipleAddressFlowDevice(MultipleAddressFlowDevice):
|
||||
"""模拟地址标题先出现,地址列表稍后才进入控件树。"""
|
||||
|
||||
def __init__(self, loading_reads=2) -> None:
|
||||
super().__init__(default_indexes=(0,))
|
||||
self.loading_reads = loading_reads
|
||||
self.address_panel_reads = 0
|
||||
|
||||
def dump_hierarchy(self):
|
||||
if self.mode == "address_panel":
|
||||
self.address_panel_reads += 1
|
||||
if self.address_panel_reads <= self.loading_reads:
|
||||
return """<hierarchy>
|
||||
<node package="com.xunmeng.pinduoduo"
|
||||
bounds="[0,0][1080,2376]">
|
||||
<node package="com.xunmeng.pinduoduo" clickable="true"
|
||||
bounds="[0,102][217,226]">
|
||||
<node package="com.xunmeng.pinduoduo" text="返回"
|
||||
bounds="[38,132][98,195]"/>
|
||||
</node>
|
||||
<node package="com.xunmeng.pinduoduo" text="收货地址"
|
||||
bounds="[418,102][602,226]"/>
|
||||
</node>
|
||||
</hierarchy>"""
|
||||
return super().dump_hierarchy()
|
||||
|
||||
|
||||
class AlternatingDefaultAddressDevice(MultipleAddressFlowDevice):
|
||||
"""模拟默认地址目标坐标持续变化。"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(default_indexes=(0,))
|
||||
self.address_panel_reads = 0
|
||||
|
||||
def dump_hierarchy(self):
|
||||
if self.mode == "address_panel":
|
||||
self.address_panel_reads += 1
|
||||
indexes = (self.address_panel_reads % 2,)
|
||||
return multiple_address_panel_xml(
|
||||
self.address, default_indexes=indexes
|
||||
)
|
||||
return super().dump_hierarchy()
|
||||
|
||||
|
||||
class AmbiguousDefaultAddressDevice(MultipleAddressFlowDevice):
|
||||
"""模拟默认地址卡片内部出现两个修改目标。"""
|
||||
|
||||
@@ -864,6 +908,54 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
self.assertEqual(device.mode, "panel")
|
||||
adapter.close()
|
||||
|
||||
def test_address_list_can_load_after_panel_title(self):
|
||||
device = DelayedMultipleAddressFlowDevice(loading_reads=2)
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
adapter.update_shipping_address("cg11")
|
||||
|
||||
self.assertGreaterEqual(device.address_panel_reads, 4)
|
||||
self.assertEqual(device.address_modify_clicks, [(948, 571)])
|
||||
self.assertEqual(device.mode, "panel")
|
||||
adapter.close()
|
||||
|
||||
def test_address_list_missing_until_timeout_has_structural_diagnostics(self):
|
||||
clock = FakeClock()
|
||||
device = DelayedMultipleAddressFlowDevice(loading_reads=100)
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
panel_timeout=1.0,
|
||||
artifact_directory=Path(directory),
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
with self.assertRaises(PddPurchaseError) as raised:
|
||||
adapter.update_shipping_address("cg11")
|
||||
|
||||
diagnostics = raised.exception.diagnostics
|
||||
self.assertEqual(
|
||||
raised.exception.code, "PURCHASE_ADDRESS_EDIT_AMBIGUOUS"
|
||||
)
|
||||
self.assertEqual(diagnostics["address_card_count"], 0)
|
||||
self.assertEqual(diagnostics["default_card_count"], 0)
|
||||
self.assertEqual(diagnostics["candidate_count"], 0)
|
||||
self.assertEqual(diagnostics["stable_reads"], 0)
|
||||
self.assertEqual(device.address_modify_clicks, [])
|
||||
artifact = diagnostics["artifacts"][0]
|
||||
self.assertTrue(Path(artifact["path"]).is_file())
|
||||
adapter.close()
|
||||
|
||||
def test_default_address_can_be_second_card(self):
|
||||
device = MultipleAddressFlowDevice(default_indexes=(1,))
|
||||
adapter = self._live_adapter(device, [])
|
||||
@@ -885,7 +977,14 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
device = MultipleAddressFlowDevice(
|
||||
default_indexes=default_indexes
|
||||
)
|
||||
adapter = self._live_adapter(device, [])
|
||||
clock = FakeClock()
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
panel_timeout=1.0,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
@@ -900,11 +999,25 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
)
|
||||
self.assertEqual(device.address_modify_clicks, [])
|
||||
self.assertEqual(device.address_back_clicks, [])
|
||||
self.assertEqual(
|
||||
raised.exception.diagnostics["address_card_count"], 2
|
||||
)
|
||||
self.assertEqual(
|
||||
raised.exception.diagnostics["default_card_count"],
|
||||
len(default_indexes),
|
||||
)
|
||||
adapter.close()
|
||||
|
||||
def test_default_address_with_multiple_modify_targets_stops_safely(self):
|
||||
device = AmbiguousDefaultAddressDevice()
|
||||
adapter = self._live_adapter(device, [])
|
||||
clock = FakeClock()
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
panel_timeout=1.0,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
@@ -920,6 +1033,30 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
self.assertEqual(device.address_modify_clicks, [])
|
||||
adapter.close()
|
||||
|
||||
def test_changing_default_target_never_clicks_until_timeout(self):
|
||||
clock = FakeClock()
|
||||
device = AlternatingDefaultAddressDevice()
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
panel_timeout=1.0,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
with self.assertRaises(PddPurchaseError) as raised:
|
||||
adapter.update_shipping_address("cg11")
|
||||
|
||||
self.assertEqual(raised.exception.code, "PURCHASE_ADDRESS_PAGE_TIMEOUT")
|
||||
self.assertEqual(raised.exception.diagnostics["candidate_count"], 1)
|
||||
self.assertLessEqual(raised.exception.diagnostics["stable_reads"], 1)
|
||||
self.assertEqual(device.address_modify_clicks, [])
|
||||
adapter.close()
|
||||
|
||||
def test_saved_address_panel_can_hide_full_address(self):
|
||||
device = HiddenSavedAddressDevice()
|
||||
adapter = self._live_adapter(device, [])
|
||||
@@ -1095,8 +1232,15 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
adapter.close()
|
||||
|
||||
def test_address_edit_does_not_retry_when_modify_target_is_ambiguous(self):
|
||||
clock = FakeClock()
|
||||
device = AmbiguousAfterModifyAddressDevice()
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
panel_timeout=1.0,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
|
||||
Reference in New Issue
Block a user