#!/bin/bash set -euo pipefail # Full-Stack App E2E Test Script # Usage: ./cookbooks/scripts/fullstack-test.sh # Commands: run, status, teardown SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/common.sh" COMMAND="${1:-}" PROJECT_NAME="${2:-}" if [[ -z "$COMMAND" || -z "$PROJECT_NAME" ]]; then echo "Usage: $0 " echo "Commands:" echo " run - Create project and run full-stack build" echo " status - Check build and deployment status" echo " teardown - Delete the project" exit 1 fi # Full-stack app build prompt FULLSTACK_PROMPT='Build a full-stack task management application with the following structure: FRONTEND (Next.js 14 + shadcn/ui): - Create a Next.js 14 app with App Router in /frontend - Use shadcn/ui for all components (install with npx shadcn-ui@latest init) - Dark theme with modern aesthetic - Pages: Dashboard showing tasks, Add Task form, Task detail view - Use Tailwind CSS for styling - Connect to backend API at /api proxy BACKEND (Go): - Create a Go HTTP server in /backend using chi router - Endpoints: GET /api/tasks, POST /api/tasks, GET /api/tasks/{id}, DELETE /api/tasks/{id} - In-memory task storage (no database needed) - Structured JSON responses - CORS middleware for frontend DOCKER: - /frontend/Dockerfile: Multi-stage build for Next.js (node:20-alpine) - /backend/Dockerfile: Multi-stage build for Go (golang:1.22-alpine) - /docker-compose.yml: Run both services, frontend proxies to backend CI/CD: - /.woodpecker.yml: Build both images, push to registry, deploy to k8s Create all necessary files including package.json, go.mod, and configuration files.' # Test backend API test_backend_api() { local domain="$1" echo "Testing backend API..." # Test GET /api/tasks local response response=$(curl -s "https://$domain/api/tasks" 2>/dev/null || echo '{"error":"failed"}') if echo "$response" | jq -e '.' > /dev/null 2>&1; then echo " GET /api/tasks: OK" echo " Response: $response" return 0 else echo " GET /api/tasks: FAILED" echo " Response: $response" return 1 fi } run_flow() { echo "=== Full-Stack App E2E Test ===" echo "Project: $PROJECT_NAME" echo "" # Step 1: Create project with build echo "Step 1: Creating project and submitting full-stack build..." local create_result # Build the JSON payload (prompt, auto_commit, auto_push are top-level fields) local payload payload=$(jq -n \ --arg name "$PROJECT_NAME" \ --arg desc "Full-stack app E2E test" \ --arg prompt "$FULLSTACK_PROMPT" \ '{ name: $name, description: $desc, prompt: $prompt, auto_commit: true, auto_push: true }') create_result=$(api_call POST "/project/create-and-build" "$payload") echo "$create_result" | jq '.' local domain domain=$(echo "$create_result" | jq -r '.data.domain // .domain // ""') local task_id task_id=$(echo "$create_result" | jq -r '.data.task_id // .task_id // ""') if [[ -z "$domain" || -z "$task_id" ]]; then echo "ERROR: Failed to create project" exit 1 fi echo "" echo "Domain: $domain" echo "Build Task: $task_id" echo "" # Step 2: Wait for build echo "Step 2: Waiting for Claude to build the full-stack app..." if ! wait_for_build "$task_id"; then echo "ERROR: Build failed" exit 1 fi echo "" # Step 3: Wait for CI pipeline echo "Step 3: Waiting for CI pipeline to build and deploy..." if ! wait_for_pipeline "$PROJECT_NAME"; then echo "WARNING: Pipeline may have failed, continuing to check site..." fi echo "" # Step 4: Wait for site echo "Step 4: Verifying site is accessible..." if ! wait_for_site "$domain"; then echo "ERROR: Site not accessible" exit 1 fi echo "" # Step 5: Test backend API echo "Step 5: Testing backend API..." if ! test_backend_api "$domain"; then echo "WARNING: Backend API test failed" fi echo "" # Summary echo "=== E2E Test Results ===" echo "Project created: PASS" echo "Build completed: PASS" echo "CI Pipeline: $(wait_for_pipeline "$PROJECT_NAME" > /dev/null 2>&1 && echo "PASS" || echo "CHECK")" echo "Site accessible: PASS" echo "Backend API: $(test_backend_api "$domain" > /dev/null 2>&1 && echo "PASS" || echo "CHECK")" echo "" echo "Site URL: https://$domain" echo "Git repo: https://git.threesix.ai/jordan/$PROJECT_NAME" echo "CI: https://ci.threesix.ai/jordan/$PROJECT_NAME" } check_status() { echo "=== Project Status: $PROJECT_NAME ===" echo "" # Get project info local project_result project_result=$(api_call GET "/projects/$PROJECT_NAME") echo "Project:" echo "$project_result" | jq '.' echo "" # Get latest build echo "Latest Builds:" api_call GET "/projects/$PROJECT_NAME/builds" | jq '.data[:3]' echo "" # Get latest pipeline echo "Latest Pipelines:" api_call GET "/projects/$PROJECT_NAME/pipelines" | jq '.data[:3]' } teardown() { echo "=== Tearing down: $PROJECT_NAME ===" local result result=$(api_call DELETE "/project/$PROJECT_NAME") echo "$result" | jq '.' echo "" echo "Project deleted. Gitea repo preserved." } case "$COMMAND" in run) run_flow ;; status) check_status ;; teardown) teardown ;; *) echo "Unknown command: $COMMAND" echo "Valid commands: run, status, teardown" exit 1 ;; esac