name: Unit Tests on: pull_request: push: branches: - main - master - develop jobs: skip-budget: name: Skipped-test budget runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Check skip budget run: node scripts/check-skip-budget.mjs unit-tests: name: Nx affected unit tests runs-on: ubuntu-latest # A microtask-spinning test starves vitest's own timeout timer entirely # (see billing's RenewalAutomationSettings hang), so the job needs its own # backstop instead of the 6h default. timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@v4 with: # Required for `nx affected --base/--head` on PRs; shallow clones can miss the base SHA. fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Cache Nx computation cache uses: actions/cache@v4 with: path: .nx/cache key: nx-cache-${{ runner.os }}-${{ hashFiles('package-lock.json', 'nx.json', 'tsconfig.base.json', '**/project.json') }} restore-keys: | nx-cache-${{ runner.os }}- - name: Upgrade npm to version 11 run: npm install -g npm@11 # No npm install fallback: a failing npm ci means the lockfile is out of # sync with a package.json, and regenerating dependencies on the fly once # swapped vitest 3→4 and silently broke test-file serialization. Fail # loudly instead. - name: Install dependencies run: npm ci - name: Determine Nx base/head shell: bash run: | if [ "${{ github.event_name }}" = "pull_request" ]; then echo "NX_BASE=${{ github.event.pull_request.base.sha }}" >> $GITHUB_ENV echo "NX_HEAD=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV else echo "NX_BASE=${{ github.event.before }}" >> $GITHUB_ENV echo "NX_HEAD=${{ github.sha }}" >> $GITHUB_ENV fi # Same two-pass split as typecheck.yml: the server app's vitest config inlines # next/next-auth and needs most of the runner's memory to itself, so libraries # run in parallel first and the heavy apps run serially afterwards (libraries # are instant Nx cache hits in pass 2). # temporal-workflows' suite needs live Postgres/Redis/Temporal (49 of its # 71 tests fail without them) and its clients reconnect forever, so the # vitest process never exits and hangs the job. It has no place in a # unit-test gate until its tests stub their connections. # Non-blocking until the runner layer is repaired: the @nx/vite:test # executor is broken under vitest 4 (fails even fully-green suites, and # reports "Unable to load test config from config file undefined" for # the ~20 projects with no vitest.config), so a red step here measures # the executor, not the tests. Past green runs were Nx cache replays. # Restore blocking once the executor is fixed and a real failure # baseline exists. - name: Nx affected tests (libraries, parallel) continue-on-error: true run: npx nx affected -t test --base=$NX_BASE --head=$NX_HEAD --output-style=static --parallel=3 --exclude=server,sebastian-ee,temporal-workflows env: NX_DAEMON: 'false' NODE_OPTIONS: '--max-old-space-size=4096' # Fixed shuffle seed so order-dependent failures are reproducible across reruns. VITEST_SEED: '20260610' # sebastian-ee's inferred test target is a bare `vitest` over its full # 209-file suite (~50 minutes serial — far past this job's 30-minute # backstop, which it blew via WorkflowAiSchemaSection's render-loop hang # before that was fixed). Excluded until the suite gets a bounded # unit-test target that fits a PR gate. - name: Nx affected tests (apps, isolated & serial) continue-on-error: true run: npx nx affected -t test --base=$NX_BASE --head=$NX_HEAD --output-style=static --parallel=1 --exclude=temporal-workflows,sebastian-ee env: NX_DAEMON: 'false' NODE_OPTIONS: '--max-old-space-size=14336' VITEST_SEED: '20260610' # Informational coverage report for the server unit suite. Push-to-main only # (it re-runs the whole suite with instrumentation, too slow for every PR) and # non-blocking while baselines are established. coverage-report: name: Server unit coverage (informational) if: github.event_name == 'push' runs-on: ubuntu-latest continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Upgrade npm to version 11 run: npm install -g npm@11 - name: Install dependencies run: npm ci - name: Run server unit tests with coverage working-directory: ./server run: npx vitest run src/test/unit src/test/infrastructure --coverage.enabled=true --coverage.reporter=text-summary --coverage.reporter=lcov env: NODE_OPTIONS: '--max-old-space-size=14336' VITEST_SEED: '20260610' - name: Upload lcov artifact uses: actions/upload-artifact@v4 with: name: server-unit-coverage path: server/coverage/lcov.info retention-days: 30