The repository uses Vitest with Cloudflare’s Workers pool. Tests execute the Worker in workerd and use local test bindings for D1, assets, and TokenManager.
Install and run
npm ci
npm test| Command | Scope |
|---|---|
npm test | Every tests/**/*.test.ts file |
npm run test:unit | tests/unit |
npm run test:integration | tests/integration |
npm run test:watch | Vitest watch mode |
Run one file:
npm test -- tests/integration/vote-flow.test.tsRun tests matching a name:
npm test -- -t "should reject second vote attempt with same token"The source snapshot at 2451aa1 contains 11 unit-test files and 24 integration-test files. The project does not define a coverage command or threshold.
Test runtime
vitest.config.ts defines:
| Setting | Value |
|---|---|
| Pool | @cloudflare/vitest-pool-workers |
| Worker entry | src/index.ts |
| Wrangler config | wrangler.test.jsonc |
| Include | tests/**/*.test.ts |
| Timeout | 30 seconds |
| Setup | tests/setup.ts |
wrangler.test.jsonc binds a local D1 database and the production TokenManager class. It supplies test values for RESEND_API_KEY, FROM_EMAIL, BASE_URL, and ADMIN_API_KEY.
Test layers
Unit tests call focused helpers such as ballot validation, result calculation, token hashing, email parsing, and Notion allowlist parsing.
Integration tests use SELF.fetch from cloudflare:test to exercise the mounted Hono application:
import { SELF, env } from "cloudflare:test";
const response = await SELF.fetch(
`http://localhost/e/${election.id}/vote`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token, choice: "YES" }),
},
);Fixtures in tests/helpers/fixtures.ts create elections, tokens, ballots, poll options, invitations, and magic links directly in the test D1 binding.
External calls
Tests that exercise Resend or Notion replace global.fetch with a Vitest mock. tests/helpers/notion-mocks.ts builds Notion page, database, search, and response fixtures.
Email unit tests can also pass an injected sender function to the exported email helpers. No test should contact the live Resend or Notion APIs.
Reset or restore a global mock in the owning test file so it cannot affect later files.
Database setup
tests/setup.ts creates a consolidated schema with SQL statements in beforeAll. It does not execute the repository’s migration files.
That distinction matters:
- application behavior tests use the schema declared in
tests/setup.ts; - migration safety must be checked separately against
migrations/*.sql; and - a passing application test does not prove the production migration chain reaches the same schema.
The current setup is behind the production migration set. Its elections table does not declare the manual-results fields from migration 014, attachments_json from migration 015, or separate Notion push/pull timestamps from migration 016. Its distribution_lists table also omits updated_at.
Tests that touch those fields can fail with schema errors or avoid the production path unintentionally. Bring tests/setup.ts in sync before treating those areas as fully covered.
Adding a test
Use a unit test when the contract can be exercised without the mounted Worker. Use an integration test for:
- route order and middleware;
- authentication headers;
- D1 and Durable Object behavior;
- cron behavior; or
- an end-to-end invitation or ballot flow.
Prefer existing fixtures over hand-written inserts. For a route test, assert both the response and the resulting D1 state, especially around token use and invitation status.
Known suite gaps
- Used magic links are expected to be rejected by integration tests, but
GET /vote/my-electionsdoes not inspectused_at. - Ranked ballot submission lacks a passing end-to-end route test; the current shared route rejects ranked input during simple-ballot validation.
- The test schema is not generated from migrations 001–016.
- No coverage report quantifies untested branches.
Sources
Verified against ihnyc-rc-vote commit 2451aa1.
package.jsonvitest.config.tswrangler.test.jsonctests/setup.tstests/helpers/fixtures.tstests/helpers/notion-mocks.tstests/unit/tests/integration/