fix: 多地址面板选择默认地址 (#187)
This commit is contained in:
@@ -294,6 +294,56 @@ def address_panel_xml(address: str) -> str:
|
||||
</hierarchy>"""
|
||||
|
||||
|
||||
def multiple_address_panel_xml(
|
||||
address: str, *, default_indexes=(0,)
|
||||
) -> str:
|
||||
"""按真机多地址结构构造不含个人数据的最小控件树。"""
|
||||
|
||||
cards = []
|
||||
for index, (top, bottom) in enumerate(((226, 654), (654, 1083))):
|
||||
modify_top = 544 if index == 0 else 973
|
||||
marker = "已设默认" if index in default_indexes else "使用"
|
||||
marker_top = 547 if index == 0 else 817
|
||||
address_text = address if index in default_indexes else "备用测试地址"
|
||||
cards.append(f"""
|
||||
<node package="com.xunmeng.pinduoduo"
|
||||
class="android.view.ViewGroup" bounds="[0,{top}][1020,{bottom}]">
|
||||
<node package="com.xunmeng.pinduoduo" text="{address_text}"
|
||||
class="android.widget.TextView" bounds="[32,{top + 120}][825,{top + 240}]"/>
|
||||
<node package="com.xunmeng.pinduoduo" clickable="true"
|
||||
bounds="[32,{marker_top - 20}][249,{marker_top + 75}]">
|
||||
<node package="com.xunmeng.pinduoduo" text="{marker}"
|
||||
class="android.widget.TextView"
|
||||
bounds="[89,{marker_top}][249,{marker_top + 48}]"/>
|
||||
</node>
|
||||
<node package="com.xunmeng.pinduoduo" clickable="true"
|
||||
bounds="[908,{modify_top}][988,{modify_top + 54}]">
|
||||
<node package="com.xunmeng.pinduoduo" text="修改"
|
||||
class="android.widget.TextView"
|
||||
bounds="[908,{modify_top}][988,{modify_top + 54}]"/>
|
||||
</node>
|
||||
</node>""")
|
||||
return f"""<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="返回"
|
||||
class="android.widget.TextView" bounds="[38,132][98,195]"/>
|
||||
</node>
|
||||
<node package="com.xunmeng.pinduoduo" text="收货地址"
|
||||
class="android.widget.TextView" bounds="[418,102][602,226]"/>
|
||||
<node package="com.xunmeng.pinduoduo"
|
||||
class="androidx.recyclerview.widget.RecyclerView"
|
||||
bounds="[0,226][1020,2140]">
|
||||
{''.join(cards)}
|
||||
</node>
|
||||
</node>
|
||||
<node package="com.android.systemui" content-desc="返回"
|
||||
class="android.widget.ImageView" clickable="true"
|
||||
bounds="[640,2140][802,2250]"/>
|
||||
</hierarchy>"""
|
||||
|
||||
|
||||
def address_edit_xml(address: str) -> str:
|
||||
return f"""<hierarchy>
|
||||
<node package="com.xunmeng.pinduoduo" bounds="[0,0][1080,2376]">
|
||||
@@ -377,6 +427,75 @@ class AddressFlowDevice(FakeDevice):
|
||||
return super().__call__(**selector)
|
||||
|
||||
|
||||
class MultipleAddressFlowDevice(AddressFlowDevice):
|
||||
"""模拟多地址面板,并记录是否点击默认卡片和 PDD 标题栏返回。"""
|
||||
|
||||
def __init__(self, default_indexes=(0,)) -> None:
|
||||
super().__init__()
|
||||
self.default_indexes = default_indexes
|
||||
self.address_modify_clicks = []
|
||||
self.address_back_clicks = []
|
||||
|
||||
def dump_hierarchy(self):
|
||||
if self.mode in {"address_panel", "address_saved"}:
|
||||
return multiple_address_panel_xml(
|
||||
self.address, default_indexes=self.default_indexes
|
||||
)
|
||||
return super().dump_hierarchy()
|
||||
|
||||
def click(self, x, y):
|
||||
if self.mode == "address_panel":
|
||||
self.clicks.append((x, y))
|
||||
self.address_modify_clicks.append((x, y))
|
||||
expected_y = 571 if self.default_indexes == (0,) else 1000
|
||||
if (x, y) == (948, expected_y):
|
||||
self.mode = "address_edit"
|
||||
return
|
||||
if self.mode == "address_saved":
|
||||
self.clicks.append((x, y))
|
||||
self.address_back_clicks.append((x, y))
|
||||
if x <= 240 and y <= 320:
|
||||
self.mode = "panel"
|
||||
return
|
||||
super().click(x, y)
|
||||
|
||||
|
||||
class AmbiguousDefaultAddressDevice(MultipleAddressFlowDevice):
|
||||
"""模拟默认地址卡片内部出现两个修改目标。"""
|
||||
|
||||
def dump_hierarchy(self):
|
||||
xml_data = super().dump_hierarchy()
|
||||
if self.mode != "address_panel":
|
||||
return xml_data
|
||||
root = ET.fromstring(xml_data)
|
||||
recycler = next(
|
||||
node
|
||||
for node in root.iter("node")
|
||||
if node.get("class")
|
||||
== "androidx.recyclerview.widget.RecyclerView"
|
||||
)
|
||||
default_card = list(recycler)[0]
|
||||
extra = ET.SubElement(
|
||||
default_card,
|
||||
"node",
|
||||
{
|
||||
"package": "com.xunmeng.pinduoduo",
|
||||
"clickable": "true",
|
||||
"bounds": "[800,544][880,598]",
|
||||
},
|
||||
)
|
||||
ET.SubElement(
|
||||
extra,
|
||||
"node",
|
||||
{
|
||||
"package": "com.xunmeng.pinduoduo",
|
||||
"text": "修改",
|
||||
"bounds": "[800,544][880,598]",
|
||||
},
|
||||
)
|
||||
return ET.tostring(root, encoding="unicode")
|
||||
|
||||
|
||||
class AddressSaveOverlayDevice(AddressFlowDevice):
|
||||
"""模拟保存后出现 ColorOS 密码本浮层。"""
|
||||
|
||||
@@ -730,6 +849,77 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
self.assertEqual(state.price_cent, 503)
|
||||
adapter.close()
|
||||
|
||||
def test_multiple_addresses_modify_only_default_card(self):
|
||||
device = MultipleAddressFlowDevice(default_indexes=(0,))
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
adapter.update_shipping_address("cg8")
|
||||
|
||||
self.assertEqual(device.address_modify_clicks, [(948, 571)])
|
||||
self.assertEqual(device.address_back_clicks, [(108, 164)])
|
||||
self.assertEqual(device.mode, "panel")
|
||||
adapter.close()
|
||||
|
||||
def test_default_address_can_be_second_card(self):
|
||||
device = MultipleAddressFlowDevice(default_indexes=(1,))
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
adapter.update_shipping_address("cg8")
|
||||
|
||||
self.assertEqual(device.address_modify_clicks, [(948, 1000)])
|
||||
self.assertEqual(device.address_back_clicks, [(108, 164)])
|
||||
self.assertEqual(device.mode, "panel")
|
||||
adapter.close()
|
||||
|
||||
def test_multiple_addresses_without_unique_default_stop_safely(self):
|
||||
for default_indexes in ((), (0, 1)):
|
||||
with self.subTest(default_indexes=default_indexes):
|
||||
device = MultipleAddressFlowDevice(
|
||||
default_indexes=default_indexes
|
||||
)
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
with self.assertRaises(PddPurchaseError) as raised:
|
||||
adapter.update_shipping_address("cg8")
|
||||
|
||||
self.assertEqual(
|
||||
raised.exception.code,
|
||||
"PURCHASE_ADDRESS_EDIT_AMBIGUOUS",
|
||||
)
|
||||
self.assertEqual(device.address_modify_clicks, [])
|
||||
self.assertEqual(device.address_back_clicks, [])
|
||||
adapter.close()
|
||||
|
||||
def test_default_address_with_multiple_modify_targets_stops_safely(self):
|
||||
device = AmbiguousDefaultAddressDevice()
|
||||
adapter = self._live_adapter(device, [])
|
||||
adapter.open_goods(GOODS_URL)
|
||||
adapter.select_options(
|
||||
{"color": "黑色", "size": "3XL【140-165斤】"}
|
||||
)
|
||||
|
||||
with self.assertRaises(PddPurchaseError) as raised:
|
||||
adapter.update_shipping_address("cg8")
|
||||
|
||||
self.assertEqual(
|
||||
raised.exception.code, "PURCHASE_ADDRESS_EDIT_AMBIGUOUS"
|
||||
)
|
||||
self.assertEqual(raised.exception.diagnostics["candidate_count"], 2)
|
||||
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, [])
|
||||
|
||||
Reference in New Issue
Block a user