Skip to content
Nautilo Documentation
Build on NautiloDevelopment

Test a source change

Run focused checks, protect the retained default database, and finish with product-level acceptance when the change needs it.

Match the proof to the change. A focused unit test is the fast loop. A real database path belongs on the disposable scratch instance. A user-visible change is not finished until it runs through a claimed Server and the actual client surface.

Start narrow

Run the smallest test or package suite that exercises the changed behavior, then widen the proof:

bun test <path-to-focused-test>
bun run --cwd <workspace> test:unit
bun run --cwd <workspace> typecheck
bun run --cwd <workspace> lint

For a repository-wide confidence pass:

bun run test:unit
bun run typecheck
bun run lint

The root scripts use Turbo to run their matching workspace tasks. Full integration coverage is intentionally heavier and serialized:

bun run test:integration

The Server integration runner executes each test file in its own Bun process to prevent process-global mocks, app instances, and environment changes from leaking across files.

Keep fixture writes away from default

Database-backed tests use the disposable instance ID test-cruft when their package preload or fixture bootstrap runs. The shared guard refuses fixture writes to (default) unless someone explicitly bypasses it or the process identifies itself as CI. CI is treated as ephemeral; do not use a CI flag to make a developer workstation's retained database look disposable.

Do not normalize the bypass

Do not set ALLOW_DEFAULT_DB_TESTS=1 in a shell profile, CI environment, or copied test command. It is an escape hatch for a deliberate one-off action, not a development default.

When adding a live-database test, call the package's fixture bootstrap before opening a database connection. Do not assume a package-level bunfig.toml preload will fire when someone runs one test from the repository root.

Recover a contaminated scratch instance

If failures show that test-cruft itself is stale or corrupted, inspect the failure first. Then, only when its deletion is intended, reset it:

bun run dev:reset-test-cruft --yes

That command deletes and recreates the entire test-cruft instance. It is not a cleanup command for default, and it is not a first response to a failing assertion.

Finish at the product boundary

Tests do not replace acceptance when the change crosses Server, Workbench, Electron, authentication, setup, provider routing, or multi-user behavior.

Use one of the paths in Run Nautilo from source. For most isolated product acceptance, clone the claimed default into an absent named instance. Use a genuinely fresh named instance only when blank-server, claim, or first-owner behavior is the thing under test.

Then verify the applicable outcome:

  1. the intended instance—not a neighboring worktree's instance—is running;
  2. setup state is ready;
  3. the known owner can sign in;
  4. the changed UI or API path works through the real client;
  5. a model-backed turn succeeds when model execution is in scope; and
  6. a second profile or client proves identity separation when multi-user state is in scope.

Record the exact instance, command, test path, and observed result in the pull request. “Tests pass” is not enough when the important proof happened in a specific retained environment.

Database changes need a second decision

Before applying a new migration to retained data, use the database migration safety decision tree. A clean Git merge and a green unit suite do not prove that two migration histories can be safely replayed against the same database.