fix: 兼容非滚动规格确认面板 (#275)
This commit is contained in:
@@ -512,6 +512,9 @@ def _find_non_scrollable_spec_panel(
|
|||||||
node.get("package") == PDD_PACKAGE_NAME
|
node.get("package") == PDD_PACKAGE_NAME
|
||||||
for node in root.iter("node")
|
for node in root.iter("node")
|
||||||
)
|
)
|
||||||
|
is_order_confirmation = (
|
||||||
|
classify_pdd_page(root, "").kind == PAGE_ORDER_CONFIRMATION
|
||||||
|
)
|
||||||
|
|
||||||
headings: list[ET.Element] = []
|
headings: list[ET.Element] = []
|
||||||
summaries: list[ET.Element] = []
|
summaries: list[ET.Element] = []
|
||||||
@@ -546,10 +549,13 @@ def _find_non_scrollable_spec_panel(
|
|||||||
and screen_bottom
|
and screen_bottom
|
||||||
and (bounds[1] + bounds[3]) // 2 >= screen_bottom * 0.6
|
and (bounds[1] + bounds[3]) // 2 >= screen_bottom * 0.6
|
||||||
and "提交订单" in descendant_label
|
and "提交订单" in descendant_label
|
||||||
and any(
|
and (
|
||||||
|
is_order_confirmation
|
||||||
|
or any(
|
||||||
word in descendant_label
|
word in descendant_label
|
||||||
for word in ("选择", "颜色", "尺码", "规格")
|
for word in ("选择", "颜色", "尺码", "规格")
|
||||||
)
|
)
|
||||||
|
)
|
||||||
):
|
):
|
||||||
submit_hints.append(node)
|
submit_hints.append(node)
|
||||||
if (
|
if (
|
||||||
@@ -563,17 +569,23 @@ def _find_non_scrollable_spec_panel(
|
|||||||
if compact == "增加数量" and node.get("clickable") == "true":
|
if compact == "增加数量" and node.get("clickable") == "true":
|
||||||
increases.append(node)
|
increases.append(node)
|
||||||
|
|
||||||
if not headings or not summaries or not panel_cues:
|
strong_confirmation_evidence = (
|
||||||
return None
|
is_order_confirmation
|
||||||
if confirms:
|
and pdd_node_count >= 3
|
||||||
action_nodes = [confirms[0]]
|
|
||||||
elif (
|
|
||||||
pdd_node_count >= 3
|
|
||||||
and len(submit_hints) == 1
|
and len(submit_hints) == 1
|
||||||
and len(quantity_editors) == 1
|
and len(quantity_editors) == 1
|
||||||
and len(decreases) == 1
|
and len(decreases) == 1
|
||||||
and len(increases) == 1
|
and len(increases) == 1
|
||||||
):
|
)
|
||||||
|
if not headings or not summaries:
|
||||||
|
return None
|
||||||
|
# 部分新版确认页会把“确认款式/关闭”滚出当前视口。只有页面分类和
|
||||||
|
# 下面的数量、提交区域证据同时成立时,才允许缺少顶部提示。
|
||||||
|
if not panel_cues and not strong_confirmation_evidence:
|
||||||
|
return None
|
||||||
|
if confirms:
|
||||||
|
action_nodes = [confirms[0]]
|
||||||
|
elif strong_confirmation_evidence:
|
||||||
action_nodes = [
|
action_nodes = [
|
||||||
submit_hints[0],
|
submit_hints[0],
|
||||||
quantity_editors[0],
|
quantity_editors[0],
|
||||||
@@ -583,7 +595,9 @@ def _find_non_scrollable_spec_panel(
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
required = [*headings, summaries[0], panel_cues[0], *action_nodes]
|
required = [*headings, summaries[0], *action_nodes]
|
||||||
|
if panel_cues:
|
||||||
|
required.append(panel_cues[0])
|
||||||
common = set([required[0], *_ancestors(required[0], parents)])
|
common = set([required[0], *_ancestors(required[0], parents)])
|
||||||
for node in required[1:]:
|
for node in required[1:]:
|
||||||
common.intersection_update([node, *_ancestors(node, parents)])
|
common.intersection_update([node, *_ancestors(node, parents)])
|
||||||
@@ -595,17 +609,22 @@ def _find_non_scrollable_spec_panel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
candidates: list[tuple[int, ET.Element]] = []
|
candidates: list[tuple[int, ET.Element]] = []
|
||||||
|
full_screen_candidates: list[tuple[int, ET.Element]] = []
|
||||||
for node in common:
|
for node in common:
|
||||||
bounds = _parse_bounds(node.get("bounds", ""))
|
bounds = _parse_bounds(node.get("bounds", ""))
|
||||||
if bounds is None or node.get("visible-to-user", "true") != "true":
|
if bounds is None or node.get("visible-to-user", "true") != "true":
|
||||||
continue
|
continue
|
||||||
area = (bounds[2] - bounds[0]) * (bounds[3] - bounds[1])
|
area = (bounds[2] - bounds[0]) * (bounds[3] - bounds[1])
|
||||||
if screen_area and area >= screen_area * 0.95:
|
if screen_area and area >= screen_area * 0.95:
|
||||||
|
if strong_confirmation_evidence:
|
||||||
|
full_screen_candidates.append((area, node))
|
||||||
continue
|
continue
|
||||||
candidates.append((area, node))
|
candidates.append((area, node))
|
||||||
if not candidates:
|
if candidates:
|
||||||
return None
|
|
||||||
return min(candidates, key=lambda item: item[0])[1]
|
return min(candidates, key=lambda item: item[0])[1]
|
||||||
|
if full_screen_candidates:
|
||||||
|
return min(full_screen_candidates, key=lambda item: item[0])[1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _is_spec_panel_open(xml_data: str | bytes) -> bool:
|
def _is_spec_panel_open(xml_data: str | bytes) -> bool:
|
||||||
|
|||||||
@@ -46,6 +46,42 @@ def style_package_spec_xml() -> str:
|
|||||||
</hierarchy>"""
|
</hierarchy>"""
|
||||||
|
|
||||||
|
|
||||||
|
def root_level_non_scrollable_confirmation_xml() -> str:
|
||||||
|
"""模拟顶部提示不可见、证据节点都挂在全屏根容器的确认页。"""
|
||||||
|
|
||||||
|
return """<hierarchy>
|
||||||
|
<node package="com.xunmeng.pinduoduo" visible-to-user="true"
|
||||||
|
bounds="[0,0][1080,2376]">
|
||||||
|
<node package="com.xunmeng.pinduoduo"
|
||||||
|
text="已选:女小码 测试白色" bounds="[396,708][1053,822]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo"
|
||||||
|
class="android.widget.EditText" text="1"
|
||||||
|
bounds="[462,876][540,954]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" content-desc="减少数量"
|
||||||
|
clickable="true" bounds="[396,876][462,954]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" content-desc="增加数量"
|
||||||
|
clickable="true" bounds="[540,876][606,954]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" text="尺码"
|
||||||
|
bounds="[36,1153][126,1206]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo"
|
||||||
|
text="女小码【建议-体重75-100斤】" clickable="true"
|
||||||
|
selected="true" bounds="[36,1232][649,1317]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo"
|
||||||
|
text="女大码【建议-体重101-120斤】" clickable="true"
|
||||||
|
bounds="[36,1347][695,1432]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" text="颜色"
|
||||||
|
bounds="[36,1482][126,1535]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" text="测试白色"
|
||||||
|
clickable="true" selected="true" bounds="[36,1561][730,1646]"/>
|
||||||
|
<node package="com.xunmeng.pinduoduo" clickable="true"
|
||||||
|
bounds="[0,2181][1080,2328]">
|
||||||
|
<node package="com.xunmeng.pinduoduo" text="提交订单 ¥28.10"
|
||||||
|
bounds="[375,2225][885,2284]"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</hierarchy>"""
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FakeTask:
|
class FakeTask:
|
||||||
goods_url: str
|
goods_url: str
|
||||||
@@ -863,6 +899,24 @@ class PddCollectParserTest(unittest.TestCase):
|
|||||||
[item.name for item in result.dimensions],
|
[item.name for item in result.dimensions],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_parse_root_level_confirmation_with_size_before_color(self):
|
||||||
|
xml_data = root_level_non_scrollable_confirmation_xml()
|
||||||
|
|
||||||
|
result = parse_spec_panel(xml_data)
|
||||||
|
|
||||||
|
self.assertTrue(_is_spec_panel_open(xml_data))
|
||||||
|
self.assertEqual(
|
||||||
|
[(item.key, item.name) for item in result.dimensions],
|
||||||
|
[("size", "尺码"), ("color", "颜色")],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[value.text for value in result.dimensions[0].values],
|
||||||
|
[
|
||||||
|
"女小码【建议-体重75-100斤】",
|
||||||
|
"女大码【建议-体重101-120斤】",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_collects_static_sizes_from_non_scrollable_submit_hint_panel(self):
|
def test_collects_static_sizes_from_non_scrollable_submit_hint_panel(self):
|
||||||
device = FakeCollectDevice(self.home_xml, self.submit_hint_spec_xml)
|
device = FakeCollectDevice(self.home_xml, self.submit_hint_spec_xml)
|
||||||
device.opened_url = (
|
device.opened_url = (
|
||||||
|
|||||||
Reference in New Issue
Block a user