文件
hyb-oa/scripts/qa/run-local-candidate.sh
T

166 行
5.5 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CLIENT_DIR="$ROOT_DIR/client"
MODE="${1:-full}"
DEV_SERVER_PID=""
DEV_SERVER_LOG=""
PLAYWRIGHT_RESULT_FILE=""
PLAYWRIGHT_STDERR_LOG=""
usage() {
printf '%s\n' \
"Usage: bash scripts/qa/run-local-candidate.sh [full|focused|list]" \
"" \
" full 完整基础门禁 + 路由反例 + 本地 Vite 行为测试(默认)" \
" focused 路由反例 + 本地 Vite 行为测试,不代表完整候选通过" \
" list 只解析 Playwright 测试资产,不代表行为通过"
}
cleanup() {
local exit_code="$?"
if [[ -n "$DEV_SERVER_PID" ]] && kill -0 "$DEV_SERVER_PID" 2>/dev/null; then
kill "$DEV_SERVER_PID" 2>/dev/null || true
wait "$DEV_SERVER_PID" 2>/dev/null || true
fi
if [[ "$exit_code" -ne 0 ]]; then
local vite_log_lines=0
local playwright_log_lines=0
if [[ -n "$DEV_SERVER_LOG" && -f "$DEV_SERVER_LOG" ]]; then
vite_log_lines="$(wc -l < "$DEV_SERVER_LOG" | tr -d ' ')"
fi
if [[ -n "$PLAYWRIGHT_STDERR_LOG" && -f "$PLAYWRIGHT_STDERR_LOG" ]]; then
playwright_log_lines="$(wc -l < "$PLAYWRIGHT_STDERR_LOG" | tr -d ' ')"
fi
echo "[local-candidate][ERROR] safe_summary exit=${exit_code} vite_log_lines=${vite_log_lines} playwright_log_lines=${playwright_log_lines}" >&2
fi
[[ -z "$DEV_SERVER_LOG" ]] || rm -f "$DEV_SERVER_LOG"
[[ -z "$PLAYWRIGHT_RESULT_FILE" ]] || rm -f "$PLAYWRIGHT_RESULT_FILE"
[[ -z "$PLAYWRIGHT_STDERR_LOG" ]] || rm -f "$PLAYWRIGHT_STDERR_LOG"
return "$exit_code"
}
trap cleanup EXIT
case "$MODE" in
full|focused|list) ;;
help|-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
cd "$ROOT_DIR"
echo "=== [1/4] 路由 manifest 与反例测试 ==="
node --test \
scripts/qa/tests/check-minimal-profile.test.mjs \
scripts/qa/tests/check-flow-coverage.test.mjs \
scripts/qa/tests/validate-loopback-url.test.mjs \
scripts/qa/tests/verify-local-candidate-results.test.mjs
node scripts/qa/check-flow-coverage.mjs --local-candidate --json
if [[ "$MODE" == "full" ]]; then
echo "=== [2/4] 完整本地基础门禁 ==="
bash scripts/check-minimal.sh local-candidate
else
echo "=== [2/4] 完整本地基础门禁(focused/list 跳过) ==="
fi
mapfile -t CANDIDATE_SPECS < <(
node -e '
const manifest = require("./scripts/qa/route-manifest.json");
const expected = new Set(manifest.coreBundles ?? []);
const flows = manifest.localCandidateFlows ?? [];
const observed = new Set(flows.map((flow) => flow.bundle));
if (expected.size !== 10 || expected.size !== observed.size || [...expected].some((bundle) => !observed.has(bundle))) {
throw new Error("localCandidateFlows 未完整覆盖 coreBundles");
}
const witnessSpecs = flows.map((flow) => flow.witnessSpec);
const specs = [...new Set([...witnessSpecs, ...(manifest.acceptanceSpecs ?? [])])];
for (const spec of specs) {
if (typeof spec !== "string" || !spec.startsWith("client/tests/e2e/") || spec.includes("/manual/") || /live/i.test(spec)) {
throw new Error(`非法本地候选 spec: ${String(spec)}`);
}
console.log(spec.slice("client/".length));
}
'
)
if [[ "${#CANDIDATE_SPECS[@]}" -eq 0 ]]; then
echo "[local-candidate][ERROR] route-manifest 未登记 localCandidateFlows" >&2
exit 1
fi
if [[ "$MODE" == "list" ]]; then
echo "=== [3/4] Playwright 资产解析(不代表行为通过) ==="
(
cd "$CLIENT_DIR"
npx playwright test "${CANDIDATE_SPECS[@]}" --list
)
echo "=== [4/4] LIST_ONLY ==="
exit 0
fi
BASE_URL="${E2E_BASE_URL:-}"
if [[ -z "$BASE_URL" ]]; then
PORT="$(node scripts/qa/validate-loopback-url.mjs --port "${LOCAL_CANDIDATE_PORT:-5178}")"
BASE_URL="$(node scripts/qa/validate-loopback-url.mjs "http://127.0.0.1:${PORT}")"
DEV_SERVER_LOG="${TMPDIR:-/tmp}/hyb-oa-local-candidate-vite-${PORT}-$$.log"
(
cd "$CLIENT_DIR"
npm run dev -- --host 127.0.0.1 --port "$PORT" --strictPort
) >"$DEV_SERVER_LOG" 2>&1 &
DEV_SERVER_PID="$!"
VITE_READY=0
for _ in $(seq 1 60); do
if curl --fail --silent --show-error "$BASE_URL/login" >/dev/null 2>&1; then
VITE_READY=1
break
fi
if ! kill -0 "$DEV_SERVER_PID" 2>/dev/null; then
echo "[local-candidate][ERROR] 本地 Vite 启动失败" >&2
exit 1
fi
sleep 0.25
done
if [[ "$VITE_READY" -ne 1 ]]; then
echo "[local-candidate][ERROR] 本地 Vite 就绪超时" >&2
exit 1
fi
else
BASE_URL="$(node scripts/qa/validate-loopback-url.mjs "$BASE_URL")"
fi
echo "=== [3/4] 本地合成浏览器行为 ==="
PLAYWRIGHT_RESULT_FILE="$(mktemp "${TMPDIR:-/tmp}/hyb-oa-local-candidate-results.XXXXXX.json")"
PLAYWRIGHT_STDERR_LOG="$(mktemp "${TMPDIR:-/tmp}/hyb-oa-local-candidate-playwright.XXXXXX.log")"
PLAYWRIGHT_STATUS=0
(
cd "$CLIENT_DIR"
E2E_MODE=local E2E_BASE_URL="$BASE_URL" \
npx playwright test "${CANDIDATE_SPECS[@]}" --workers=1 --reporter=json
) >"$PLAYWRIGHT_RESULT_FILE" 2>"$PLAYWRIGHT_STDERR_LOG" || PLAYWRIGHT_STATUS="$?"
RESULT_GATE_STATUS=0
node scripts/qa/verify-local-candidate-results.mjs \
--manifest scripts/qa/route-manifest.json \
--results "$PLAYWRIGHT_RESULT_FILE" || RESULT_GATE_STATUS="$?"
if [[ "$PLAYWRIGHT_STATUS" -ne 0 || "$RESULT_GATE_STATUS" -ne 0 ]]; then
echo "[local-candidate][ERROR] browser_exit=${PLAYWRIGHT_STATUS} witness_result_gate=${RESULT_GATE_STATUS}" >&2
exit 1
fi
if [[ "$MODE" == "full" ]]; then
echo "=== [4/4] LOCAL_CANDIDATE_PASS ==="
else
echo "=== [4/4] FOCUSED_BROWSER_PASS ==="
fi