Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions docs/playbooks/backend-test-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion docs/playbooks/fixing-flaky-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions docs/playbooks/frontend-test-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion docs/playbooks/migration-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 10 additions & 2 deletions docs/playbooks/new-graphql-endpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
6 changes: 6 additions & 0 deletions docs/playbooks/test-data-factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
105 changes: 105 additions & 0 deletions docs/skills/test-writing.md
Original file line number Diff line number Diff line change
@@ -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