Implement external-results case endpoints with test-case auto-upsert, transition enforcement, and traceability linking #280
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E Tests | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'frontend/**' | |
| - 'backend/**' | |
| - 'docker-compose.test.yml' | |
| - '.github/workflows/e2e-tests.yml' | |
| pull_request: | |
| branches: | |
| - main | |
| paths: | |
| - 'frontend/**' | |
| - 'backend/**' | |
| - 'docker-compose.test.yml' | |
| - '.github/workflows/e2e-tests.yml' | |
| jobs: | |
| e2e: | |
| name: Playwright E2E Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Install Playwright browsers | |
| working-directory: frontend | |
| run: npx playwright install --with-deps chromium | |
| - name: Start test environment | |
| run: docker compose -f docker-compose.test.yml build --no-cache && docker compose -f docker-compose.test.yml up -d | |
| - name: Wait for backend to be healthy | |
| run: | | |
| echo "Waiting for backend health check..." | |
| for i in $(seq 1 24); do | |
| if curl -sf http://localhost:8001/health; then | |
| echo "Backend is healthy!" | |
| break | |
| fi | |
| echo "Attempt $i/24 — backend not ready yet, waiting 10s..." | |
| sleep 10 | |
| done | |
| # Final check — fail loudly if still not healthy | |
| curl -sf http://localhost:8001/health || (echo "Backend failed to become healthy" && exit 1) | |
| - name: Wait for frontend health check | |
| run: | | |
| timeout 60 bash -c ' | |
| until curl -sf http://localhost:3001; do | |
| echo "Frontend not ready, retrying in 5s..." | |
| sleep 5 | |
| done | |
| ' | |
| - name: Verify API routing | |
| continue-on-error: true | |
| run: | | |
| set +e | |
| echo "=== Checking API proxy via nginx ===" | |
| curl -sv http://localhost:3001/api/v1/auth/login 2>&1 | tail -20 || true | |
| echo "" | |
| echo "=== Checking backend health directly ===" | |
| curl -sf http://localhost:8001/health || echo "Backend direct check failed" | |
| echo "" | |
| echo "=== Checking for hardcoded localhost:8000 in JS bundle ===" | |
| curl -s http://localhost:3001/ | grep -o 'src="[^"]*\.js"' | head -5 || true | |
| JS_BUNDLE=$(curl -s http://localhost:3001/ | grep -oP '(?<=src=")[^"]+\.js' | head -1 || true) | |
| if [ -n "$JS_BUNDLE" ]; then | |
| curl -s "http://localhost:3001/${JS_BUNDLE}" | grep -c "localhost:8000" && echo "WARNING: hardcoded localhost:8000 found in bundle" || echo "OK: no hardcoded localhost:8000 in bundle" | |
| fi | |
| echo "=== Nginx config ===" | |
| docker compose -f docker-compose.test.yml exec -T frontend cat /etc/nginx/conf.d/default.conf || true | |
| - name: Verify login endpoint | |
| run: | | |
| echo "=== Testing login via nginx proxy ===" | |
| LOGIN_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST http://localhost:3001/api/v1/auth/login \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"email":"admin@test.com","password":"password123"}') | |
| HTTP_CODE=$(echo "$LOGIN_RESPONSE" | tail -1) | |
| BODY=$(echo "$LOGIN_RESPONSE" | head -n -1) | |
| echo "HTTP Status: $HTTP_CODE" | |
| echo "Response: $BODY" | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "ERROR: Login failed with status $HTTP_CODE" | |
| echo "=== Dumping backend logs for diagnosis ===" | |
| docker compose -f docker-compose.test.yml logs backend 2>&1 | tail -100 | |
| exit 1 | |
| fi | |
| echo "Login endpoint verified successfully" | |
| - name: Dump backend container logs | |
| if: always() | |
| run: | | |
| echo "=== Backend container logs ===" | |
| docker compose -f docker-compose.test.yml logs backend 2>&1 | tail -100 | |
| - name: Verify Playwright environment | |
| run: | | |
| echo "PLAYWRIGHT_BASE_URL=http://localhost:3001" | |
| echo "PLAYWRIGHT_API_URL=http://localhost:8001" | |
| echo "E2E_ADMIN_EMAIL=admin@test.com" | |
| - name: Run Playwright tests | |
| working-directory: frontend | |
| env: | |
| PLAYWRIGHT_BASE_URL: http://localhost:3001 | |
| PLAYWRIGHT_API_URL: http://localhost:8001 | |
| E2E_ADMIN_EMAIL: admin@test.com | |
| E2E_ADMIN_PASSWORD: password123 | |
| CI: true | |
| run: npx playwright test --project=chromium | |
| - name: Upload Playwright HTML report on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: playwright-report | |
| path: frontend/playwright-report/ | |
| retention-days: 7 | |
| - name: Upload screenshots on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: playwright-screenshots | |
| path: frontend/test-results/ | |
| retention-days: 7 | |
| - name: Dump container logs (always) | |
| if: always() | |
| run: | | |
| echo "===== DB logs =====" | |
| docker compose -f docker-compose.test.yml logs db || true | |
| echo "===== Backend logs =====" | |
| docker compose -f docker-compose.test.yml logs backend || true | |
| echo "===== Frontend logs =====" | |
| docker compose -f docker-compose.test.yml logs frontend || true | |
| - name: Upload container logs on failure | |
| if: failure() | |
| run: | | |
| mkdir -p /tmp/container-logs | |
| docker compose -f docker-compose.test.yml logs db > /tmp/container-logs/db.log 2>&1 || true | |
| docker compose -f docker-compose.test.yml logs backend > /tmp/container-logs/backend.log 2>&1 || true | |
| docker compose -f docker-compose.test.yml logs frontend > /tmp/container-logs/frontend.log 2>&1 || true | |
| - name: Upload container logs artifact | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: container-logs | |
| path: /tmp/container-logs/ | |
| retention-days: 7 | |
| - name: Tear down test environment | |
| if: always() | |
| run: docker compose -f docker-compose.test.yml down -v --remove-orphans || true |