Testing
This page covers running the test suite, the two kinds of test, and the gaps.
Running the tests
Section titled “Running the tests”pnpm test # every workspace with a test scriptpnpm --filter app test # the app only (vitest run)pnpm --filter app test src/graph # files whose path matchesThe root pnpm test runs pnpm -r --if-present test. That covers two workspaces:
| Workspace | Runner | Files |
|---|---|---|
apps/app |
Vitest (vitest run), using apps/app/vite.config.ts |
46 |
packages/bluesky_to_graph |
Node’s test runner (tsx --test src/*.test.ts) |
2 |
There is no separate Vitest config. vite.config.ts loads the root .env into
process.env, so the integration tests get VITE_SUPABASE_URL,
VITE_SUPABASE_PUBLISHABLE_KEY and SUPABASE_SECRET_KEY without ./scripts/supa.
Running them through ./scripts/supa pnpm test also works.
Test files sit next to the code they test, named *.test.ts (or *.test.tsx for one
that renders JSX).
Unit tests
Section titled “Unit tests”39 files in apps/app test pure functions with no database. The main groups:
- graph algorithms:
graph/(betweenness, communities, weight modes, connection rules, and the progressive reveal’s worked example inmodes.test.ts) - import and export parsing:
server/lib/map-io/(CSV, GraphML, internal JSON, the/changespayload, the upsert plan) - visualiser helpers:
components/map-visualiser/lib/(appearance, including Bridges sizing; force adapter; node painting, including selection emphasis; PNG export; saved-view naming; config; force parameters; the “What you’re looking at” sentences indescribe-view.test.ts), and the raw view parameters panel (raw-view-parameters.test.tsx) - editor and table helpers:
components/map-editor/(including the editor’s description,describe-canvas.test.ts),components/map-table/lib/ - the About this map panel:
components/map-workspace/about/(sentence helpers, panel height, and recipe markdown, rendered to a string withrenderToStaticMarkup) - the recipe:
server/lib/map-recipe.test.ts(planRecipeSave, and the split between data and layout event types) - shared helpers:
lib/(connection dates, CSV conventions, value formatting, the view parameters schema) - public API request parsing and key hashing:
server/api/v1/request.test.ts,server/lib/api-key-crypto.test.ts
server/lib/pagination.test.ts uses a real supabase-js client with a stubbed fetch, so
it checks the PostgREST requests fetchAllRows sends without a network call.
Integration tests
Section titled “Integration tests”Nine files named *.integration.test.ts run against the shared dev Supabase project. They
create real users with the service-role client, sign them in with the publishable key, and
create orgs, maps and data. Each run tags its rows with a runId timestamp and deletes them
in afterAll. A run that crashes can leave rows behind.
There is no per-branch database. Two people running the suite at once share the same project, and a migration you haven’t pushed isn’t there (see Development environment).
| File | Covers |
|---|---|
server/lib/authz.integration.test.ts |
The RLS helpers and app-schema policies: membership, roles, the roster, invitations, public and private maps. |
server/functions/manual-editing.integration.test.ts |
The network RPCs, composite FKs, catalogue rules and map scoping, RLS between orgs, the getGraph and unplaced-node query shapes, change capture, property promotion and connection dates. |
server/functions/tag-groups.integration.test.ts |
Moving tags into and out of groups: a clash is refused, naming the nodes, and changes nothing; a deleted group keeps its tags; group names are unique; tag icons and colours reach the browser and survive a duplicate. |
server/lib/map-io/map-io.integration.test.ts |
Export loading and import for internal JSON, GraphML and CSV bundles, including field mapping, value columns and dates. |
server/api/v1/auth.integration.test.ts |
API key to org resolution: bad keys, cross-org maps, soft-deleted orgs, removed members, key hash access. |
server/api/v1/v1.integration.test.ts |
The public API’s GraphML export and upsert import through the real handlers. |
server/api/v1/v1-1.integration.test.ts |
The public API’s maps, fields, /changes and create_fields endpoints. |
server/api/v1/v1-views.integration.test.ts |
The view endpoints: the CK progressive reveal built from tag names, read back with its descriptions; repeat requests; patch, null and reset; unknown names; a shared name; another map’s view and another org. |
server/api/v1/v1-recipe.integration.test.ts |
The recipe endpoints, and staleness: API writes (including no-ops), value-type changes and editor changes without a session make it stale; layout changes don’t. Also the save conflict check and cross-org access. |
The integration tests call library functions that take a Supabase client (readMapFields,
ingestGraph and similar) or the v1 handlers with real Request objects. They don’t go
through createServerFn.
What isn’t covered
Section titled “What isn’t covered”A createServerFn handler can’t run outside the TanStack Start runtime, because it needs the
request context that holds the cookie-bound client. So no test exercises logic that lives
only inside a handler. That includes:
- the guard that stops
removeMemberorchangeMemberRoleremoving an org’s lastorg_admin acceptInvitation’s branches: already a member, expired, email mismatch- setting
map_idanduser_idon service-role writes
To make handler logic testable, move it into a function that takes a Supabase client and
call that from the handler, as fields.ts and server/lib/map-io/ do.
There are no interactive component tests or end-to-end browser tests.
.github/workflows/ci.yml runs pnpm check, pnpm typecheck and pnpm build on every
pull request and push to main. It doesn’t run the tests. Run pnpm test yourself before
opening a pull request.