Skip to content

E2E Tests

E2E Tests #137

Workflow file for this run

name: E2E Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
# Cancel in-progress runs for the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Single consolidated job that runs all tests with sharding
e2e-tests:
name: E2E Tests (Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3]
shardTotal: [3]
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: test123
MYSQL_DATABASE: wegent_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd="redis-cli ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- name: Checkout code
uses: actions/checkout@v4
# Cache Python packages
- name: Cache Python packages
uses: actions/cache@v4
with:
path: |
~/.cache/uv
backend/.venv
shared/.venv
key: ${{ runner.os }}-python-${{ hashFiles('backend/pyproject.toml', 'shared/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-python-
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install uv
run: pip install uv
# Install dependencies in parallel
- name: Install shared module
working-directory: ./shared
run: |
uv venv --allow-existing
source .venv/bin/activate
uv pip install -e .
- name: Install backend dependencies
working-directory: ./backend
run: |
uv sync
source .venv/bin/activate
uv pip install -e ../shared
- name: Install frontend dependencies
working-directory: ./frontend
run: npm ci
# Cache Next.js build
- name: Cache Next.js build
uses: actions/cache@v4
with:
path: |
./frontend/.next/cache
key: ${{ runner.os }}-nextjs-e2e-${{ hashFiles('./frontend/package-lock.json') }}-${{ hashFiles('./frontend/src/**/*.[jt]s', './frontend/src/**/*.[jt]sx') }}
restore-keys: |
${{ runner.os }}-nextjs-e2e-${{ hashFiles('./frontend/package-lock.json') }}-
${{ runner.os }}-nextjs-e2e-
# Cache Playwright browsers
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('frontend/package-lock.json') }}
- name: Install Playwright browsers
working-directory: ./frontend
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install --with-deps chromium
- name: Install Playwright dependencies (cached)
working-directory: ./frontend
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps chromium
- name: Run database migrations
working-directory: ./backend
env:
DATABASE_URL: mysql+pymysql://root:test123@localhost:3306/wegent_test
run: |
source .venv/bin/activate
alembic upgrade head
- name: Start backend server
working-directory: ./backend
env:
DATABASE_URL: mysql+pymysql://root:test123@localhost:3306/wegent_test
REDIS_URL: redis://localhost:6379/0
SECRET_KEY: test-secret-key-for-ci-testing
ALGORITHM: HS256
ENVIRONMENT: development
DB_AUTO_MIGRATE: "false"
INIT_DATA_ENABLED: "true"
run: |
source .venv/bin/activate
nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > backend.log 2>&1 &
echo $! > backend.pid
- name: Build frontend
working-directory: ./frontend
env:
NEXT_PUBLIC_API_URL: http://localhost:8000
NEXT_TELEMETRY_DISABLED: 1
run: npm run build
- name: Start frontend server
working-directory: ./frontend
env:
RUNTIME_INTERNAL_API_URL: http://localhost:8000
RUNTIME_SOCKET_DIRECT_URL: http://localhost:8000
run: |
npm start &
- name: Start Mock Model Server
working-directory: ./frontend
run: |
npx tsx e2e/utils/mock-model-server.ts &
echo $! > mock-server.pid
- name: Wait for services
run: |
npx wait-on http://localhost:8000/api/docs http://localhost:3000 --timeout 90000
- name: Verify backend is running
run: |
curl -f http://localhost:8000/api/docs > /dev/null 2>&1 || (cat backend/backend.log && exit 1)
- name: Run E2E tests (Sharded)
working-directory: ./frontend
env:
E2E_BASE_URL: http://localhost:3000
E2E_API_URL: http://localhost:8000
MOCK_MODEL_SERVER_URL: http://localhost:9999
CI: true
run: |
npx playwright test --project=chromium --project=api \
--shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Stop Mock Model Server
if: always()
working-directory: ./frontend
run: |
if [ -f mock-server.pid ]; then
kill $(cat mock-server.pid) 2>/dev/null || true
rm mock-server.pid
fi
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: frontend/blob-report/
retention-days: 14
- name: Upload test traces
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-traces-${{ matrix.shardIndex }}
path: frontend/test-results/
retention-days: 7
- name: Upload backend logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: backend-logs-${{ matrix.shardIndex }}
path: backend/backend.log
retention-days: 7
# Merge test reports from all shards
merge-reports:
name: Merge Test Reports
needs: e2e-tests
if: always()
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Download all blob reports
uses: actions/download-artifact@v4
with:
pattern: blob-report-*
path: all-blob-reports
merge-multiple: true
- name: Install frontend dependencies
working-directory: ./frontend
run: npm ci
- name: Merge reports
working-directory: ./frontend
run: npx playwright merge-reports --reporter html ../all-blob-reports
- name: Upload merged report
uses: actions/upload-artifact@v4
with:
name: playwright-report-merged
path: frontend/playwright-report/
retention-days: 30