fix: 安全采集图片颜色并取消默认尺码 (#160)
This commit is contained in:
@@ -300,6 +300,95 @@ class DelayedHorizontalSwipeDevice(SnakeColorDevice):
|
||||
self.sizes_visible = True
|
||||
|
||||
|
||||
class ImageColorDevice(SnakeColorDevice):
|
||||
"""图片型颜色卡片:点图片会进入大图,点底部文字才选中颜色。"""
|
||||
|
||||
def __init__(self, home_xml):
|
||||
super().__init__(home_xml)
|
||||
self.big_image_open = False
|
||||
|
||||
def dump_hierarchy(self):
|
||||
if self.big_image_open:
|
||||
return """<hierarchy>
|
||||
<node class="android.support.v4.view.ViewPager"
|
||||
scrollable="true" bounds="[0,0][1080,2000]">
|
||||
<node class="android.widget.ImageView" content-desc="A色" />
|
||||
</node>
|
||||
<node class="android.widget.TextView" text="1/31"
|
||||
bounds="[500,1850][580,1900]" />
|
||||
</hierarchy>"""
|
||||
return super().dump_hierarchy()
|
||||
|
||||
def click(self, x, y):
|
||||
if self.panel_open and 740 <= y < 820:
|
||||
self.clicks.append((x, y))
|
||||
self.big_image_open = True
|
||||
return
|
||||
super().click(x, y)
|
||||
|
||||
def press(self, key):
|
||||
if key == "back":
|
||||
self.big_image_open = False
|
||||
|
||||
def _spec_xml(self):
|
||||
xml_data = super()._spec_xml()
|
||||
old = (
|
||||
'<node class="android.view.ViewGroup" content-desc="A色" '
|
||||
f'clickable="true" selected="{str(self.selected_color == "A色").lower()}" '
|
||||
'bounds="[36,740][340,850]" visible-to-user="true" enabled="true" />'
|
||||
)
|
||||
new = (
|
||||
'<node class="android.view.ViewGroup" content-desc="A色" '
|
||||
f'clickable="true" selected="{str(self.selected_color == "A色").lower()}" '
|
||||
'bounds="[36,740][340,850]" visible-to-user="true" enabled="true">'
|
||||
'<node class="android.widget.ImageView" content-desc="A色" '
|
||||
'clickable="true" bounds="[36,740][340,820]" />'
|
||||
'<node class="android.widget.ImageView" content-desc="打开大图" '
|
||||
'clickable="true" bounds="[280,740][340,800]" />'
|
||||
'<node class="android.widget.TextView" text="A色" clickable="true" '
|
||||
'bounds="[36,820][340,850]" visible-to-user="true" />'
|
||||
'</node>'
|
||||
)
|
||||
return xml_data.replace(old, new)
|
||||
|
||||
|
||||
class DefaultSizeDevice(SnakeColorDevice):
|
||||
"""尺码在下方且默认选中,取消后才能完整遍历颜色。"""
|
||||
|
||||
def __init__(self, home_xml, *, can_clear=True):
|
||||
super().__init__(home_xml)
|
||||
self.size_selected = True
|
||||
self.can_clear = can_clear
|
||||
self.size_clicks = 0
|
||||
|
||||
def click(self, x, y):
|
||||
if self.panel_open and self.sizes_visible and 1210 <= y <= 1300:
|
||||
self.clicks.append((x, y))
|
||||
self.size_clicks += 1
|
||||
if self.can_clear:
|
||||
self.size_selected = False
|
||||
return
|
||||
super().click(x, y)
|
||||
|
||||
def swipe(self, x1, y1, x2, y2, duration=0.35):
|
||||
self.swipes.append(((x1, y1, x2, y2), {"duration": duration}))
|
||||
self.swipe_panel_states.append(self.panel_open)
|
||||
if abs(x2 - x1) > abs(y2 - y1):
|
||||
self.page = 1 if x1 > x2 else 0
|
||||
else:
|
||||
self.sizes_visible = y1 > y2
|
||||
|
||||
def _spec_xml(self):
|
||||
xml_data = super()._spec_xml()
|
||||
if self.sizes_visible:
|
||||
selected = str(self.size_selected).lower()
|
||||
xml_data = xml_data.replace(
|
||||
'content-desc="M"\n clickable="true"',
|
||||
f'content-desc="M"\n clickable="true" selected="{selected}"',
|
||||
)
|
||||
return xml_data
|
||||
|
||||
|
||||
class FakeClock:
|
||||
"""测试用时钟:sleep 只推进虚拟时间,不真的等待。"""
|
||||
|
||||
@@ -822,6 +911,86 @@ class PddCollectParserTest(unittest.TestCase):
|
||||
for item in data["skus"]
|
||||
))
|
||||
|
||||
def test_image_color_card_clicks_caption_instead_of_opening_big_image(self):
|
||||
device = ImageColorDevice(self.home_xml)
|
||||
device.panel_open = True
|
||||
device.page = 0
|
||||
service = PddCollectService(
|
||||
PddDeviceService(lambda _serial: device),
|
||||
"USB-001",
|
||||
"client-001",
|
||||
sleeper=lambda _seconds: None,
|
||||
)
|
||||
|
||||
sample = service._click_and_sample_color(device, "A色")
|
||||
|
||||
self.assertEqual(1000, sample.price_cent)
|
||||
self.assertFalse(device.big_image_open)
|
||||
self.assertGreaterEqual(device.clicks[0][1], 820)
|
||||
|
||||
def test_big_image_recovery_presses_back_only_once(self):
|
||||
device = ImageColorDevice(self.home_xml)
|
||||
device.panel_open = True
|
||||
device.big_image_open = True
|
||||
press_calls = []
|
||||
original_press = device.press
|
||||
|
||||
def record_press(key):
|
||||
press_calls.append(key)
|
||||
original_press(key)
|
||||
|
||||
device.press = record_press
|
||||
service = PddCollectService(
|
||||
PddDeviceService(lambda _serial: device),
|
||||
"USB-001",
|
||||
"client-001",
|
||||
sleeper=lambda _seconds: None,
|
||||
)
|
||||
|
||||
service._recover_spec_panel_from_big_image(device)
|
||||
|
||||
self.assertEqual(["back"], press_calls)
|
||||
self.assertFalse(device.big_image_open)
|
||||
|
||||
def test_default_size_is_cleared_once_before_colors_and_sizes_are_collected(self):
|
||||
device = DefaultSizeDevice(self.home_xml)
|
||||
service = PddCollectService(
|
||||
PddDeviceService(lambda _serial: device),
|
||||
"USB-001",
|
||||
"client-001",
|
||||
sleeper=lambda _seconds: None,
|
||||
)
|
||||
|
||||
data = service.collect(
|
||||
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
|
||||
).to_pdd_data()
|
||||
|
||||
self.assertEqual(1, device.size_clicks)
|
||||
self.assertFalse(device.size_selected)
|
||||
self.assertEqual(
|
||||
["A色", "B色", "C色", "F色", "E色", "D色"],
|
||||
device.clicked_colors,
|
||||
)
|
||||
self.assertEqual(
|
||||
["M", "L"],
|
||||
[item["text"] for item in data["dimensions"][1]["values"]],
|
||||
)
|
||||
|
||||
def test_size_that_cannot_be_cleared_is_not_clicked_repeatedly(self):
|
||||
device = DefaultSizeDevice(self.home_xml, can_clear=False)
|
||||
device.panel_open = True
|
||||
service = PddCollectService(
|
||||
PddDeviceService(lambda _serial: device),
|
||||
"USB-001",
|
||||
"client-001",
|
||||
sleeper=lambda _seconds: None,
|
||||
)
|
||||
|
||||
service._clear_default_size_selection(device)
|
||||
|
||||
self.assertEqual(1, device.size_clicks)
|
||||
self.assertTrue(device.size_selected)
|
||||
|
||||
def test_visible_click_is_fallback_when_page_exposes_no_selection_state(self):
|
||||
xml_data = keep_only_one_sku(self.spec_xml)
|
||||
root = ET.fromstring(xml_data)
|
||||
|
||||
Reference in New Issue
Block a user