Skip to Content
DevelopersOperationsTesting

3 min read

Testing

Terminal
bun run test # all packages, via turbo (unchanged packages are cache hits) bun run affected # typecheck + test for packages changed since origin/main bun run test:coverage bun run test:sweeps # guardrail sweeps — see /developer-docs/core-concepts/guardrails

One vitest project per package/app that has tests.

Testing fast (read this before running the suite)

  • Test what changed. bun run affected runs turbo run typecheck test --filter=...[origin/main]. For one package: bun run turbo:shared run typecheck test --filter=@commerce/core. A change to commerce.config.ts, commerce.blocks.config.ts or a plugin package also affects core and everything above it; run bun run test then (the cache still skips the rest).
  • Cached. test and typecheck are turbo-cached. The hash covers the package, every workspace package it depends on (a new migration re-runs every database suite), .env.test, and the plugin graph for anything built on core. A failed run is never cached.
  • Shared between worktrees. The root scripts set TURBO_CACHE_DIR to the main checkout’s .turbo/cache, so a typecheck or test another worktree already ran is a cache hit. Set TURBO_CACHE_DIR to use a different folder.
  • Parallel files. Database-backed packages run TEST_WORKERS test files at once (default 3, TEST_WORKERS=1 for one at a time). Each worker gets its own copy of the test database, cloned from a migrated template, so files never see each other’s rows.
  • Skip next build unless you changed build config or something only the bundler checks; bun run typecheck covers types.
Terminal
TEST_DB_NAMESPACE=agent7 TEST_WORKERS=2 bun run affected

Details and the reasons behind each piece: docs/guardrails.md, “Testing fast”.

Admin component tests

Admin components are tested with Testing Library  on jsdom. A file named *.test.tsx next to the component starts with // @vitest-environment jsdom; plain *.test.ts files stay on Node. apps/admin/test/dom.ts (a vitest setup file) stubs what jsdom lacks (ResizeObserver, IntersectionObserver, matchMedia, scrollIntoView) and unmounts after each test.

The Customize editor’s panels read the Puck store through useCustomizePuck, so a test mocks that one hook with a small store (dispatch as a vi.fn(), config.components, selectedItem) and asserts the Puck actions dispatched, rather than mounting Puck. Query by role and accessible name from data/customize.ts copy, not by class names. Examples: apps/admin/src/components/themes/customize/{template-list,template-picker,section-tree-item,link-picker,add-section-browser,section-inspector}.test.tsx.

Terminal
cd apps/admin && bunx vitest run src/components/themes/customize/link-picker.test.tsx

Test databases

Tests never run against the dev database. packages/config/src/test-env.ts loads .env.test and points DATABASE_URL/DATABASE_URL_OWNER at commerce_test_<suffix> — a separate database per test package, so suites can run in parallel without stepping on each other.

The test-DB guard. Before running, assertTestDatabase checks the resolved database name against /^commerce_test(_[a-z0-9_]+)?$/ and throws immediately if it doesn’t match. This is what stops a misconfigured .env.test (or an accidentally-loaded .env) from a test suite truncating the real dev or production database — every test run refuses to start unless its target database is unmistakably a test database.

TEST_DB_NAMESPACE

Parallel worktrees share the same Postgres instance, so without namespacing two worktrees’ test runs would both reset commerce_test_<suffix> and stomp on each other mid-run. Set TEST_DB_NAMESPACE (letters, digits, underscores, 1-32 chars) per checkout/worktree, and every package then uses commerce_test_<namespace>_<suffix> instead — created on first use by the global test setup. That database is the migrated template; the workers run on commerce_test_<namespace>_<suffix>_w1, _w2, … copies, cloned once and then migrated with the template on every run. Keep the namespace short enough that the copy names stay within Postgres’s 63 characters (the setup refuses longer ones).

Terminal
TEST_DB_NAMESPACE=agent7 bun run test

This also matters for migrations: parallel worktrees that don’t set distinct namespaces can see migration numbers collide and the __drizzle_migrations log drift between them.

Was this helpful?