feat(cross_end): add driver-to-settlement E2E test with SQL retry

- Add DriverFreightFlowPage (Android): 28-step flow covering accept/load/unload
- Add FreightAccountingPage (Web): accounting/audit/finance-payment/shipper-payment
- Add db_helper: update_risk_control_status via pymysql
- Fix ensure_logged_in: coordinate tap on 'mine' tab + login check
- Add test_driver_to_settlement.py: full cross-end E2E with SQL retry

Co-authored-by: xst <xst@ntocc.com>
This commit is contained in:
xst
2026-07-22 17:18:52 +08:00
parent 6f5668b7ec
commit f75a6f5ec9
6 changed files with 763 additions and 22 deletions
+70 -22
View File
@@ -54,11 +54,14 @@ def make_ensure_logged_in(
):
"""创建一个 ensure_logged_in 闭包。
策略:坐标点击底部"我的"tab(第4个图标)→ 检查"登录/注册"文本。
无法通过 resourceId 或 text 定位底部导航时用坐标点击兜底。
Args:
section_config: App 端配置
config: 全局配置
account_role: 默认账号角色名(如 "driver""shipper"
home_indicator: 首页元素的 accessibility_id
home_indicator: 未使用,保留兼容
"""
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
@@ -68,42 +71,87 @@ def make_ensure_logged_in(
skip_login = section_config.get("skip_login", True)
wait = WebDriverWait(driver, timeout=timeout_s)
try:
wait.until(
EC.visibility_of_element_located((AppiumBy.ACCESSIBILITY_ID, home_indicator))
)
return
except Exception:
pass
driver.implicitly_wait(3)
# 坐标点击底部"我的"tab4 tab 均分宽度,第4个中心 x≈0.875*w, y≈h-50
try:
login_input = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_phone_input")
if login_input.is_displayed():
w = driver.get_window_size()["width"]
h = driver.get_window_size()["height"]
driver.tap([(int(w * 0.875), h - 50)])
driver.implicitly_wait(1)
except Exception as e:
raise RuntimeError(f"无法点击底部导航栏: {e}")
# 判断登录态:检查"登录/注册"文本
login_check = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("登录/注册")')
try:
el = driver.find_element(*login_check)
if el.is_displayed():
if skip_login:
raise RuntimeError(
"APP 在登录页,未检测到登录!请在设备上手动完成一次登录(含验证码),"
"APP 登录!请在设备上手动完成一次登录(含验证码),"
"之后重新运行用例即可。\n如需自动化登录,请设置 skip_login: false。"
)
account = config["accounts"].get(account_role, {})
login_input.send_keys(account.get("phone", ""))
driver.find_element(
AppiumBy.ACCESSIBILITY_ID, "login_password_input"
).send_keys(account.get("password", ""))
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_submit_btn").click()
wait.until(
EC.visibility_of_element_located((AppiumBy.ACCESSIBILITY_ID, home_indicator))
)
_perform_ui_login(driver, config["accounts"].get(account_role, {}), wait)
return
except RuntimeError:
raise
except Exception:
pass # 没找到"登录/注册" → 已登录
# 回到首页
home_tab = (
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().resourceId("com.arpa.ynchenggangdriver:id/fixed_bottom_navigation_icon").instance(0)',
)
try:
wait.until(EC.visibility_of_element_located(home_tab))
driver.find_element(*home_tab).click()
except Exception:
pass
raise RuntimeError("无法确定 APP 的登录状态!请确保 APP 已启动且首页或登录页可见。")
return _ensure_logged_in
def _perform_ui_login(driver, account: dict, wait) -> None:
"""执行 UI 自动登录(skip_login: false 时使用)。"""
from appium.webdriver.common.appiumby import AppiumBy
phone = account.get("phone", "")
password = account.get("password", "")
# 点击登录入口
login_entry = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("登录/注册")')
wait.until(lambda d: d.find_element(*login_entry))
driver.find_element(*login_entry).click()
driver.implicitly_wait(1)
# 填写手机号
phone_input = (AppiumBy.ID, "com.arpa.ynchenggangdriver:id/ed_phone")
wait.until(lambda d: d.find_element(*phone_input))
driver.find_element(*phone_input).send_keys(phone)
# 填写密码
password_input = (AppiumBy.ID, "com.arpa.ynchenggangdriver:id/ed_pwd")
driver.find_element(*password_input).send_keys(password)
# 点击登录
login_btn = (AppiumBy.ID, "com.arpa.ynchenggangdriver:id/tv_login")
driver.find_element(*login_btn).click()
driver.implicitly_wait(2)
# 回到首页
home_tab = (
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().resourceId("com.arpa.ynchenggangdriver:id/fixed_bottom_navigation_icon").instance(0)',
)
try:
wait.until(lambda d: d.find_element(*home_tab))
driver.find_element(*home_tab).click()
except Exception:
pass
def save_failure_screenshot(driver, section_config, platform, request):
"""失败自动截图(各端 conftest teardown 中调用)。"""
if (