fix: 采购选色前归位规格面板 (#230)
This commit is contained in:
@@ -98,6 +98,53 @@ def contextual_confirm_panel_xml(quantity: int = 1) -> str:
|
||||
</hierarchy>"""
|
||||
|
||||
|
||||
def vertically_scrolled_purchase_panel_xml(*, at_color_top: bool) -> str:
|
||||
"""构造规格面板位于颜色顶部或停在中部的脱敏控件树。"""
|
||||
|
||||
if at_color_top:
|
||||
scroll_content = """
|
||||
<node text="颜色分类" bounds="[32,1120][190,1170]"/>
|
||||
<node text="黑色" clickable="true" enabled="true"
|
||||
visible-to-user="true" bounds="[32,1190][332,1320]"/>
|
||||
<node text="白色" clickable="true" enabled="true"
|
||||
visible-to-user="true" bounds="[359,1190][659,1320]"/>
|
||||
<node text="尺码" bounds="[32,1500][114,1550]"/>
|
||||
<node text="均码" clickable="true" enabled="true"
|
||||
visible-to-user="true" bounds="[32,1580][391,1660]"/>
|
||||
"""
|
||||
else:
|
||||
scroll_content = """
|
||||
<node text="黑色 ¥6.93" clickable="true" enabled="true"
|
||||
visible-to-user="true" bounds="[32,1095][332,1460]"/>
|
||||
<node text="白色 ¥6.93" clickable="true" enabled="true"
|
||||
visible-to-user="true" bounds="[359,1095][659,1460]"/>
|
||||
<node text="尺码" bounds="[32,1605][114,1653]"/>
|
||||
<node text="均码" clickable="true" selected="true"
|
||||
enabled="true" visible-to-user="true"
|
||||
bounds="[32,1677][391,1753]"/>
|
||||
"""
|
||||
return f"""<hierarchy>
|
||||
<node package="com.xunmeng.pinduoduo" bounds="[0,0][1080,2376]">
|
||||
<node text="确认款式" bounds="[430,650][650,710]"/>
|
||||
<node text="请选择: 颜色分类" bounds="[360,770][990,830]"/>
|
||||
<node class="android.widget.EditText" text="1"
|
||||
bounds="[440,870][510,940]"/>
|
||||
<node content-desc="减少数量" clickable="true"
|
||||
bounds="[360,870][430,940]"/>
|
||||
<node content-desc="增加数量" clickable="true"
|
||||
bounds="[515,870][585,940]"/>
|
||||
<node package="com.xunmeng.pinduoduo"
|
||||
class="androidx.recyclerview.widget.RecyclerView"
|
||||
scrollable="true" enabled="true" visible-to-user="true"
|
||||
bounds="[0,1095][1020,1918]">
|
||||
{scroll_content}
|
||||
</node>
|
||||
<node text="选择颜色分类后,提交订单"
|
||||
bounds="[0,2181][1080,2328]"/>
|
||||
</node>
|
||||
</hierarchy>"""
|
||||
|
||||
|
||||
class FakeEditor:
|
||||
def __init__(self, device) -> None:
|
||||
self.device = device
|
||||
@@ -180,6 +227,32 @@ class FakeDevice:
|
||||
raise AssertionError(f"未预期的 selector: {selector}")
|
||||
|
||||
|
||||
class VerticallyScrolledColorPanelDevice(FakeDevice):
|
||||
"""模拟 PDD 记住规格面板纵向位置。"""
|
||||
|
||||
def __init__(self, *, starts_at_top: bool, restores_on_swipe: bool = True):
|
||||
super().__init__()
|
||||
self.at_color_top = starts_at_top
|
||||
self.restores_on_swipe = restores_on_swipe
|
||||
self.swipes = []
|
||||
|
||||
def dump_hierarchy(self):
|
||||
if not self.has_opened:
|
||||
return super().dump_hierarchy()
|
||||
if self.mode == "home":
|
||||
return home_xml()
|
||||
if self.mode == "panel":
|
||||
return vertically_scrolled_purchase_panel_xml(
|
||||
at_color_top=self.at_color_top
|
||||
)
|
||||
return super().dump_hierarchy()
|
||||
|
||||
def swipe(self, x1, y1, x2, y2, duration=0.0):
|
||||
self.swipes.append((x1, y1, x2, y2, duration))
|
||||
if self.restores_on_swipe:
|
||||
self.at_color_top = True
|
||||
|
||||
|
||||
class ColdStartDevice(FakeDevice):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
@@ -927,6 +1000,74 @@ class U2PddPurchaseAdapterTest(unittest.TestCase):
|
||||
self.assertEqual(device.clicks[-1], (540, 2140))
|
||||
adapter.close()
|
||||
|
||||
def test_purchase_restores_color_region_before_selecting_color(self):
|
||||
clock = FakeClock()
|
||||
device = VerticallyScrolledColorPanelDevice(starts_at_top=False)
|
||||
selected_xml = []
|
||||
|
||||
def select_color_fn(_device, xml_data, _target, **_kwargs):
|
||||
selected_xml.append(xml_data)
|
||||
return True
|
||||
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
select_color_fn=select_color_fn,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
|
||||
adapter.select_options({"color": "黑色"})
|
||||
|
||||
self.assertEqual(len(device.swipes), 1)
|
||||
self.assertLess(device.swipes[0][1], device.swipes[0][3])
|
||||
self.assertEqual(len(selected_xml), 1)
|
||||
self.assertIn('text="颜色分类"', selected_xml[0])
|
||||
adapter.close()
|
||||
|
||||
def test_purchase_does_not_scroll_when_color_region_is_already_visible(self):
|
||||
device = VerticallyScrolledColorPanelDevice(starts_at_top=True)
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
select_color_fn=lambda *_args, **_kwargs: True,
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
|
||||
adapter.select_options({"color": "黑色"})
|
||||
|
||||
self.assertEqual(device.swipes, [])
|
||||
adapter.close()
|
||||
|
||||
def test_purchase_stops_when_color_region_cannot_be_restored(self):
|
||||
clock = FakeClock()
|
||||
device = VerticallyScrolledColorPanelDevice(
|
||||
starts_at_top=False,
|
||||
restores_on_swipe=False,
|
||||
)
|
||||
select_calls = []
|
||||
adapter = self._live_adapter(
|
||||
device,
|
||||
[],
|
||||
sleeper=clock.sleep,
|
||||
monotonic=clock.monotonic,
|
||||
select_color_fn=lambda *_args, **_kwargs: select_calls.append(True),
|
||||
)
|
||||
adapter.open_goods(GOODS_URL)
|
||||
|
||||
with self.assertRaises(PddPurchaseError) as raised:
|
||||
adapter.select_options({"color": "黑色"})
|
||||
|
||||
self.assertEqual(
|
||||
raised.exception.code,
|
||||
"PURCHASE_PANEL_COLOR_REGION_NOT_FOUND",
|
||||
)
|
||||
self.assertEqual(len(device.swipes), 2)
|
||||
self.assertEqual(select_calls, [])
|
||||
self.assertEqual(len(device.clicks), 1)
|
||||
adapter.close()
|
||||
|
||||
def test_address_is_split_at_first_separator_before_tagging(self):
|
||||
self.assertEqual(
|
||||
_tagged_shipping_address(
|
||||
|
||||
Reference in New Issue
Block a user