#!/usr/bin/env bash # tests/lib/common.sh — Shared testing utilities BASE_URL="${BASE_URL:-http://localhost:3000}" CLIENT_URL="${CLIENT_URL:-http://localhost:5173}" PASS_COUNT=0 FAIL_COUNT=0 SKIP_COUNT=0 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # --- HTTP helpers --- api_call() { local method="$1" path="$2" token="$3" data="$4" local args=(-s -w '\n%{http_code}' -X "$method") [[ -n "$token" ]] && args+=(-H "Authorization: Bearer $token") [[ -n "$data" ]] && args+=(-H "Content-Type: application/json" -d "$data") curl "${args[@]}" "${BASE_URL}${path}" 2>/dev/null } get_body() { echo "$1" | sed '$ d'; } get_status() { echo "$1" | tail -n1; } # --- Login helper (returns token, retries on rate limit) --- login_as() { local email="$1" password="${2:-password123}" local result body status attempt for attempt in 1 2 3 4 5; do result=$(api_call POST "/api/auth/login" "" "{\"email\":\"$email\",\"password\":\"$password\"}") status=$(get_status "$result") if [[ "$status" == "429" || "$status" == "500" || "$status" == "503" ]]; then sleep "$attempt" continue fi body=$(get_body "$result") echo "$body" | jq -r '.accessToken // empty' 2>/dev/null return done echo "" } # --- Assertions --- assert_status() { local name="$1" expected="$2" actual="$3" if [[ "$expected" == "$actual" ]]; then printf " ${GREEN}PASS${NC} %s (HTTP %s)\n" "$name" "$actual" ((PASS_COUNT++)) else printf " ${RED}FAIL${NC} %s (expected %s, got %s)\n" "$name" "$expected" "$actual" ((FAIL_COUNT++)) fi } assert_json() { local name="$1" body="$2" field="$3" expected="$4" local actual actual=$(echo "$body" | jq -r "$field" 2>/dev/null) if [[ "$actual" == "$expected" ]]; then printf " ${GREEN}PASS${NC} %s (%s = %s)\n" "$name" "$field" "$actual" ((PASS_COUNT++)) else printf " ${RED}FAIL${NC} %s (%s: expected '%s', got '%s')\n" "$name" "$field" "$expected" "$actual" ((FAIL_COUNT++)) fi } assert_json_exists() { local name="$1" body="$2" field="$3" local actual actual=$(echo "$body" | jq -r "$field" 2>/dev/null) if [[ -n "$actual" && "$actual" != "null" ]]; then printf " ${GREEN}PASS${NC} %s (%s exists)\n" "$name" "$field" ((PASS_COUNT++)) else printf " ${RED}FAIL${NC} %s (%s is null/missing)\n" "$name" "$field" ((FAIL_COUNT++)) fi } assert_json_array_min() { local name="$1" body="$2" field="$3" min="${4:-1}" local length length=$(echo "$body" | jq "$field | length" 2>/dev/null) if [[ "$length" -ge "$min" ]] 2>/dev/null; then printf " ${GREEN}PASS${NC} %s (%s items)\n" "$name" "$length" ((PASS_COUNT++)) else printf " ${RED}FAIL${NC} %s (expected >= %s items, got %s)\n" "$name" "$min" "$length" ((FAIL_COUNT++)) fi } assert_contains() { local name="$1" body="$2" substring="$3" if echo "$body" | grep -q "$substring"; then printf " ${GREEN}PASS${NC} %s (contains '%s')\n" "$name" "$substring" ((PASS_COUNT++)) else printf " ${RED}FAIL${NC} %s (missing '%s')\n" "$name" "$substring" ((FAIL_COUNT++)) fi } skip_test() { local name="$1" reason="$2" printf " ${YELLOW}SKIP${NC} %s (%s)\n" "$name" "$reason" ((SKIP_COUNT++)) } # --- Stage header/summary --- stage_header() { echo "" printf "${CYAN}${BOLD}════════════════════════════════════════${NC}\n" printf "${CYAN}${BOLD} %s${NC}\n" "$1" printf "${CYAN}${BOLD}════════════════════════════════════════${NC}\n" } print_summary() { local name="$1" echo "" printf "${BOLD}--- %s Results ---${NC}\n" "$name" printf " ${GREEN}Passed: %d${NC}\n" "$PASS_COUNT" [[ $FAIL_COUNT -gt 0 ]] && printf " ${RED}Failed: %d${NC}\n" "$FAIL_COUNT" [[ $SKIP_COUNT -gt 0 ]] && printf " ${YELLOW}Skipped: %d${NC}\n" "$SKIP_COUNT" printf " Total: %d\n" "$((PASS_COUNT + FAIL_COUNT + SKIP_COUNT))" [[ $FAIL_COUNT -gt 0 ]] && return 1 return 0 }