fix(android): recognize single-dimension panels only in collection #256
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "cn.ilapage.goauto.agent"
|
||||
minSdk = 23
|
||||
targetSdk = 34
|
||||
versionCode = 85
|
||||
versionName = "0.9.72"
|
||||
versionCode = 86
|
||||
versionName = "0.9.73"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
+13
-2
@@ -186,7 +186,7 @@ object PddScreenParser {
|
||||
// purchase/order/payment controls must never become collection click targets.
|
||||
private val nonConfigurableClickDenylist = listOf("提交订单", "确认订单", "支付", "付款")
|
||||
|
||||
fun parse(snapshot: UiSnapshot, config: PddCollectorConfig, goodsId: String, evidence: PageEvidence?, purchaseContext: PurchasePanelContext? = null): ParsedPddScreen {
|
||||
fun parse(snapshot: UiSnapshot, config: PddCollectorConfig, goodsId: String, evidence: PageEvidence?, purchaseContext: PurchasePanelContext? = null, collectionContext: Boolean = false): ParsedPddScreen {
|
||||
val visibleNodes = snapshot.nodes.filter { it.visible }
|
||||
val visible = visibleNodes.mapNotNull { node ->
|
||||
val descendants = descendants(node, visibleNodes)
|
||||
@@ -323,12 +323,23 @@ object PddScreenParser {
|
||||
(headings.size >= 2 || (continuedPurchasePanel && headings.isNotEmpty())) &&
|
||||
dimensions.any { it.values.isNotEmpty() } && hasClose &&
|
||||
hasQuantityControls && hasPaymentArea && hasOrderSubmitAction
|
||||
// Collection can start before any selection summary exists and with only
|
||||
// one dimension visible. Keep this exception out of purchase parsing.
|
||||
val singleDimensionCollectionPanel = collectionContext && purchaseContext == null &&
|
||||
snapshot.packageName == PDD_PACKAGE && problem == null && !hasSelectionSummary &&
|
||||
evidence != null && snapshot.packageName == evidence.packageName &&
|
||||
snapshot.activityName == evidence.activityName &&
|
||||
snapshot.nodes.any { it.visible && it.matches(evidence.selector) } &&
|
||||
boundedScrollables.size == 1 && headedPanelScrollable != null && headings.size == 1 &&
|
||||
dimensions.size == 1 && dimensions.single().values.isNotEmpty() &&
|
||||
hasClose && hasQuantityControls && hasPaymentArea && hasOrderSubmitAction
|
||||
// Some selected-spec panels omit both the "已选" prefix and a confirm
|
||||
// button. Keep the same structural evidence required for checkout.
|
||||
val specPanelType = when {
|
||||
quickConfirmationEvidence -> SpecPanelType.QUICK_CONFIRMATION
|
||||
orderConfirmationEvidence -> SpecPanelType.ORDER_CONFIRMATION
|
||||
structuredSelectionPanel -> SpecPanelType.NORMAL_SCROLLABLE
|
||||
singleDimensionCollectionPanel -> SpecPanelType.NORMAL_SCROLLABLE
|
||||
panelScrollable != null && (hasSelectionSummary || hasSubmitHint || (hasPanelTitle && hasPanelAction)) -> SpecPanelType.NORMAL_SCROLLABLE
|
||||
hasSelectionSummary && hasPanelTitle && hasPanelAction -> SpecPanelType.NON_SCROLLABLE_CONFIRMATION
|
||||
// Some PDD builds expose the complete selector as non-scrollable
|
||||
@@ -1765,7 +1776,7 @@ class PddProductDetailCollector(
|
||||
}
|
||||
|
||||
private fun parse(goodsId: String, config: PddCollectorConfig, evidence: PageEvidence) =
|
||||
PddScreenParser.parse(driver.capture(), config, goodsId, evidence)
|
||||
PddScreenParser.parse(driver.capture(), config, goodsId, evidence, collectionContext = true)
|
||||
|
||||
private fun screenSignature(screen: ParsedPddScreen): List<String> = screen.sourceNodes.asSequence()
|
||||
.filter(SnapshotNode::visible)
|
||||
|
||||
@@ -27,6 +27,52 @@ import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class PddProductDetailCollectorTest {
|
||||
private fun singleDimensionPanel(): UiSnapshot {
|
||||
val snapshot = prefixlessPanel()
|
||||
return snapshot.copy(nodes = snapshot.nodes.filterNot {
|
||||
it.path.startsWith("scroll/size") || it.path == "info/summary"
|
||||
}.map {
|
||||
if (it.path == "root") it.copy(resourceId = "android:id/content", className = "android.widget.FrameLayout") else it
|
||||
})
|
||||
}
|
||||
|
||||
@Test fun `single dimension without summary is recognized only during collection`() {
|
||||
for (heading in listOf("颜色分类", "尺码")) {
|
||||
val snapshot = singleDimensionPanel().let { original ->
|
||||
original.copy(nodes = original.nodes.map {
|
||||
if (it.path == "scroll/color-title") it.copy(text = heading) else it
|
||||
})
|
||||
}
|
||||
assertFalse(PddScreenParser.parse(snapshot, config(), GOODS_ID, evidence()).specPanelOpen)
|
||||
val parsed = PddScreenParser.parse(snapshot, config(), GOODS_ID, evidence(), collectionContext = true)
|
||||
assertEquals(SpecPanelType.NORMAL_SCROLLABLE, parsed.specPanelType)
|
||||
assertEquals("scroll", parsed.specPanelContainer?.path)
|
||||
assertEquals(1, parsed.dimensions.size)
|
||||
assertEquals(null, parsed.selectedSummary)
|
||||
assertFalse(parsed.hasSelectionSummary)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun `single dimension collection requires all structural and page evidence`() {
|
||||
val snapshot = singleDimensionPanel()
|
||||
for (missing in listOf("close", "plus", "minus", "info/quantity", "payment", "submit", "scroll/color-title", "scroll/color", "root")) {
|
||||
val changed = snapshot.copy(nodes = snapshot.nodes.filterNot { it.path == missing })
|
||||
assertFalse(missing, PddScreenParser.parse(changed, config(), GOODS_ID, evidence(), collectionContext = true).specPanelOpen)
|
||||
}
|
||||
val secondScroll = node("other-scroll", "", 0, 500, 1080, 700, scrollable = true)
|
||||
val secondSubmit = node("other-submit", "提交订单", 10, 2200, 300, 2300, clickable = true)
|
||||
for (changed in listOf(
|
||||
snapshot.copy(nodes = snapshot.nodes + secondScroll),
|
||||
snapshot.copy(nodes = snapshot.nodes + secondSubmit),
|
||||
snapshot.copy(packageName = "example.other"),
|
||||
snapshot.copy(activityName = "example.OtherActivity"),
|
||||
snapshot.copy(nodes = snapshot.nodes + node("captcha", "请完成安全验证", 0, 0, 600, 100)),
|
||||
)) {
|
||||
assertFalse(PddScreenParser.parse(changed, config(), GOODS_ID, evidence(), collectionContext = true).specPanelOpen)
|
||||
}
|
||||
assertFalse(PddScreenParser.parse(snapshot, config(), GOODS_ID, null, collectionContext = true).specPanelOpen)
|
||||
}
|
||||
|
||||
private fun prefixlessPanel(): UiSnapshot = UiSnapshot(PDD_PACKAGE, ACTIVITY, listOf(
|
||||
node("root", "", 0, 0, 1080, 2376),
|
||||
node("close", "关闭", 970, 270, 1050, 350, clickable = true),
|
||||
|
||||
Reference in New Issue
Block a user