Use when writing or reviewing tests - covers test philosophy, condition-based waiting, mocking strategy, and test isolation
View on GitHubed3dai/ed3d-plugins
ed3d-house-style
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/ed3dai/ed3d-plugins/blob/main/plugins/ed3d-house-style/skills/writing-good-tests/SKILL.md -a claude-code --skill writing-good-testsInstallation paths:
.claude/skills/writing-good-tests/# Writing Good Tests
## Philosophy
**"Write tests. Not too many. Mostly integration."** — Kent C. Dodds
Tests verify real behavior, not implementation details. The goal is confidence that your code works, not coverage numbers.
**Core principles:**
1. Test behavior, not implementation — refactoring shouldn't break tests
2. Integration tests provide better confidence-to-cost ratio than unit tests
3. Wait for actual conditions, not arbitrary timeouts
4. Mock strategically — real dependencies when feasible, mocks for external systems
5. Don't pollute production code with test-only methods
## Test Structure
Use **Arrange-Act-Assert** (or Given-When-Then):
```typescript
test('user can cancel reservation', async () => {
// Arrange
const reservation = await createReservation({ userId: 'user-1', roomId: 'room-1' });
// Act
const result = await cancelReservation(reservation.id);
// Assert
expect(result.status).toBe('cancelled');
expect(await getReservation(reservation.id)).toBeNull();
});
```
**One action per test.** Multiple assertions are fine if they verify the same behavior.
## Condition-Based Waiting
Flaky tests often guess at timing. This creates race conditions where tests pass locally but fail in CI.
**Wait for conditions, not time:**
```typescript
// BAD: Guessing at timing
await new Promise(r => setTimeout(r, 50));
const result = getResult();
// GOOD: Waiting for condition
await waitFor(() => getResult() !== undefined);
const result = getResult();
```
### Generic Polling Function
```typescript
async function waitFor<T>(
condition: () => T | undefined | null | false,
description: string,
timeoutMs = 5000
): Promise<T> {
const startTime = Date.now();
while (true) {
const result = condition();
if (result) return result;
if (Date.now() - startTime > timeoutMs) {
throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
}
await new Promise(r => setTimeout(r, 10)); // Poll every 10ms