name: CI on: push: branches: [master] pull_request: workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: checks: name: Lint, typecheck, unit tests, build runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: # Node 24 is the toolchain this project is developed on. package.json # requires 20 or newer. node-version: 24 cache: npm - name: Install run: npm ci - name: Lint run: npm run lint - name: Typecheck run: npm run typecheck - name: Unit tests run: npm test # No environment variables are needed: the app has no external origins # to allow, so the same build runs everywhere. - name: Production build run: npm run build e2e: name: End-to-end (Playwright) runs-on: ubuntu-latest timeout-minutes: 40 steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: 24 cache: npm - name: Install run: npm ci - name: Install browsers run: npx playwright install --with-deps chromium firefox webkit # playwright.config.ts starts `npm run dev` itself. The camera specs need # Chromium's fake media device flags, and the firefox/webkit projects run # crossbrowser.spec.ts only. - name: Run Playwright run: npx playwright test - name: Upload the report on failure if: failure() uses: actions/upload-artifact@v7 with: name: playwright-report # The `line` reporter used in CI writes no HTML report, so the failure # evidence is the trace, the error context, and the screenshots under # test-results. path: | playwright-report test-results if-no-files-found: ignore retention-days: 7