Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bec8c84321 | ||
|
|
7ea34e32c1 |
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "cn.ilapage.goauto.agent"
|
||||
minSdk = 23
|
||||
targetSdk = 34
|
||||
versionCode = 76
|
||||
versionName = "0.9.63"
|
||||
versionCode = 78
|
||||
versionName = "0.9.65"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
+22
-4
@@ -491,8 +491,11 @@ class PurchaseLiveAutomation(
|
||||
restoreFinalEvidenceInCurrentPanel(savedEvidence, expected, suffix)
|
||||
} else {
|
||||
if (!driver.backPurchase()) fail("PURCHASE_ADDRESS_UPDATE_FAILED", "地址保存后无法返回订单页面,未创建订单")
|
||||
waitFor("PURCHASE_ADDRESS_SAVE_TIMEOUT", "地址保存后无法返回订单页面,未创建订单") {
|
||||
hasFinalSavedAddressEvidence(it, expected, suffix)
|
||||
val returned = waitFor("PURCHASE_ADDRESS_SAVE_TIMEOUT", "地址保存后无法返回订单页面,未创建订单") {
|
||||
hasFinalSavedAddressEvidence(it, expected, suffix) || isPurchaseConfirmationPanel(it)
|
||||
}
|
||||
if (!hasFinalSavedAddressEvidence(returned, expected, suffix)) {
|
||||
restoreFinalEvidenceInCurrentPanel(returned, expected, suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,9 +524,10 @@ class PurchaseLiveAutomation(
|
||||
if (!isPurchaseConfirmationPanel(snapshot)) {
|
||||
fail("PURCHASE_ADDRESS_SAVE_TIMEOUT", "地址保存后采购面板发生变化,未创建订单")
|
||||
}
|
||||
val panels = purchasePanelScrollTargets(snapshot)
|
||||
val panels = savedAddressPanelScrollTargets(snapshot)
|
||||
if (panels.size != 1) {
|
||||
fail("PURCHASE_ADDRESS_ENTRY_AMBIGUOUS", "地址保存后没有找到唯一的规格面板滚动区域,未创建订单")
|
||||
val reason = if (panels.isEmpty()) "未找到可用的规格面板滚动区域" else "找到多个规格面板滚动区域"
|
||||
fail("PURCHASE_ADDRESS_ENTRY_AMBIGUOUS", "地址保存后${reason},未创建订单")
|
||||
}
|
||||
val panel = panels.single()
|
||||
val signature = viewportSignature(snapshot, panel)
|
||||
@@ -591,6 +595,20 @@ class PurchaseLiveAutomation(
|
||||
fail(code, message)
|
||||
}
|
||||
|
||||
private fun savedAddressPanelScrollTargets(snapshot: UiSnapshot): List<SnapshotNode> {
|
||||
val panel = PddScreenParser.parse(snapshot, PurchaseRehearsalExecutor.DEFAULT_COLLECTOR, "", null)
|
||||
.specPanelContainer ?: return purchasePanelScrollTargets(snapshot)
|
||||
val screenWidth = snapshot.nodes.maxOfOrNull { it.bounds.right }?.coerceAtLeast(1) ?: 1
|
||||
val screenHeight = snapshot.nodes.maxOfOrNull { it.bounds.bottom }?.coerceAtLeast(1) ?: 1
|
||||
return snapshot.nodes.filter { node ->
|
||||
node.visible && node.enabled && node.scrollable &&
|
||||
node.bounds.width * 100 >= screenWidth * 60 &&
|
||||
node.bounds.height * 100 >= screenHeight * 20 &&
|
||||
node.bounds.left >= panel.bounds.left && node.bounds.right <= panel.bounds.right &&
|
||||
node.bounds.top >= panel.bounds.top && node.bounds.bottom <= panel.bounds.bottom
|
||||
}.distinctBy { it.path }
|
||||
}
|
||||
|
||||
private fun purchasePanelScrollTargets(snapshot: UiSnapshot): List<SnapshotNode> {
|
||||
val screenWidth = snapshot.nodes.maxOfOrNull { it.bounds.right }?.coerceAtLeast(1) ?: 1
|
||||
val screenHeight = snapshot.nodes.maxOfOrNull { it.bounds.bottom }?.coerceAtLeast(1) ?: 1
|
||||
|
||||
@@ -141,6 +141,72 @@ class PurchaseLiveAutomationTest {
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saved address back into short spec panel restores without aspect ratio restriction`() {
|
||||
val driver = LiveDriver(savedTransitionWithoutLegacyContext = true, backReturnsToSpecPanel = true,
|
||||
savedPanelBounds = NodeBounds(0, 400, 1080, 1325))
|
||||
val automation = PurchaseLiveAutomation(driver, pause = {})
|
||||
val address = automation.updateShippingAddress("_cg81")
|
||||
|
||||
assertEquals("_cg81", automation.finalConfirmation(input().copy(addressSuffix = "_cg81"), address).addressSuffix)
|
||||
assertEquals(1, driver.backCount)
|
||||
assertEquals(1, driver.scopedSwipes)
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `short saved spec panel still stops when unchanged`() {
|
||||
val driver = LiveDriver(saveReturnsToSpecPanel = true, savedSpecPanelRecoveryStuck = true,
|
||||
savedPanelBounds = NodeBounds(0, 400, 1080, 1325))
|
||||
val error = runCatching { PurchaseLiveAutomation(driver, pause = {}).updateShippingAddress("_cg81") }
|
||||
.exceptionOrNull() as PurchaseLiveException
|
||||
assertEquals("PURCHASE_ADDRESS_SAVE_TIMEOUT", error.code)
|
||||
assertEquals(0, driver.backCount)
|
||||
assertTrue(driver.scopedSwipes in 1..5)
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `missing and duplicate saved panel scroll regions fail distinctly without gestures`() {
|
||||
for (count in listOf(0, 2)) {
|
||||
val driver = LiveDriver(saveReturnsToSpecPanel = true, savedPanelScrollCount = count)
|
||||
val error = runCatching { PurchaseLiveAutomation(driver, pause = {}).updateShippingAddress("_cg81") }
|
||||
.exceptionOrNull() as PurchaseLiveException
|
||||
assertEquals("PURCHASE_ADDRESS_ENTRY_AMBIGUOUS", error.code)
|
||||
assertTrue(error.message.orEmpty().contains(if (count == 0) "未找到可用" else "找到多个"))
|
||||
assertEquals(0, driver.scopedSwipes)
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saved address back into spec panel restores final evidence with one back`() {
|
||||
val driver = LiveDriver(savedTransitionWithoutLegacyContext = true, backReturnsToSpecPanel = true)
|
||||
val automation = PurchaseLiveAutomation(driver, pause = {})
|
||||
|
||||
val address = automation.updateShippingAddress("_cg81")
|
||||
val final = automation.finalConfirmation(input().copy(addressSuffix = "_cg81"), address)
|
||||
|
||||
assertEquals("_cg81", final.addressSuffix)
|
||||
assertEquals(1, driver.backCount)
|
||||
assertEquals(1, driver.scopedSwipes)
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saved address back into stuck spec panel fails without another back or submit`() {
|
||||
val driver = LiveDriver(savedTransitionWithoutLegacyContext = true, backReturnsToSpecPanel = true,
|
||||
savedSpecPanelRecoveryStuck = true)
|
||||
|
||||
val error = runCatching { PurchaseLiveAutomation(driver, pause = {}).updateShippingAddress("_cg81") }
|
||||
.exceptionOrNull() as PurchaseLiveException
|
||||
|
||||
assertEquals("PURCHASE_ADDRESS_SAVE_TIMEOUT", error.code)
|
||||
assertEquals(1, driver.backCount)
|
||||
assertTrue(driver.scopedSwipes in 1..5)
|
||||
assertEquals(0, driver.submitClicks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saved address returning to spec panel is recovered without pressing back`() {
|
||||
val driver = LiveDriver(saveReturnsToSpecPanel = true)
|
||||
@@ -645,6 +711,9 @@ class PurchaseLiveAutomationTest {
|
||||
private val savedTransitionWithoutLegacyContext: Boolean = false,
|
||||
private val savedTransitionHidesSuffix: Boolean = false,
|
||||
private val saveReturnsToSpecPanel: Boolean = false,
|
||||
private val backReturnsToSpecPanel: Boolean = false,
|
||||
private val savedPanelBounds: NodeBounds = NodeBounds(0, 400, 1080, 2100),
|
||||
private val savedPanelScrollCount: Int = 1,
|
||||
private val savedSpecPanelRecoveryStuck: Boolean = false,
|
||||
private val duplicatePhoneNodesSameCard: Boolean = false,
|
||||
private val duplicateSemanticAddressCards: Boolean = false,
|
||||
@@ -708,7 +777,7 @@ class PurchaseLiveAutomationTest {
|
||||
))
|
||||
"post-save-spec" -> snapshot(listOf(
|
||||
node("root", "", bounds = NodeBounds(0, 0, 1080, 2200)),
|
||||
node("panel", "", scrollable = true, bounds = NodeBounds(0, 400, 1080, 2100)),
|
||||
node("panel", "", scrollable = true, bounds = savedPanelBounds),
|
||||
node("panel-title", "确认款式", bounds = NodeBounds(20, 396, 300, 430)),
|
||||
node("panel/price", "¥20.00", parentPath = "panel", bounds = NodeBounds(20, 460, 300, 520)),
|
||||
node("panel/selected", "已选 黑色 XL", parentPath = "panel", bounds = NodeBounds(20, 540, 700, 600)),
|
||||
@@ -720,7 +789,8 @@ class PurchaseLiveAutomationTest {
|
||||
node("panel/confirm", "确定", clickable = true, parentPath = "panel", bounds = NodeBounds(20, 1200, 500, 1280)),
|
||||
node("submit-parent", "", clickable = true, bounds = NodeBounds(20, 1900, 1000, 2100)),
|
||||
node("submit", "提交订单", parentPath = "submit-parent", bounds = NodeBounds(520, 1940, 980, 2040)),
|
||||
))
|
||||
).map { if (it.path == "panel" && savedPanelScrollCount == 0) it.copy(enabled = false) else it } +
|
||||
if (savedPanelScrollCount > 1) listOf(node("panel/duplicate", "", scrollable = true, bounds = savedPanelBounds, parentPath = "panel")) else emptyList())
|
||||
"order" -> snapshot(listOf(node("status", "待付款"), node("order", "订单号:PDD-202608210001"), node("time", "下单时间:2026-08-21 10:30:00"), node("pay", "立即支付", clickable = true)))
|
||||
"order-folded" -> snapshot(listOf(node("status", "待付款"), node("pay", "立即支付", clickable = true)))
|
||||
"order-folded-payment-activity" -> UiSnapshot(PDD, "com.xunmeng.pinduoduo.app_pay.core.PayActivity", listOf(
|
||||
@@ -863,6 +933,7 @@ class PurchaseLiveAutomationTest {
|
||||
page = when (page) {
|
||||
"chooser" -> "payment"
|
||||
"payment" -> if (orderEvidenceBelowFold) "order-folded" else "order"
|
||||
"saved-transition" -> if (backReturnsToSpecPanel) "post-save-spec" else "confirmation"
|
||||
else -> "confirmation"
|
||||
}
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user