internkim

Testing

Three kinds of test, one rule for when each runs, and the command that runs them.

Every change is checked by three kinds of test. Each answers one question, so a new test belongs to exactly one of them.

KindQuestionWhere it lives
UnitIs the logic right?web/tests/unit/, Go _test.go files beside their source, .dependency/internkim-plugin/tests/
APIDoes a route answer correctly against a real database, and refuse what it must?web/tests/api/
UICan a person finish the job on screen?web/tests/e2e/<area>/

The agent loop is unit tested too. Its scenarios replace the model with a script, so they decide the same way every run and finish in seconds.

Where a new test goes

Logic that can be called as a function is a unit test. When the logic sits inside a Svelte component, move it into a function first and test that.

A route, a tool or a permission is an API test. API tests sign in as a seeded member and call the route the way the browser would, so row level security is checked by the same call that checks the answer.

A screen is a UI test in the directory named after its route, such as web/tests/e2e/crm/ for /crm. Screens that belong to no single route, like the navigation rail or the workspace loading states, live in web/tests/e2e/shell/. Cover the states a person actually meets: loading, empty, an error, a missing permission and a phone-width screen.

The file name says which plane the screen runs against:

Name ends inThe app talks toUse it when
-central.spec.tsthe local Supabase stack, reset to supabase/seed.dev.sqlthe screen reads or writes the record
-fixture.spec.tsan address the test answers itself with page.routethe test must hold a response back or shape it exactly
-mocked.spec.tsthe dev server's sample data (VITE_MOCK_*)the screen is host-backed and the sample data is enough
.spec.tsno central planethe screen works without one, like the messenger against a stubbed relay

A test that changes company state puts it back in afterAll, because every -central spec shares one database.

Tests that read source files to keep two copies of one fact in step, or to hold a repository-wide rule, are guards. They live in web/tests/conventions/ and run with the unit tests.

When each runs

tools/verify reads what a change touches and runs what it can break:

  • Unit and API tests run in full for any change to the code they cover.
  • UI tests run for the areas a change touches. A change under web/src/routes/crm/, web/src/lib/crm/ or web/tests/e2e/crm/ runs web/tests/e2e/crm/. A change to anything shared, such as a component, a stylesheet or the layout, runs every area. A migration or the seed reaches only the specs on the local plane, so it runs every -central spec.

tools/verify --plan prints what a change would run without running it, and tools/verify --all runs everything.

A group that keeps every core busy, such as a Go test run, the web suite or the UI tests, holds one of a few slots shared by every tools/verify on the machine: one for each six cores. When several checkouts verify at once, those groups queue for a slot and print wait, so one run's load never becomes another's timeout.

A group that passed is not run again while the files its patterns select, the submodule commits, the tools and the commands are all the same. The record is kept for the whole machine, so a fresh clone, or a rebase that left a group's files alone, prints same for that group and moves on. A failure is never kept, and --all or --only runs what they name afresh. This makes a group's patterns a promise: they name every file the group reads.

Running them yourself

cd web
bun run test                       # unit and conventions
bun run test:api                   # API, against the local plane reset to this checkout
bun run test:e2e                   # every UI test
bun run test:e2e tests/e2e/crm     # one area
go test ./...                      # Go, from the repository root
.dependency/internkim-plugin/tests/run

The API and -central UI tests take the local plane with tools/with-local-plane, which starts it if it is stopped and makes a second checkout wait its turn.

Model evaluations

Tests that ask a real model are evaluations. They measure quality, cost money, and run before a release, so no change waits on them to merge. They build only with the llmeval tag. Building with the tag is the request to run them, so a missing key or server fails instead of skipping. Name the evaluation with -run:

monkeys run @test go test -tags llmeval -run OpenRouterLive ./internal/llmbackend

On this page