#!/usr/bin/env bash # ═══════════════════════════════════════════════ # E2E Workflow Test — Without Chat # ═══════════════════════════════════════════════ # # Verifies the complete workflow lifecycle works without chat or # chat-core packages installed. Uses only admin API + PAT auth. # # Proves: workflow independence from optional packages. # # Prerequisites: # - Server running at $SERVER_URL (default: http://localhost:3000) # - ADMIN_USER / ADMIN_PASS env vars (default: admin/admin) # # Exit codes: 0 = all assertions passed, 1 = failures detected set -euo pipefail SERVER_URL="${SERVER_URL:-http://localhost:3000}" ADMIN_USER="${ADMIN_USER:-admin}" ADMIN_PASS="${ADMIN_PASS:-admin}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' PASS=0 FAIL=0 assert() { local desc="$1" ok="$2" if [ "$ok" = "true" ]; then echo -e " ${GREEN}✓${NC} $desc" PASS=$((PASS + 1)) else echo -e " ${RED}✗${NC} $desc" FAIL=$((FAIL + 1)) fi } echo -e "${YELLOW}═══ E2E Workflow Independence Test ═══${NC}" echo " Server: ${SERVER_URL}" # ── Authenticate ───────────────────────────── TOKEN="" PAT_FILE="/tmp/armature-admin-pat.txt" if [ -f "$PAT_FILE" ]; then TOKEN=$(cat "$PAT_FILE") fi if [ -z "$TOKEN" ]; then TOKEN=$(curl -sf -X POST "${SERVER_URL}/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d "{\"login\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASS}\"}" \ | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{try{console.log(JSON.parse(d).token)}catch(e){process.exit(1)}})" 2>/dev/null || true) fi if [ -z "$TOKEN" ]; then echo -e "${RED}Failed to authenticate${NC}" exit 1 fi echo -e "${GREEN}Authenticated${NC}" AUTH="Authorization: Bearer ${TOKEN}" # ── Verify chat is NOT installed ───────────── echo -e "\n${YELLOW}Phase 1: Verify chat packages not required${NC}" CHAT_PKG=$(curl -sf -H "$AUTH" "${SERVER_URL}/api/v1/admin/packages" \ | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{ const pkgs = JSON.parse(d).data || JSON.parse(d); const chat = (Array.isArray(pkgs) ? pkgs : []).filter(p => p.id === 'chat' || p.id === 'chat-core'); console.log(JSON.stringify(chat)); })" 2>/dev/null || echo "[]") echo " Chat packages found: ${CHAT_PKG}" # ── Create a test workflow ─────────────────── echo -e "\n${YELLOW}Phase 2: Create workflow via admin API${NC}" WF_RESP=$(curl -sf -X POST "${SERVER_URL}/api/v1/workflows" \ -H "$AUTH" -H "Content-Type: application/json" \ -d '{ "name": "E2E No-Chat Test", "slug": "e2e-nochat-test", "description": "Workflow independence E2E test", "entry_mode": "public_link", "is_active": true }' 2>/dev/null || echo '{"error":"failed"}') WF_ID=$(echo "$WF_RESP" | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{try{console.log(JSON.parse(d).id||'')}catch(e){console.log('')}})" 2>/dev/null) assert "Workflow created" "$([ -n "$WF_ID" ] && echo true || echo false)" if [ -z "$WF_ID" ]; then echo -e "${RED}Cannot continue without workflow ID${NC}" echo "Response: ${WF_RESP}" exit 1 fi # ── Add a form stage ───────────────────────── echo -e "\n${YELLOW}Phase 3: Add form stage${NC}" STAGE_RESP=$(curl -sf -X POST "${SERVER_URL}/api/v1/workflows/${WF_ID}/stages" \ -H "$AUTH" -H "Content-Type: application/json" \ -d '{ "name": "Intake Form", "stage_mode": "form", "ordinal": 0, "form_template": { "fields": [ {"key": "title", "type": "text", "label": "Issue Title", "required": true}, {"key": "description", "type": "textarea", "label": "Description"} ] } }' 2>/dev/null || echo '{"error":"failed"}') STAGE_ID=$(echo "$STAGE_RESP" | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{try{console.log(JSON.parse(d).id||'')}catch(e){console.log('')}})" 2>/dev/null) assert "Form stage created" "$([ -n "$STAGE_ID" ] && echo true || echo false)" # ── Add a review stage ─────────────────────── REVIEW_RESP=$(curl -sf -X POST "${SERVER_URL}/api/v1/workflows/${WF_ID}/stages" \ -H "$AUTH" -H "Content-Type: application/json" \ -d '{ "name": "Manager Review", "stage_mode": "review", "ordinal": 1 }' 2>/dev/null || echo '{"error":"failed"}') REVIEW_ID=$(echo "$REVIEW_RESP" | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>{try{console.log(JSON.parse(d).id||'')}catch(e){console.log('')}})" 2>/dev/null) assert "Review stage created" "$([ -n "$REVIEW_ID" ] && echo true || echo false)" # ── Landing page responds ──────────────────── echo -e "\n${YELLOW}Phase 4: Landing page accessible${NC}" LANDING_STATUS=$(curl -so /dev/null -w "%{http_code}" "${SERVER_URL}/w/global/e2e-nochat-test" 2>/dev/null || echo "000") assert "Landing page returns 200" "$([ "$LANDING_STATUS" = "200" ] && echo true || echo false)" # ── Start workflow via public API ──────────── echo -e "\n${YELLOW}Phase 5: Start workflow (public entry)${NC}" START_RESP=$(curl -sf -X POST "${SERVER_URL}/api/v1/workflow-entry/global/e2e-nochat-test" \ -H "Content-Type: application/json" \ -d '{}' 2>/dev/null || echo '{"error":"failed"}') INST_ID=$(echo "$START_RESP" | node -e "process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c; process.stdin.on('end',()=>{try{console.log(JSON.parse(d).id||'')}catch(e){console.log('')}})" 2>/dev/null) assert "Instance created" "$([ -n "$INST_ID" ] && echo true || echo false)" # ── Workflow page renders ──────────────────── echo -e "\n${YELLOW}Phase 6: Workflow execution page${NC}" if [ -n "$INST_ID" ]; then WF_PAGE_STATUS=$(curl -so /dev/null -w "%{http_code}" "${SERVER_URL}/w/${INST_ID}" 2>/dev/null || echo "000") assert "Workflow page returns 200" "$([ "$WF_PAGE_STATUS" = "200" ] && echo true || echo false)" fi # ── Cleanup: delete workflow ───────────────── echo -e "\n${YELLOW}Cleanup${NC}" curl -sf -X DELETE "${SERVER_URL}/api/v1/workflows/${WF_ID}" \ -H "$AUTH" >/dev/null 2>&1 || true echo -e " Deleted test workflow" # ── Summary ────────────────────────────────── echo "" TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo -e "${GREEN}═══ All ${TOTAL} assertions passed ═══${NC}" exit 0 else echo -e "${RED}═══ ${FAIL}/${TOTAL} assertions failed ═══${NC}" exit 1 fi