Skip to content

Implement external-results case endpoints with test-case auto-upsert, transition enforcement, and traceability linking #280

Implement external-results case endpoints with test-case auto-upsert, transition enforcement, and traceability linking

Implement external-results case endpoints with test-case auto-upsert, transition enforcement, and traceability linking #280

Workflow file for this run

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