#!/bin/bash # 跑所有已调通的 P0 必测用例,累积出一份合并报告。 # 规则:ADD 阶段跑完后,失败的添加在进 CONTROL 前再重试最多 2 次;2 次仍失败则放弃、继续后续用例。 # SOAK_MODE=1:跨多次 vitest run 累积到 reports/.results.json,末尾 gen-combined 出报告。 set -u cd /Users/woan/Desktop/AI_UIAutomation LOG=reports/p0-all.log export PLATFORM=android SOAK_MODE=1 SKIP_PROTO_NET=1 export LOCK_DEVICE="Lock 6D" LOCK_PRO_DEVICE="Lock Pro DE" BT_DEVICE="Blind Tilt 42" # PLUG_CTRL_DEVICE 不导出:让 plug 控制走 getDeviceName('plug') → 注册表实际名(如 "Plug EU"),不写死 rm -f reports/.results.json # 添加命令(含各设备专属 env);灯类/EU plug 用品类入口区分 ADD_CMDS=( "npx vitest run tests/bot/bot_connect.test.ts" "npx vitest run tests/meter/meter_connect.test.ts" "npx vitest run tests/meter/meter_plus_connect.test.ts" "npx vitest run tests/meter/outdoor_meter_connect.test.ts" "npx vitest run tests/meter/meter_pro_connect.test.ts" "npx vitest run tests/sensor/motion_sensor_connect.test.ts" "npx vitest run tests/sensor/presence_sensor_connect.test.ts" "npx vitest run tests/remote/remote_connect.test.ts" "npx vitest run tests/curtain/curtain_connect.test.ts" "CURTAIN_DEVICE='Curtain3 2B' CURTAIN_CALIBRATE=1 npx vitest run tests/curtain/curtain_connect.test.ts" "CURTAIN_CALIBRATE=1 npx vitest run tests/curtain/curtain3_2025_connect.test.ts" "npx vitest run tests/water_detector/water_detector_connect.test.ts" "npx vitest run tests/hub/hub_matter_connect.test.ts" "npx vitest run tests/find_card/find_card_connect.test.ts" "npx vitest run tests/safety_alarm/safety_alarm_connect.test.ts" "PLUG_MINI_CATEGORY='Plug Mini (JP)' PLUG_MINI_RELAY=plug_mini npx vitest run tests/plug/plug_mini_connect.test.ts" "PLUG_MINI_CATEGORY='Plug Mini (US)' PLUG_MINI_RELAY=plug_mini_us npx vitest run tests/plug/plug_mini_connect.test.ts" "PLUG_MINI_CATEGORY='Plug Mini (EU)' PLUG_MINI_RELAY=plug_mini_eu PLUG_MINI_ONES=332918 npx vitest run tests/plug/plug_mini_connect.test.ts" "npx vitest run tests/color_bulb/color_bulb_connect.test.ts" "npx vitest run tests/ceiling_light/ceiling_light_pro_connect.test.ts" "npx vitest run tests/strip_light/strip_light_connect.test.ts" "npx vitest run tests/ceiling_light/floor_lamp_connect.test.ts" "npx vitest run tests/ceiling_light/color_floor_lamp_connect.test.ts" "npx vitest run tests/strip_light/neon_light_connect.test.ts" "npx vitest run tests/strip_light/strip_light_3_connect.test.ts" "npx vitest run tests/robot/robot_s1p_connect.test.ts" "npx vitest run tests/robot/robot_s10_connect.test.ts" "npx vitest run tests/keypad/keypad_vision_connect.test.ts" "npx vitest run tests/keypad/keypad_touch_connect.test.ts" "npx vitest run tests/aihub/aihub_connect.test.ts -t '通过BLE添加'" "npx vitest run tests/air_purifier/air_purifier_connect.test.ts" "npx vitest run tests/humidifier/humidifier2_connect.test.ts" "npx vitest run tests/ceiling_light/eave_light_connect.test.ts" "npx vitest run tests/urc/urc_connect.test.ts" "npx vitest run tests/hub/relay_switch_connect.test.ts" "npx vitest run tests/hub/hub3_connect.test.ts" "npx vitest run tests/hub/hub_plus_connect.test.ts" "npx vitest run tests/aihub/ai_art_frame_connect.test.ts" "npx vitest run tests/sensor/contact_sensor_connect.test.ts" "npx vitest run tests/camera/doorbell_connect.test.ts" "npx vitest run tests/camera/outdoor_ptc_connect.test.ts" ) CONTROL=( "npx vitest run tests/meter/meter_control.test.ts" "npx vitest run tests/bot/bot_card.test.ts" "npx vitest run tests/lock/lock_card.test.ts" "npx vitest run tests/curtain/curtain_control.test.ts" "CURTAIN_DEVICE='Curtain3 Auto' npx vitest run tests/curtain/curtain_control.test.ts" "CURTAIN_DEVICE='Curtain3 2025 Auto' npx vitest run tests/curtain/curtain_control.test.ts" "PLUG_CTRL_DEVICE='Plug JP' npx vitest run tests/plug/plug_mini_control.test.ts" "PLUG_CTRL_DEVICE='Plug US' npx vitest run tests/plug/plug_mini_control.test.ts" "PLUG_CTRL_DEVICE='Plug EU' npx vitest run tests/plug/plug_mini_control.test.ts" "npx vitest run tests/curtain/blind_tilt_control.test.ts" "npx vitest run tests/humidifier/humidifier2_card.test.ts" "npx vitest run tests/air_purifier/air_purifier_card.test.ts" # 灯类首页卡片控制(电源+亮度+色温):通用用例 eave_light_control,按 LIGHT_CARD 覆盖每个灯(textContains 匹配,免后缀) "LIGHT_REG=eaveLight LIGHT_CARD='Permanent Outdoor Lights' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=colorBulb LIGHT_CARD='Color Bulb' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=ceilingLight LIGHT_CARD='Ceiling Light Pro' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=colorFloorLamp LIGHT_CARD='RGBICWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=floorLamp LIGHT_CARD='RGBWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=stripLight LIGHT_CARD='Strip Light SB' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=stripLight3 LIGHT_CARD='RGBWW Strip Light 3' npx vitest run tests/ceiling_light/eave_light_control.test.ts" "LIGHT_REG=neonLight LIGHT_CARD='RGBIC Neon Rope Light' npx vitest run tests/ceiling_light/eave_light_control.test.ts" ) TAIL=( # Keypad 功能页闭环(绑锁+加密码+物理输密码解锁+清理),只跑一次;依赖 ADD 阶段已加 Keypad Vision Pro + 保留的 Lock 6D。 # 必须在 delete_account 之前(账号注销后设备全清)。默认 KEYPAD_CARD=Keypad Vision(Vision Pro 密码用例需覆盖)。 # ⚠️ Keypad Touch 的密码用例暂不支持(继电器物理键未接)→ 不在 P0 跑;仅 Vision Pro 走此用例。 "npx vitest run tests/keypad/keypad_lock_passcode.test.ts" "STREAM_HOLD_MS=60000 npx vitest run tests/camera/camera_stream.test.ts" "npx vitest run tests/platform/feedback.test.ts" "npx vitest run tests/platform/rn_plugin.test.ts" "npx vitest run tests/platform/create_room.test.ts" "npx vitest run tests/platform/message_center.test.ts" "npx vitest run tests/platform/scene_operation.test.ts" "npx vitest run tests/auth/third_party_login.test.ts" "npx vitest run tests/auth/eu_login.test.ts" "npx vitest run tests/auth/register.test.ts" "npx vitest run tests/auth/forgot_password.test.ts" "npx vitest run tests/auth/delete_account.test.ts" "npx vitest run tests/auth/login.test.ts" ) # 跑一条命令,过滤出结果行;含 "✗ [FAIL]" 视为失败(返回1),否则0(PASS/SKIP) run_one() { local cmd="$1" tmp tmp=$(mktemp) eval "$cmd" > "$tmp" 2>&1 grep -E '✓ \[PASS\]|✗ \[FAIL\]|○ \[SKIP\]|结果:' "$tmp" | tail -12 if grep -q '✗ \[FAIL\]' "$tmp"; then rm -f "$tmp"; return 1; fi rm -f "$tmp"; return 0 } # 恢复手机 WiFi(BLE 控制阶段关了 WiFi)→ 打开并验证 wlan0 拿到 IP(联网成功),最多重试 5 次。 restore_wifi() { for i in 1 2 3 4 5; do adb shell svc wifi enable >/dev/null 2>&1 sleep 8 if adb shell ip addr show wlan0 2>/dev/null | grep -q "inet "; then echo "[WiFi] 已恢复联网(第${i}次)"; return 0 fi echo "[WiFi] 未联网,重试 ${i}/5..."; sleep 5 done echo "[WiFi] WARN: 多次重试仍未恢复 WiFi,后续 WiFi 控制/平台/账号用例可能失败" return 1 } { echo "===== $(date '+%F %T') P0 全量回归开始 =====" echo "----- 复位:删除所有可重加设备(保留 锁/Blind Tilt + 摄像头/门铃,自动化无法重加)-----" # 锁需物理校准、摄像头需扫码,均跳过添加 → 绝不可删,否则对应控制/拉流用例整晚无设备失败。 # Lock Lite / Video Doorbell 同样保留(Doorbell 关键字覆盖门铃,Lock Lite 关键字覆盖锁丽特)。 if [ -z "${CONTROL_ONLY:-}" ]; then RESET_EXCEPT=1 KEEP_DEVICES="Lock 6D,Lock Pro DE,Blind Tilt 42" KEEP_KEYWORDS="Cam,Doorbell,Lock Lite" npx ts-node scripts/reset-except.ts 2>&1 | tail -8 || echo "复位异常(继续跑)" echo "----- ADD 阶段 -----" FAILED=() for cmd in "${ADD_CMDS[@]}"; do echo "--- $(date +%T) $cmd ---" run_one "$cmd" || { echo "[ADD-FAIL] $cmd"; FAILED+=("$cmd"); } done # 规则:失败的添加,进 CONTROL 前重试最多 2 次;仍失败则放弃 if [ ${#FAILED[@]} -gt 0 ]; then echo "===== 添加失败 ${#FAILED[@]} 个,重试(每个最多2次)=====" STILL=() for cmd in "${FAILED[@]}"; do ok=0 for att in 1 2; do echo "--- 重试 $att/2: $cmd ---" if run_one "$cmd"; then ok=1; echo "[RETRY-OK] $cmd"; break; fi done [ $ok -eq 0 ] && { echo "[RETRY-GIVEUP] $cmd"; STILL+=("$cmd"); } done echo "重试后仍失败 ${#STILL[@]} 个(已放弃,继续后续用例)" fi else echo "----- CONTROL_ONLY=1:跳过复位+添加阶段,直接控制现有设备 -----" fi # 添加后:打开 Action Panel Settings 所有开关 → 点设备卡片才弹「快捷动作浮层」(灯/加湿器卡片控制依赖; # 新加设备该开关默认可能 OFF → 否则点卡片进功能页致控制失败)。必须在 CONTROL 之前。 echo "----- 打开 Action Panel Settings 所有开关 -----" run_one "npx vitest run tests/platform/action_panel_settings.test.ts" || true echo "----- CONTROL 阶段(BLE + WiFi 各跑一遍,分别打 15975/15974 锚点)-----" # 跑一遍控制清单,失败的收集后**重试一轮**(控制偶发性高:浮层/卡片漂移/同步延迟)。$1=协议标签。 run_control_pass() { local label="$1" cmd local failed=() export VITEST_RETRY=1 # 控制阶段:单个 it 失败自动重跑一次(用例级,见 vitest.config.ts);添加阶段不受影响 for cmd in "${CONTROL[@]}"; do echo "--- $(date +%T) [$label] $cmd ---" run_one "$cmd" || failed+=("$cmd") done if [ ${#failed[@]} -gt 0 ]; then echo "===== [$label] 控制失败 ${#failed[@]} 个,重试一轮 =====" for cmd in "${failed[@]}"; do echo "--- $(date +%T) [$label][retry] $cmd ---" run_one "$cmd" && echo "[CTRL-RETRY-OK][$label] $cmd" || echo "[CTRL-RETRY-GIVEUP][$label] $cmd" done fi unset VITEST_RETRY } # BLE 阶段:切"仅 BLE"并校验设备已连上(关 WiFi + 复位蓝牙 + 下拉刷新 + 响应度校验 + 重试)。 # 根治"中途切 BLE 后首页卡片全无响应 → BLE 控制整片失败"。失败不阻塞,后续控制照跑。 echo "----- BLE 控制前:切 BLE 并校验设备连上(下拉刷新+重试)-----" PLATFORM=android npx ts-node scripts/switch-ble.ts 2>&1 | tail -6 || echo "切 BLE 校验异常(继续跑)" export PROTO=ble echo "===== 控制 PROTO=ble(手机 WiFi 已关)=====" run_control_pass ble # 关键:BLE 控制完成后恢复手机 WiFi(带重试)。没 WiFi 后续 WiFi 控制+平台+账号都会挂。 restore_wifi export PROTO=wifi echo "===== 控制 PROTO=wifi(手机 WiFi 已恢复)=====" run_control_pass wifi unset PROTO restore_wifi # 进平台/账号前再确保 WiFi 在线 echo "----- 平台 + 账号阶段 -----" if [ -z "${CONTROL_ONLY:-}" ]; then for cmd in "${TAIL[@]}"; do echo "--- $(date +%T) $cmd ---"; run_one "$cmd" || true; done else echo "----- CONTROL_ONLY=1:跳过平台/账号阶段 -----" fi echo "----- 生成合并报告 -----" npx ts-node scripts/gen-combined.ts P0_All_Android python3 scripts/gen-p0-report.py reports/p0-all.log reports/P0_Android_真实结果.md 2>&1 | tail -2 # 含 BLE/WiFi 控制成功率表 echo "===== $(date '+%F %T') 完成 =====" } >> "$LOG" 2>&1