#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" CLIENT_DIR="$ROOT_DIR/client" MODE="${1:-local}" REPORT_DIR="${BUSINESS_FLOW_REPORT_DIR:-$ROOT_DIR/artifacts/qa-flow/business-flow-$(date +%Y%m%d-%H%M%S)}" mkdir -p "$REPORT_DIR" write_summary() { local exit_code="$?" if [[ "$MODE" == "help" || "$MODE" == "-h" || "$MODE" == "--help" || "$MODE" == "list" ]]; then return "$exit_code" fi if [[ "$MODE" == "local" && -f "$REPORT_DIR/summary.json" ]]; then return "$exit_code" fi local status="PASS" if [[ "$exit_code" -ne 0 ]]; then status="FAIL" fi QA_REPORT_DIR="$REPORT_DIR" \ QA_ISSUE_ID="${QA_ISSUE_ID:-}" \ QA_BASE_URL="${E2E_BASE_URL:-}" \ QA_MODE="business-flow-${MODE}" \ QA_STATUS="$status" \ QA_SUMMARY_NOTES="业务流门禁按 BUSINESS_FLOW_GROUPS 选择领域执行;summary.txt 保留逐组通过/失败明细。" \ BUSINESS_FLOW_GROUPS="${BUSINESS_FLOW_GROUPS:-}" \ node "$ROOT_DIR/scripts/qa/write-qa-summary.mjs" >/dev/null 2>&1 || true return "$exit_code" } trap write_summary EXIT usage() { cat < 说明: local 通过 scripts/qa/run-web-gates.sh business-flow-local 准备临时库和服务后运行 attached 复用当前 E2E_BASE_URL 直接按业务域执行 Playwright list 仅输出业务域与用例清单 可选环境变量: BUSINESS_FLOW_GROUPS=auth,reimbursement 仅运行部分业务域 BUSINESS_FLOW_EXCLUDE_SPECS=tests/e2e/a.spec.ts,tests/e2e/b.spec.ts 从已选业务域中排除指定 Playwright spec,多个值可用逗号或空白分隔 E2E_BASE_URL attached 模式下必填或沿用 Playwright 默认 USAGE } declare -a GROUP_ORDER=( auth reimbursement approval leave collaboration hr project procurement asset travel governance ) specs_for_group() { case "$1" in auth) printf '%s\n' \ tests/e2e/login-portal-ux.spec.ts \ tests/e2e/wecom-entry.spec.ts \ tests/e2e/wecom-first-bind.spec.ts \ tests/e2e/r89-mobile-login-navigation.spec.ts ;; reimbursement) printf '%s\n' \ tests/e2e/reimbursement-workflow-progress.spec.ts \ tests/e2e/invoice-ocr-flow.spec.ts \ tests/e2e/reimbursement-payment-batch-flow.spec.ts \ tests/e2e/r102-reimbursement-main-flow.spec.ts \ tests/e2e/r111-invoice-reimbursement-guard.spec.ts \ tests/e2e/r125-invoice-reupload-after-delete.spec.ts ;; approval) printf '%s\n' \ tests/e2e/workflow-quick-approve.spec.ts \ tests/e2e/mobile-approvals-offline.spec.ts ;; leave) printf '%s\n' \ tests/e2e/leave-flow.spec.ts \ tests/e2e/leave-team-calendar.spec.ts ;; collaboration) printf '%s\n' \ tests/e2e/weekly-todo-flow.spec.ts \ tests/e2e/announcements-presence.spec.ts \ tests/e2e/global-search.spec.ts ;; hr) printf '%s\n' \ tests/e2e/user-onboarding.spec.ts \ tests/e2e/r75-automation-gap-fill.spec.ts ;; project) printf '%s\n' \ tests/e2e/project-workbench.spec.ts \ tests/e2e/confidential-boundary.spec.ts ;; procurement) printf '%s\n' \ tests/e2e/procurement-flow.spec.ts ;; asset) printf '%s\n' \ tests/e2e/assets-flow.spec.ts ;; travel) printf '%s\n' \ tests/e2e/travel-payment-flow.spec.ts \ tests/e2e/travel-reconciliation-flow.spec.ts ;; governance) printf '%s\n' \ tests/e2e/permission-direct-access.spec.ts \ tests/e2e/settings-governance.spec.ts ;; *) echo "[business-flow][ERROR] 未知业务域:$1" >&2 return 1 ;; esac } selected_groups() { if [[ -n "${BUSINESS_FLOW_GROUPS:-}" ]]; then tr ',' '\n' <<<"$BUSINESS_FLOW_GROUPS" | sed '/^$/d' return fi printf '%s\n' "${GROUP_ORDER[@]}" } spec_is_excluded() { local candidate="$1" local raw="${BUSINESS_FLOW_EXCLUDE_SPECS:-}" local excluded [[ -n "$raw" ]] || return 1 while IFS= read -r excluded; do [[ -n "$excluded" ]] || continue if [[ "$candidate" == "$excluded" ]]; then return 0 fi done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n') return 1 } existing_specs_for_group() { local group="$1" local spec while IFS= read -r spec; do [[ -f "$CLIENT_DIR/$spec" ]] || continue spec_is_excluded "$spec" && continue printf '%s\n' "$spec" done < <(specs_for_group "$group") } list_groups() { local group for group in "${GROUP_ORDER[@]}"; do echo "[$group]" existing_specs_for_group "$group" | sed 's/^/ - /' done } run_attached() { local group local status=0 local summary="$REPORT_DIR/summary.txt" : >"$summary" for group in $(selected_groups); do mapfile -t specs < <(existing_specs_for_group "$group") if [[ "${#specs[@]}" -eq 0 ]]; then echo "[business-flow][SKIP] $group:无可执行 spec" | tee -a "$summary" continue fi echo ">>> [business-flow] $group" | tee -a "$summary" if ( cd "$CLIENT_DIR" E2E_MODE=local npx playwright test "${specs[@]}" --workers=1 --reporter=list ); then echo "[business-flow][PASS] $group" | tee -a "$summary" else echo "[business-flow][FAIL] $group" | tee -a "$summary" status=1 break fi done echo "[business-flow] report=$summary" return "$status" } case "$MODE" in help|-h|--help) usage ;; list) list_groups ;; attached) run_attached ;; local) BUSINESS_FLOW_REPORT_DIR="$REPORT_DIR" bash "$ROOT_DIR/scripts/qa/run-web-gates.sh" business-flow-local ;; *) usage >&2 exit 1 ;; esac