name: E2E Tests on: push: branches: [master] pull_request: branches: [master] concurrency: group: e2e-${{ github.ref }} cancel-in-progress: true jobs: e2e: name: Playwright E2E runs-on: ubuntu-latest timeout-minutes: 20 services: postgres: image: postgis/postgis:16-3.4 env: POSTGRES_DB: goodgo_test POSTGRES_USER: goodgo POSTGRES_PASSWORD: goodgo_test_secret ports: - 5432:5432 options: >- --health-cmd "pg_isready -U goodgo -d goodgo_test" --health-interval 10s --health-timeout 5s --health-retries 5 --health-start-period 30s redis: image: redis:7-alpine ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 typesense: image: typesense/typesense:27.1 ports: - 8108:8108 env: TYPESENSE_API_KEY: ts_ci_key TYPESENSE_DATA_DIR: /data options: >- --health-cmd "curl -sf http://localhost:8108/health || exit 1" --health-interval 10s --health-timeout 5s --health-retries 5 minio: image: minio/minio:latest ports: - 9000:9000 env: MINIO_ROOT_USER: ${{ vars.CI_MINIO_ACCESS_KEY || 'ci_minio_user' }} MINIO_ROOT_PASSWORD: ${{ vars.CI_MINIO_SECRET_KEY || 'ci_minio_secret_key_32chars!!' }} options: >- --health-cmd "curl -sf http://localhost:9000/minio/health/live || exit 1" --health-interval 10s --health-timeout 5s --health-retries 5 env: DATABASE_URL: postgresql://goodgo:goodgo_test_secret@localhost:5432/goodgo_test REDIS_URL: redis://localhost:6379 REDIS_HOST: localhost REDIS_PORT: 6379 TYPESENSE_URL: http://localhost:8108 TYPESENSE_HOST: localhost TYPESENSE_PORT: 8108 TYPESENSE_PROTOCOL: http TYPESENSE_API_KEY: ts_ci_key MINIO_ENDPOINT: localhost MINIO_PORT: 9000 MINIO_ACCESS_KEY: ${{ vars.CI_MINIO_ACCESS_KEY || 'ci_minio_user' }} MINIO_SECRET_KEY: ${{ vars.CI_MINIO_SECRET_KEY || 'ci_minio_secret_key_32chars!!' }} MINIO_BUCKET: goodgo-uploads NODE_ENV: test CI: true # API and Web ports for Playwright webServer API_PORT: 3001 WEB_PORT: 3000 API_BASE_URL: http://localhost:3001/api/v1/ WEB_BASE_URL: http://localhost:3000 NEXT_PUBLIC_API_URL: http://localhost:3001/api/v1 JWT_SECRET: e2e-test-jwt-secret-key-minimum-32-chars-long-enough JWT_REFRESH_SECRET: e2e-test-refresh-secret-key-minimum-32-chars-ok JWT_EXPIRES_IN: 15m JWT_REFRESH_EXPIRES_IN: 7d BCRYPT_ROUNDS: 4 VNPAY_TMN_CODE: TESTCODE VNPAY_HASH_SECRET: TESTHASHSECRETTESTHASHSECRETTEST VNPAY_URL: https://sandbox.vnpayment.vn/paymentv2/vpcpay.html VNPAY_RETURN_URL: http://localhost:3000/payment/return GOOGLE_CLIENT_ID: test-google-client-id GOOGLE_CLIENT_SECRET: test-google-client-secret GOOGLE_CALLBACK_URL: http://localhost:3001/api/v1/auth/google/callback ZALO_APP_ID: test-zalo-app-id ZALO_APP_SECRET: test-zalo-app-secret ZALO_CALLBACK_URL: http://localhost:3001/api/v1/auth/zalo/callback steps: - name: Checkout uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' run: npx playwright install --with-deps chromium - name: Install Playwright system deps if: steps.playwright-cache.outputs.cache-hit == 'true' run: npx playwright install-deps chromium - name: Generate Prisma client run: pnpm db:generate - name: Run database migrations run: pnpm db:migrate:deploy - name: Seed database run: pnpm db:seed - name: Run E2E tests run: pnpm test:e2e - name: Upload Playwright report if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: playwright-report path: playwright-report/ retention-days: 14 - name: Upload Playwright traces if: failure() uses: actions/upload-artifact@v4 with: name: playwright-traces path: test-results/ retention-days: 7