name: E2E

on:
  pull_request:
  push:
    branches: [main]

jobs:
  e2e:
    name: Playwright E2E (chromium + webkit)
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: 'e2e/package.json'

      - name: Install e2e deps
        working-directory: ./e2e
        run: npm install

      - name: Install Playwright browsers
        working-directory: ./e2e
        run: npx playwright install --with-deps chromium webkit

      - name: Bring up the test stack
        working-directory: ./e2e
        run: docker compose -f docker-compose.test.yml up -d --build

      - name: Wait for stack health
        working-directory: ./e2e
        run: |
          for i in $(seq 1 60); do
            if curl -fsS http://localhost:3101/health > /dev/null; then exit 0; fi
            sleep 2
          done
          echo "Stack never became healthy. Dumping logs:"
          docker compose -f docker-compose.test.yml logs
          exit 1

      - name: Run E2E tests
        working-directory: ./e2e
        run: npm run test:e2e -- --project=chromium-desktop

      # 09-mobile is `testIgnore`d on chromium-desktop (it needs hasTouch + a phone viewport), so
      # running only that project left 22 tests — focus traps, touch targets, safe-area insets,
      # viewport reflow, upload-cancel — never executing in CI. On a phone-first event app, where
      # essentially every real guest is on a phone, that was the wrong half of the suite to skip.
      - name: Run E2E tests (mobile)
        working-directory: ./e2e
        run: npm run test:e2e -- --project=chromium-mobile

      # iOS Safari is the app's stated primary user (a wedding guest opening a QR link), and
      # WebKit is the ONLY engine here that reproduces two of its behaviours:
      #   - it enforces X-Frame-Options on the download iframe, so a site-wide `DENY` makes the
      #     keepsake download silently do nothing. Blink hands attachments to the download
      #     manager first and never notices. That shipped once already.
      #   - it abandons a <video> load without a 206 response to its Range probe.
      # Both regressions are invisible to every Chromium project, so running WebKit is what
      # actually gates them on a PR rather than on someone remembering to test locally.
      #
      # The project is scoped in playwright.config.ts to the journeys a guest walks
      # (01-auth, 02-upload, 03-feed, 06-export); four IndexedDB-blob tests skip themselves
      # there — see helpers/webkit.ts for why that is the harness and not the app.
      - name: Run E2E tests (webkit / iOS)
        working-directory: ./e2e
        run: npm run test:e2e -- --project=webkit-iphone

      - name: Upload Playwright report
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: e2e/playwright-report/
          retention-days: 14

      - name: Upload traces
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: traces
          path: e2e/test-results/
          retention-days: 14

      - name: Tear down stack
        if: always()
        working-directory: ./e2e
        run: docker compose -f docker-compose.test.yml down -v

  smoke-ua-matrix:
    name: Cross-UA smoke matrix
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install e2e deps
        working-directory: ./e2e
        run: npm install
      - name: Install Playwright browsers (full)
        working-directory: ./e2e
        run: npx playwright install --with-deps chromium firefox webkit
      - name: Bring up the test stack
        working-directory: ./e2e
        run: docker compose -f docker-compose.test.yml up -d --build
      - name: Wait for stack health
        working-directory: ./e2e
        run: |
          for i in $(seq 1 60); do
            if curl -fsS http://localhost:3101/health > /dev/null; then exit 0; fi
            sleep 2
          done
          docker compose -f docker-compose.test.yml logs
          exit 1
      - name: Smoke matrix
        working-directory: ./e2e
        run: npm run test:e2e:smoke
      - name: Upload smoke report
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-smoke-report
          path: e2e/playwright-report/
          retention-days: 14
      - name: Tear down
        if: always()
        working-directory: ./e2e
        run: docker compose -f docker-compose.test.yml down -v
