testing-guide
4
总安装量
2
周安装量
#49178
全站排名
安装命令
npx skills add https://github.com/clarkkkk/seagull --skill testing-guide
Agent 安装分布
windsurf
2
opencode
2
cursor
2
antigravity
2
Skill 文档
Seagull Testing Guide
Quick start (default approach)
When implementing a feature that touches backend/frontend:
-
Classify behavior:
- service semantics (pure rules): put tests near the service
- cross-layer behavior (tRPC + react-query + cache invalidation + timers): use
packages/test-integration - deployment-shape behavior (real Postgres + pooling + true concurrency): run strict smoke tests pre-release
-
Prefer real integrations over hook mocks:
- Do not mock
useMutationwhen the goal is react-query/tRPC integration. - Only mock/alias platform-only deps (Expo/RN modules that break node/jsdom).
- Do not mock
-
Use header-injected identity for multi-user tests:
- Client: set
httpBatchLink({ headers: () => ({ 'x-test-user-id': userId }) }) - Server: in
createContext({ headers }), readheaders.get('x-test-user-id')
- Client: set
-
Test DB schema is schema-driven (no hand-written DDL):
packages/test-integration/src/db/pglite.tsapplies a generatedpackages/test-integration/src/db/schema.sql(single file)- Generate it from current Drizzle schema before running tests:
pnpm -F @acme/test-integration db:schema
pnpm -F @acme/test-integration testshould rundb:schemafirst (so forgetting to regenerate only breaks tests, not production).- PGlite compatibility: we polyfill
gen_random_uuid()used by Drizzle schema/DDL. - This prevents schema drift and avoids migration ordering/duplication issues in tests.
Where tests live
- Cross-layer:
packages/test-integration/src/**- in-memory tRPC fetch:
packages/test-integration/src/trpc/inMemoryFetch.ts - PGlite DB harness:
packages/test-integration/src/db/pglite.ts - Test schema SQL (generated):
packages/test-integration/src/db/schema.sql - Generator script:
packages/test-integration/scripts/generate-schema-sql.mjs - example tests:
- expiry:
packages/test-integration/src/trpc/tripLock.expiry.test.ts - concurrency smoke:
packages/test-integration/src/trpc/tripLock.concurrent.test.ts
- expiry:
- Expo business examples:
- trip/edit:
packages/test-integration/src/expo/trip/edit/** - wishlist:
packages/test-integration/src/expo/wishlist/**
- trip/edit:
- in-memory tRPC fetch:
- Backend package tests:
packages/api/src/**/*.test.ts
How to run
pnpm test
pnpm -F @acme/test-integration test
pnpm -F @acme/test-integration typecheck
pnpm -F @acme/api test
pnpm -F @acme/api typecheck
When DB schema changes
After changing packages/db/src/schema.ts (or schema modules), regenerate test schema SQL so PGlite tests stay in sync:
pnpm -F @acme/test-integration db:schema
Test case style rules
- One behavior per test: a test name should read like a requirement.
- Assert the contract:
- success payload shape
- error code (
CONFLICT,UNAUTHORIZED, etc.) - cache behavior (invalidate/refetch) where relevant
- Avoid flakiness:
- prefer deterministic triggers over âsleepâ
- if time is essential, isolate it (DB state manipulation or controlled timers)
FK/seed policy (important after migrations reuse)
- PGlite applies real FK/unique constraints from Drizzle migrations.
- If you insert rows directly, seed required parents first (notably
"user"). - Prefer seed helpers in
packages/test-integration/src/trpc/api/seed.ts:seedUser/seedTrip/seedWishlistJar/...(helpers ensure required parents exist).
- For router/hook tests that use
createApiTestServer(), authenticated requests (via header or cookiex-test-user-id) will auto-upsert"user"to keep tests concise.
Concurrency policy (locks/idempotency)
Implementation guidance
For lock acquisition, prefer DB-atomic statements (e.g. onConflictDoUpdate + where + returning) so correctness does not depend on JS scheduling.
Testing guidance
Use two stages:
- CI/PR smoke (fast): multi-user
Promise.allSettledconcurrency test verifying:- exactly one success, rest
CONFLICT - no raw DB errors leak to the client
- exactly one success, rest
- Pre-release strict smoke: run the same scenario against real Postgres to cover pooling/isolation/scheduler differences.
Definition of Done (mandatory coverage)
When a feature is âdoneâ, tests must cover all necessary scenarios (not âat least one testâ).
Backend (packages/api)
- Service rules: cover all branches and boundary cases (expiry edges, ownership checks, conflict mapping, empty-return defenses).
- tRPC route changes: cover:
- happy path
- key failure path(s) with correct error codes/shape
- at least one invalid input path
Frontend (Expo business layer)
- Effects/polling/side effects: cover:
- trigger conditions and call counts
- success and failure behavior (invalidate/refetch, error handling)
- cleanup (intervals/subscriptions released)
Cross-layer (default required)
- Any feature that touches backend interaction (query/mutation/errors/cache/timers/concurrency) must add
packages/test-integrationtests covering all necessary scenarios.
Reference
For the full written guide, see docs/testing.md.