190 lines
12 KiB
Bash
190 lines
12 KiB
Bash
#!/bin/bash
|
|
# iOS 控制用例批量:每个用例前用 WDA terminate/launch 复位到首页,跑完记录结果。失败不阻塞。
|
|
# 对齐 Android run-p0-all 的 CONTROL,iOS 适配:① 复位走 WDA(无 adb)② 不做 BLE/WiFi 切换双跑(iOS 无 adb svc,
|
|
# 控制走当前连接即可)③ plug 在 iOS 改名为 "Plug JP",PLUG_CTRL_DEVICE 用子串 "Plug"。
|
|
# 设备依赖:控制类用例依赖添加阶段(run-ios-adds.sh)已加的设备 + 账号保留的 摄像头/门铃。
|
|
# 注:本 iOS 账号当前无 Lock/Blind Tilt 实体 → lock_card/blind_tilt 多半无设备(失败隔离,不影响其它)。
|
|
# WDA 须已在 localhost:8100。
|
|
set -u
|
|
cd "$(dirname "$0")/.."
|
|
export PLATFORM=ios SOAK_MODE=1 SKIP_PROTO_NET=1 VITEST_RETRY=1 # 控制阶段:单个 it 失败自动重跑一次(对齐 Android)
|
|
export LOCK_DEVICE="Lock 6D" LOCK_PRO_DEVICE="Lock Pro DE" BT_DEVICE="Blind Tilt 42"
|
|
# PLUG_CTRL_DEVICE 不导出:plug 控制走 getDeviceName('plug') → 注册表实际名(iOS 当前 "Plug EU"),不写死
|
|
BUNDLE=com.wohand.wohand
|
|
LOG=reports/ios-controls.log
|
|
: > "$LOG"
|
|
|
|
# WDA 健康检查 + 恢复:/status 不通则重启 iproxy 端口转发(覆盖过夜端口转发断开;设备上 WDA 进程仍在即恢复)。
|
|
ensure_wda(){
|
|
for t in 1 2 3; do
|
|
curl -s --max-time 5 http://localhost:8100/status 2>/dev/null | grep -q '"ready"' && return 0
|
|
echo "[wda] /status 不通,重启 iproxy(第 $t 次)..." | tee -a "$LOG"
|
|
pkill -f "iproxy 8100" 2>/dev/null; sleep 1
|
|
local udid; udid=$(idevice_id -l 2>/dev/null | head -1)
|
|
nohup iproxy 8100 8100 -u "$udid" >/dev/null 2>&1 &
|
|
sleep 5
|
|
done
|
|
curl -s --max-time 5 http://localhost:8100/status 2>/dev/null | grep -q '"ready"' && return 0
|
|
echo "[wda] !! WDA 仍不可达(设备上 WDA 进程可能已退出,需手动重启 WDA)" | tee -a "$LOG"; return 1
|
|
}
|
|
|
|
reset_home(){
|
|
ensure_wda || return 1
|
|
local sid
|
|
sid=$(curl -s --max-time 5 http://localhost:8100/status 2>/dev/null | grep -oE '"sessionId" *: *"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/')
|
|
[ -z "$sid" ] && { echo "[reset] 无 WDA session(WDA 掉了?)" | tee -a "$LOG"; return 1; }
|
|
curl -s -X POST "http://localhost:8100/session/$sid/wda/apps/terminate" -H 'Content-Type: application/json' -d "{\"bundleId\":\"$BUNDLE\"}" >/dev/null 2>&1
|
|
sleep 1
|
|
curl -s -X POST "http://localhost:8100/session/$sid/wda/apps/launch" -H 'Content-Type: application/json' -d "{\"bundleId\":\"$BUNDLE\"}" >/dev/null 2>&1
|
|
sleep 3
|
|
}
|
|
|
|
# 设备控制(两轮:BLE/WiFi 各跑一遍,分别打 PROTO=ble/wifi 标签)。action_panel 作为前置只跑一次。
|
|
CTRL=(
|
|
"meter|npx vitest run tests/meter/meter_control.test.ts"
|
|
"meter_alert_cal|METER_DEVICE='Meter 0B' npx vitest run tests/meter/meter_alert_calibration.test.ts"
|
|
"meterplus_alert_cal|METER_DEVICE='Meter Plus C9' METER_ALERT_STEP=UZCtZRPy METER_CALT_STEP=9mheLMDJ METER_CALH_STEP=GSZv8BYm npx vitest run tests/meter/meter_alert_calibration.test.ts"
|
|
"outdoormeter_alert_cal|METER_DEVICE='Outdoor Meter 6A' METER_ALERT_STEP=QwnZJARA METER_CALT_STEP=Ncg7BDeR METER_CALH_STEP=k6cqKqtZ npx vitest run tests/meter/meter_alert_calibration.test.ts"
|
|
"meterpro_alert_cal|METER_DEVICE='Meter Pro (CO2 Monitor) 6E' METER_ALERT_STEP=JggzNXDo METER_CALT_STEP=L967RGHa METER_CALH_STEP=8Wzaj5pB npx vitest run tests/meter/meter_alert_calibration.test.ts"
|
|
"bot_card|npx vitest run tests/bot/bot_card.test.ts"
|
|
"lock_card|npx vitest run tests/lock/lock_card.test.ts"
|
|
"curtain|npx vitest run tests/curtain/curtain_control.test.ts"
|
|
"curtain3|CURTAIN_DEVICE='Curtain3 Auto' npx vitest run tests/curtain/curtain_control.test.ts"
|
|
"curtain3_2025|CURTAIN_DEVICE='Curtain3 2025 Auto' npx vitest run tests/curtain/curtain_control.test.ts"
|
|
"plug_jp|PLUG_CTRL_DEVICE='Plug JP' npx vitest run tests/plug/plug_mini_control.test.ts"
|
|
"plug_us|PLUG_CTRL_DEVICE='Plug US' npx vitest run tests/plug/plug_mini_control.test.ts"
|
|
"plug_eu|PLUG_CTRL_DEVICE='Plug EU' npx vitest run tests/plug/plug_mini_control.test.ts"
|
|
"blind_tilt|npx vitest run tests/curtain/blind_tilt_control.test.ts"
|
|
"humidifier2|npx vitest run tests/humidifier/humidifier2_card.test.ts"
|
|
"air_purifier|npx vitest run tests/air_purifier/air_purifier_card.test.ts"
|
|
"light_eave|LIGHT_REG=eaveLight LIGHT_CARD='Permanent Outdoor Lights' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_color_bulb|LIGHT_REG=colorBulb LIGHT_CARD='Color Bulb' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_ceiling_pro|LIGHT_REG=ceilingLight LIGHT_CARD='Ceiling Light Pro' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_color_floor|LIGHT_REG=colorFloorLamp LIGHT_CARD='RGBICWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_floor|LIGHT_REG=floorLamp LIGHT_CARD='RGBWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_strip|LIGHT_REG=stripLight LIGHT_CARD='Strip Light SB' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_strip3|LIGHT_REG=stripLight3 LIGHT_CARD='RGBWW Strip Light 3' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_neon|LIGHT_REG=neonLight LIGHT_CARD='RGBIC Neon Rope Light' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
"light_candle|LIGHT_REG=candleLamp LIGHT_CARD='Candle Warmer Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
|
|
# ===== 功能页控制(进设备详情页;iOS 用 tapElement+原地校验,见 reference-ios-feature-control-fixes) =====
|
|
"feat_lock|npx vitest run tests/lock/lock_control.test.ts"
|
|
"feat_curtain|npx vitest run tests/curtain/curtain_feature_control.test.ts"
|
|
"feat_curtain3|CURTAIN_DEVICE='Curtain3 Auto' npx vitest run tests/curtain/curtain_feature_control.test.ts"
|
|
"feat_curtain3_2025|CURTAIN_DEVICE='Curtain3 2025 Auto' npx vitest run tests/curtain/curtain_feature_control.test.ts"
|
|
"feat_blind_tilt|npx vitest run tests/curtain/blind_tilt_feature_control.test.ts"
|
|
"feat_plug|npx vitest run tests/plug/plug_feature_control.test.ts"
|
|
"feat_air_purifier|npx vitest run tests/air_purifier/air_purifier_feature_control.test.ts"
|
|
"feat_humidifier2|npx vitest run tests/humidifier/humidifier2_feature_control.test.ts"
|
|
"feat_color_bulb|npx vitest run tests/color_bulb/color_bulb_feature_control.test.ts"
|
|
"feat_relay_switch|npx vitest run tests/switch/relay_switch_feature_control.test.ts"
|
|
"feat_relay_card|npx vitest run tests/switch/relay_switch_card.test.ts"
|
|
"feat_relay_2pm|npx vitest run tests/switch/relay_switch_2pm_control.test.ts"
|
|
"feat_light_eave|LIGHT_CARD='Permanent Outdoor Lights' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_floor_c|LIGHT_CARD='RGBICWW Floor Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_floor|LIGHT_CARD='RGBWW Floor Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_strip3|LIGHT_CARD='RGBWW Strip Light 3' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_neon|LIGHT_CARD='RGBIC Neon Rope Light' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_ceiling|LIGHT_CARD='Ceiling Light Pro' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"feat_light_candle|LIGHT_CARD='Candle Warmer Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
|
|
"camera_stream|STREAM_HOLD_MS=60000 npx vitest run tests/camera/camera_stream.test.ts"
|
|
)
|
|
# TAIL:keypad 闭环 + 平台 + 账号(只跑一次,不分协议)
|
|
TAIL=(
|
|
"keypad_lock_passcode|npx vitest run tests/keypad/keypad_lock_passcode.test.ts"
|
|
"feedback|npx vitest run tests/platform/feedback.test.ts"
|
|
"rn_plugin|npx vitest run tests/platform/rn_plugin.test.ts"
|
|
"create_room|npx vitest run tests/platform/create_room.test.ts"
|
|
"message_center|npx vitest run tests/platform/message_center.test.ts"
|
|
"scene_operation|npx vitest run tests/platform/scene_operation.test.ts"
|
|
"third_party_login|npx vitest run tests/auth/third_party_login.test.ts"
|
|
"eu_login|npx vitest run tests/auth/eu_login.test.ts"
|
|
"register|npx vitest run tests/auth/register.test.ts"
|
|
"forgot_password|npx vitest run tests/auth/forgot_password.test.ts"
|
|
"delete_account|npx vitest run tests/auth/delete_account.test.ts"
|
|
"login|npx vitest run tests/auth/login.test.ts"
|
|
)
|
|
|
|
echo "===== $(date '+%F %T') iOS 控制批量开始 =====" | tee -a "$LOG"
|
|
# 跑单条:复位→执行→打印结果;含 "✗ [FAIL]" 返回 1(SKIP/无设备不算失败,不重试)。
|
|
run_ctrl_one() {
|
|
local name="$1" cmd="$2"
|
|
echo "----- $(date +%T) [$name] -----" | tee -a "$LOG"
|
|
reset_home
|
|
eval "$cmd" > /tmp/ios-ctrl-one.log 2>&1
|
|
grep -E '✓ \[PASS\]|✗ \[FAIL\]|○ \[SKIP\]|结果:|找不到|未找到|读不到|not found|cannot|诊断|Unable to perform' /tmp/ios-ctrl-one.log | grep -ivE "deprecat" | tail -12 | tee -a "$LOG"
|
|
if grep -q '✗ \[FAIL\]' /tmp/ios-ctrl-one.log; then
|
|
{ echo "========== FAIL: [$name] $cmd @ $(date '+%F %T') =========="; cat /tmp/ios-ctrl-one.log; echo; } >> reports/ios-ctrl-fail.log
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# 跑一轮 CTRL 清单,失败收集后重试一轮。$1=协议标签(打进日志,供 gen-p0-report 按 PROTO 拆分)。
|
|
run_ctrl_pass() {
|
|
local label="$1" entry name cmd
|
|
local failed=()
|
|
for entry in "${CTRL[@]}"; do
|
|
name="${entry%%|*}"; cmd="${entry#*|}"
|
|
# BLE 轮跳过摄像头拉流:拉流依赖 WiFi,BLE 轮 WiFi 已关 → 必失败,白等无意义。仅 WiFi 轮测拉流。
|
|
if [ "$label" = "ble" ] && [ "$name" = "camera_stream" ]; then
|
|
echo "----- [skip][ble] camera_stream(拉流需 WiFi,BLE 轮跳过)-----" | tee -a "$LOG"; continue
|
|
fi
|
|
run_ctrl_one "[$label]$name" "$cmd" || failed+=("$entry")
|
|
done
|
|
if [ ${#failed[@]} -gt 0 ]; then
|
|
echo "===== [$label] 控制失败 ${#failed[@]} 个,重试一轮 =====" | tee -a "$LOG"
|
|
for entry in "${failed[@]}"; do
|
|
name="${entry%%|*}"; cmd="${entry#*|}"
|
|
run_ctrl_one "[$label]${name}-retry" "$cmd" && echo "[CTRL-RETRY-OK][$label] $name" | tee -a "$LOG" || echo "[CTRL-RETRY-GIVEUP][$label] $name" | tee -a "$LOG"
|
|
done
|
|
fi
|
|
}
|
|
|
|
# 前置:打开 Action Panel Settings 所有开关(只跑一次)
|
|
run_ctrl_one "action_panel" "npx vitest run tests/platform/action_panel_settings.test.ts" || true
|
|
|
|
if [ -n "${NO_PROTO_SPLIT:-}" ]; then
|
|
# ===== 单轮:不分 BLE/WiFi,保持当前 radio 态(两端 WiFi+蓝牙都开),控制清单只跑一遍 =====
|
|
echo "===== 控制:单轮(不分协议, radio 保持当前态) =====" | tee -a "$LOG"
|
|
run_ctrl_pass all
|
|
else
|
|
# ===== BLE 轮:WiFi 关(蓝牙保持开)=====
|
|
echo "----- BLE 控制前:WiFi 关闭(蓝牙保持开)-----" | tee -a "$LOG"
|
|
WIFI_TARGET=off npx ts-node scripts/ios-set-wifi.ts 2>&1 | grep -iE "iOS-WiFi|快捷|翻遍" | tee -a "$LOG"
|
|
export PROTO=ble
|
|
echo "===== 控制 PROTO=ble(WiFi 已关) =====" | tee -a "$LOG"
|
|
run_ctrl_pass ble
|
|
|
|
# ===== WiFi 轮:蓝牙关 + WiFi 开 =====
|
|
echo "----- WiFi 控制前:关蓝牙 + 开 WiFi(纯 WiFi)-----" | tee -a "$LOG"
|
|
npx ts-node scripts/ios-toggle-bt.ts 2>&1 | grep -iE "iOS-BT|快捷" | tee -a "$LOG" # 蓝牙 开→关
|
|
WIFI_TARGET=on npx ts-node scripts/ios-set-wifi.ts 2>&1 | grep -iE "iOS-WiFi|快捷|翻遍" | tee -a "$LOG"
|
|
export PROTO=wifi
|
|
echo "===== 控制 PROTO=wifi(WiFi 已开, 蓝牙已关) =====" | tee -a "$LOG"
|
|
run_ctrl_pass wifi
|
|
unset PROTO
|
|
|
|
# 恢复:蓝牙开回来(WiFi 已开),供 TAIL 平台/账号用例
|
|
echo "----- 恢复蓝牙(开)-----" | tee -a "$LOG"
|
|
npx ts-node scripts/ios-toggle-bt.ts 2>&1 | grep -iE "iOS-BT|快捷" | tee -a "$LOG" # 蓝牙 关→开
|
|
fi
|
|
|
|
# ===== TAIL:平台 + 账号(只跑一次,不分协议)=====
|
|
if [ -z "${NO_PROTO_SPLIT:-}" ]; then
|
|
echo "----- 平台 + 账号阶段 -----" | tee -a "$LOG"
|
|
for entry in "${TAIL[@]}"; do
|
|
name="${entry%%|*}"; cmd="${entry#*|}"
|
|
run_ctrl_one "$name" "$cmd" || true
|
|
done
|
|
else
|
|
echo "----- NO_PROTO_SPLIT=1:跳过平台/账号 TAIL(只跑控制)-----" | tee -a "$LOG"
|
|
fi
|
|
echo "===== $(date '+%F %T') iOS 控制完成 =====" | tee -a "$LOG"
|
|
|
|
# 汇总 iOS 全量(添加+控制)逐用例报告 + BLE/WiFi 成功率
|
|
TS=$(date +%Y%m%d-%H%M%S)
|
|
npx ts-node scripts/gen-combined.ts "iOSAll_$TS" >> "$LOG" 2>&1 \
|
|
&& echo "iOS 逐用例报告: reports/iOSAll_${TS}_*.html" | tee -a "$LOG" \
|
|
|| echo "报告生成失败(见 $LOG)" | tee -a "$LOG"
|
|
python3 scripts/gen-p0-report.py reports/ios-controls.log reports/P0_iOS_Ctrl_真实.md 2>&1 | tail -2 | tee -a "$LOG" # 含 BLE/WiFi 成功率表
|