payfrit-qa/shared/lib/test_helpers.sh
Luna (QA) e6153ac4b7 Add QA test framework — API tests, infra health, test data seeding
Payfrit:
- Tab API contract tests (bash + python) — all 13 endpoints
- Param validation, response time, cross-env parity checks

Grubflip:
- API endpoint test stubs — menu, restaurant, order, auth
- Ready to activate as Mike deploys endpoints

Shared:
- test_helpers.sh + test_helpers.py — HTTP helpers, pass/fail/skip, JSON output mode
- Master test runner (scripts/run-all.sh)
- Infrastructure health checker (disk, RAM, services, SSL certs)

Test data:
- Grubflip seed SQL (QA test restaurants, menus, orders)
- Payfrit tab seeder script

All Payfrit tab tests confirmed passing against dev + prod.
2026-03-26 05:57:37 +00:00

101 lines
3.1 KiB
Bash

#!/usr/bin/env bash
# ============================================================
# test_helpers.sh — Shared test utilities
# Source this in any test script: source shared/lib/test_helpers.sh
# ============================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0
TEST_RESULTS=()
JSON_MODE=false
# Parse --json flag
for arg in "$@"; do
[ "$arg" = "--json" ] && JSON_MODE=true
done
pass() {
local msg="$1"
((PASS_COUNT++))
TEST_RESULTS+=("{\"status\":\"pass\",\"test\":\"$msg\"}")
$JSON_MODE || echo -e " ${GREEN}${NC} $msg"
}
fail() {
local msg="$1"
local detail="${2:-}"
((FAIL_COUNT++))
TEST_RESULTS+=("{\"status\":\"fail\",\"test\":\"$msg\",\"detail\":\"$detail\"}")
$JSON_MODE || echo -e " ${RED}${NC} $msg${detail:+ — $detail}"
}
skip() {
local msg="$1"
local reason="${2:-}"
((SKIP_COUNT++))
TEST_RESULTS+=("{\"status\":\"skip\",\"test\":\"$msg\",\"reason\":\"$reason\"}")
$JSON_MODE || echo -e " ${YELLOW}⏭️${NC} $msg${reason:+ — $reason}"
}
section() {
$JSON_MODE || echo -e "\n${CYAN}━━━ $1 ━━━${NC}"
}
# HTTP helper: returns "status_code|body|time_ms"
http_get() {
local url="$1"
local tmpfile=$(mktemp)
local http_code time_total body
http_code=$(curl -sk -o "$tmpfile" -w "%{http_code}" "$url" 2>/dev/null)
time_total=$(curl -sk -o /dev/null -w "%{time_total}" "$url" 2>/dev/null)
body=$(cat "$tmpfile")
rm -f "$tmpfile"
local ms=$(echo "$time_total * 1000" | bc 2>/dev/null | cut -d'.' -f1)
echo "${http_code}|${body}|${ms:-0}"
}
http_post() {
local url="$1"
local data="${2:-{}}"
local tmpfile=$(mktemp)
local http_code
http_code=$(curl -sk -X POST -o "$tmpfile" -w "%{http_code}" \
-H "Content-Type: application/json" -d "$data" "$url" 2>/dev/null)
local body=$(cat "$tmpfile")
rm -f "$tmpfile"
echo "${http_code}|${body}"
}
# JSON field extractor (requires python3)
json_field() {
local json="$1"
local field="$2"
echo "$json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('$field',''))" 2>/dev/null
}
is_valid_json() {
echo "$1" | python3 -c "import sys,json; json.load(sys.stdin)" 2>/dev/null
}
# Print summary and exit with appropriate code
test_summary() {
local total=$((PASS_COUNT + FAIL_COUNT + SKIP_COUNT))
if $JSON_MODE; then
echo "{\"total\":$total,\"pass\":$PASS_COUNT,\"fail\":$FAIL_COUNT,\"skip\":$SKIP_COUNT,\"results\":[$(IFS=,; echo "${TEST_RESULTS[*]}")]}"
else
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e " TOTAL: $total | ${GREEN}PASS: $PASS_COUNT${NC} | ${RED}FAIL: $FAIL_COUNT${NC} | ${YELLOW}SKIP: $SKIP_COUNT${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
fi
[ "$FAIL_COUNT" -eq 0 ] && return 0 || return 1
}