diff --git a/docs/README.md b/docs/README.md index 465ba8ab..591c2001 100644 --- a/docs/README.md +++ b/docs/README.md @@ -86,6 +86,7 @@ Pre-flight checks for critical operations: LLM-specific task guides for AI assistants: +- [test-writing.md](skills/test-writing.md) - Decision tree for choosing test types and placement - [testing-local-dev.md](skills/testing-local-dev.md) - Validate Skaffold dev environment (required before Skaffold changes) ## Related Documentation diff --git a/docs/playbooks/backend-test-patterns.md b/docs/playbooks/backend-test-patterns.md index fd4e25ba..451dfc78 100644 --- a/docs/playbooks/backend-test-patterns.md +++ b/docs/playbooks/backend-test-patterns.md @@ -426,8 +426,9 @@ Migrations haven't run. The test framework runs them automatically, but check: ## See Also -- `docs/playbooks/frontend-test-patterns.md` - Frontend testing guide -- `docs/playbooks/adding-migration.md` - Database migration workflow +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement +- [Frontend Test Patterns](./frontend-test-patterns.md) - Frontend testing guide +- [Adding Migration](./adding-migration.md) - Database migration workflow - `service/tests/common/mod.rs` - Test DB infrastructure (`test_transaction`, `isolated_db`) - `service/tests/common/app_builder.rs` - Test Axum app builder - `service/tests/common/graphql.rs` - GraphQL response helpers diff --git a/docs/playbooks/fixing-flaky-tests.md b/docs/playbooks/fixing-flaky-tests.md index 83200c08..38254c42 100644 --- a/docs/playbooks/fixing-flaky-tests.md +++ b/docs/playbooks/fixing-flaky-tests.md @@ -147,6 +147,7 @@ test('sometimes flaky', async ({ page }) => { ## See Also +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement - [Playwright Best Practices](https://playwright.dev/docs/best-practices) -- `docs/playbooks/frontend-test-patterns.md` - General frontend testing +- [Frontend Test Patterns](./frontend-test-patterns.md) - General frontend testing - `web/playwright.config.ts` - Test configuration diff --git a/docs/playbooks/frontend-test-patterns.md b/docs/playbooks/frontend-test-patterns.md index d150a4cf..1674b8aa 100644 --- a/docs/playbooks/frontend-test-patterns.md +++ b/docs/playbooks/frontend-test-patterns.md @@ -142,6 +142,8 @@ Coverage reports uploaded as artifacts. | "Target closed" | Page navigated during test | Wait for navigation to complete | ## See also +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement +- [Backend Test Patterns](./backend-test-patterns.md) - Rust/database testing guide - `web/test-utils/` - Shared test utilities - `web/vitest.setup.mjs` - Test configuration - `web/playwright.config.ts` - E2E configuration diff --git a/docs/playbooks/migration-testing.md b/docs/playbooks/migration-testing.md index 385fe87e..ddf04eeb 100644 --- a/docs/playbooks/migration-testing.md +++ b/docs/playbooks/migration-testing.md @@ -69,7 +69,9 @@ A migration file was deleted after being applied. ## See Also +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement +- [Backend Test Patterns](./backend-test-patterns.md) - Database testing patterns +- [Adding Migration](./adding-migration.md) - How to add new migrations - `service/tests/common/mod.rs` - Test infrastructure documentation - `service/tests/migration_tests.rs` - Migration test implementations - `service/tests/schema_snapshot.rs` - Schema drift detection -- `docs/playbooks/adding-migration.md` - How to add new migrations diff --git a/docs/playbooks/new-graphql-endpoint.md b/docs/playbooks/new-graphql-endpoint.md index 771bb1d2..e3be1c26 100644 --- a/docs/playbooks/new-graphql-endpoint.md +++ b/docs/playbooks/new-graphql-endpoint.md @@ -45,11 +45,17 @@ 5. **Add tests** in `service/tests/`: ```rust - #[tokio::test] + use tc_test_macros::shared_runtime_test; + use common::test_db::test_transaction; + + #[shared_runtime_test] async fn test_my_new_query() { - // Setup and assertions + let mut tx = test_transaction().await; + // Setup and assertions using &mut *tx } ``` + Use `#[shared_runtime_test]` with `test_transaction()` for database tests. + See [Backend Test Patterns](./backend-test-patterns.md) for detailed guidance. 6. **Regenerate TypeScript types**: ```bash @@ -81,4 +87,6 @@ ## See also - `service/src/` - existing resolvers - [GraphQL Codegen Workflow](./graphql-codegen.md) - type generation process +- [Backend Test Patterns](./backend-test-patterns.md) - database and resolver testing +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement - async-graphql docs for patterns diff --git a/docs/playbooks/test-data-factories.md b/docs/playbooks/test-data-factories.md index cab7dbbc..067e2615 100644 --- a/docs/playbooks/test-data-factories.md +++ b/docs/playbooks/test-data-factories.md @@ -141,3 +141,9 @@ impl Default for EntityFactory { 3. **Builder pattern**: Methods return `Self` for fluent chaining 4. **Executor agnostic**: Works with transactions, connections, and pools 5. **Return Result**: Factories return `Result` types, letting callers decide how to handle errors (use `.expect()` for simple cases, `?` for propagation) + +## See Also + +- [Test Writing Skill](../skills/test-writing.md) - LLM decision tree for test placement +- [Backend Test Patterns](./backend-test-patterns.md) - Database testing patterns +- `service/tests/common/factories/` - Existing factory implementations diff --git a/docs/skills/test-writing.md b/docs/skills/test-writing.md new file mode 100644 index 00000000..4a922c1b --- /dev/null +++ b/docs/skills/test-writing.md @@ -0,0 +1,105 @@ +# Test Writing + +Use this skill when writing tests for new code or bug fixes. This guide helps you choose the right test type and location. + +## Decision Tree + +``` +What are you testing? +│ +├─► Backend (Rust code in service/) +│ │ +│ ├─► Database interaction? +│ │ │ +│ │ ├─► Query logic, CRUD, business logic +│ │ │ → Use `test_transaction()` with `#[shared_runtime_test]` +│ │ │ +│ │ └─► Migration, transaction isolation, DB features +│ │ → Use `isolated_db()` with `#[shared_runtime_test]` +│ │ +│ ├─► GraphQL resolver? +│ │ → Test via schema.execute() or full HTTP test +│ │ → See backend-test-patterns.md#graphql-resolver-tests +│ │ +│ ├─► Pure function, no DB? +│ │ → Use `#[test]` or `#[tokio::test]` +│ │ +│ └─► Invariants that should hold for all inputs? +│ → Use proptest for property-based testing +│ +└─► Frontend (TypeScript code in web/) + │ + ├─► Component rendering/interaction? + │ → Vitest test in same directory: `Component.test.tsx` + │ → Use `@test-utils` for render/screen/userEvent + │ + ├─► User flow across pages? + │ → Playwright E2E in `web/tests/` + │ → Use `./fixtures` for shared helpers + │ + └─► Time-dependent behavior? + → Use fake timers (vi.useFakeTimers or page.clock) +``` + +## Quick Reference + +| Scenario | Test Type | Location | Macro/Tool | +|----------|-----------|----------|------------| +| DB query/CRUD | Integration | `service/tests/*_tests.rs` | `#[shared_runtime_test]` + `test_transaction()` | +| Migration testing | Isolated DB | `service/tests/*_tests.rs` | `#[shared_runtime_test]` + `isolated_db()` | +| GraphQL resolver | Integration | `service/tests/graphql_tests.rs` | `#[shared_runtime_test]` or `#[tokio::test]` | +| Pure Rust function | Unit | `service/tests/*_tests.rs` | `#[test]` | +| Async without DB | Unit | `service/tests/*_tests.rs` | `#[tokio::test]` | +| Property/invariant | Property | Same file, `mod proptests` | `proptest!` | +| React component | Unit | `web/src/**/*.test.tsx` | Vitest | +| User flow E2E | E2E | `web/tests/*.spec.ts` | Playwright | + +## Backend: Which Database Pattern? + +**95% of tests:** Use `test_transaction()` +- Fast (~1-5ms setup) +- Auto-rollback on drop +- Ideal for query logic, CRUD, business rules + +**5% of tests:** Use `isolated_db()` +- Slower (~15-30ms setup) +- Full database isolation +- Use for: migrations, concurrent transactions, LISTEN/NOTIFY, advisory locks + +**Never use `get_test_db()` for tests that write data** - changes persist and cause flaky tests. + +## Frontend: Component vs E2E + +**Component tests (Vitest):** +- Single component behavior +- Unit interactions (clicks, inputs) +- Fast, no browser needed +- Co-located with component + +**E2E tests (Playwright):** +- Multi-page user journeys +- Integration with real API +- Visual verification +- In `web/tests/` directory + +## Naming Conventions + +``` +# Backend +service/tests/ + {feature}_tests.rs # e.g., voting_tests.rs, auth_tests.rs + +# Frontend +web/src/components/ + MyComponent.tsx + MyComponent.test.tsx # Co-located + +web/tests/ + user-signup.spec.ts # E2E kebab-case +``` + +## See Also + +- [Backend Test Patterns](../playbooks/backend-test-patterns.md) - Detailed Rust testing guide +- [Frontend Test Patterns](../playbooks/frontend-test-patterns.md) - Vitest and Playwright patterns +- [Test Data Factories](../playbooks/test-data-factories.md) - Creating backend test data