Test framework
Tests use Vitest. There are 4 test files, all in lib/. Tests focus on pure business logic — there are no frontend component tests, API route tests, or end-to-end tests.
Running tests
# Run all tests
pnpm test
# Watch mode (re-runs on file changes)
pnpm test:watch
# With v8 coverage (same as CI)
pnpm test:ci
# Unit tests only (lib/, verbose output)
pnpm test:unitTest files
| File | What it tests |
|---|---|
lib/scoring/normalize.test.ts | normalizeGitHubData() — signal production from raw GitHub data, content hash deduplication, co-author splitting, bot detection via [bot] suffix |
lib/scoring/engine.test.ts | computeSignalScore() — per-signal scoring with multipliers, zero-point conditions, diminishing returns, daily quotas |
lib/leaderboard/ingest-freshness.test.ts | evaluateIngestFreshness() — 24h cooldown logic, per-period TTL computation, staleness evaluation |
lib/github/required-permissions.test.ts | findMissingPermissions() — permission-level comparison against REQUIRED_INSTALLATION_PERMISSIONS |
Test files live next to the code they test (e.g. normalize.ts and normalize.test.ts in the same directory).
Test utilities
lib/test/ provides shared test infrastructure:
setup.ts— vitest global test setupsupabase-mock.ts— Supabase admin client mock for tests that need DB stubsoctokit-mock.ts— Octokit mock for tests that simulate GitHub API responsesfixtures/— static test dataserver-only-stub.ts— stub that satisfiesimport 'server-only'in test contextsindex.ts— barrel exportindex.d.ts— type declarations for test utilities
Coverage
pnpm test:ci runs vitest with the v8 coverage provider. The coverage/ directory is generated at the project root. In CI, the coverage artifact is uploaded at the end of the workflow and is accessible from the Actions run summary.
Writing new tests
- Place the test file next to the module it tests:
lib/scoring/myModule.test.ts. - Import test utilities from
lib/test/. - Use standard vitest functions:
describe,it,expect. - Follow the existing pattern — pure function tests with deterministic inputs.
- Run
pnpm test:unitto run onlylib/tests in verbose mode.
What is not tested
- API route handlers — no mock server or integration test framework exists
- React components and hooks — no React testing library is configured
- Supabase queries — no test database or schema migration in CI
- End-to-end flows — no Cypress, Playwright, or browser tests
CI integration
The CI workflow (.github/workflows/ci.yml) runs pnpm test:ci after linting. Tests must pass for the build step to proceed. Coverage artifacts are uploaded regardless of pass/fail (via if: always()).
Pre-commit
The pre-commit hook does not run tests — it only formats staged files with Prettier. Run pnpm test manually before pushing if your change affects tested logic.