|
| 1 | +# Testing Guidelines - General |
| 2 | + |
| 3 | +## Repository Context |
| 4 | + |
| 5 | +**Framework:** Preact (NOT React) - All imports must use `preact` and `preact/hooks` |
| 6 | +**Testing Stack:** Vitest + @testing-library/preact + TypeScript |
| 7 | +**File Convention:** Co-locate tests with source files using `.test.ts` or `.test.tsx` |
| 8 | + |
| 9 | +## Core Principles |
| 10 | + |
| 11 | +### Critical Rule: Deterministic Assertions Only |
| 12 | + |
| 13 | +All test assertions must use concrete, deterministic values. No generic type checks or regex patterns allowed. |
| 14 | + |
| 15 | +Never use: |
| 16 | + |
| 17 | +```typescript |
| 18 | +expect(typeof result).toBe('string'); |
| 19 | +expect(result.length).toBeGreaterThan(0); |
| 20 | +expect(result).toMatch(/pattern/); |
| 21 | +``` |
| 22 | + |
| 23 | +Always use: |
| 24 | + |
| 25 | +```typescript |
| 26 | +expect(result).toBe('04:10 PM'); |
| 27 | +expect(result).toEqual(['04:10 PM', '']); |
| 28 | +``` |
| 29 | + |
| 30 | +### Real Implementation Over Mocking |
| 31 | + |
| 32 | +- Use real implementations with controlled inputs |
| 33 | +- Control behavior through `vi.useFakeTimers()` and `vi.setSystemTime()` |
| 34 | +- Only mock external dependencies, not internal utilities |
| 35 | +- Use `vi.mocked()` for typed mocks instead of casting to `any` |
| 36 | + |
| 37 | +### Code Style |
| 38 | + |
| 39 | +- Use consistent formatting with trailing commas |
| 40 | +- Simple arrays stay inline, complex ones get expanded |
| 41 | +- Keep variable names descriptive and purpose-driven |
| 42 | + |
| 43 | +## Query Priority (Testing Library) |
| 44 | + |
| 45 | +1. `getByRole` - Best for accessibility |
| 46 | +2. `getByLabelText` - Form elements |
| 47 | +3. `getByPlaceholderText` - When no label |
| 48 | +4. `getByText` - Static content |
| 49 | +5. `getByTestId` - Last resort only |
| 50 | + |
| 51 | +Avoid direct DOM access via `container` or `document.querySelector` |
| 52 | + |
| 53 | +## Common Pitfalls |
| 54 | + |
| 55 | +- Testing internal state instead of rendered output |
| 56 | +- Forgetting to `await` async operations |
| 57 | +- Not clearing mocks between tests (add `vi.clearAllMocks()` to `beforeEach`) |
| 58 | + |
| 59 | +## Type Safety |
| 60 | + |
| 61 | +Use `vi.mocked()` instead of casting to `any` for: |
| 62 | + |
| 63 | +- Autocomplete for mock methods |
| 64 | +- Compile-time type checking |
| 65 | +- Better refactoring support |
| 66 | + |
| 67 | +## Workflow |
| 68 | + |
| 69 | +### When writing tests for hooks |
| 70 | + |
| 71 | +1. Always follow `.agents/testing/unit-tests/hooks_testing_guidelines.md` |
| 72 | +2. Complete the analysis phase before writing any tests |
| 73 | +3. Wait for user confirmation after analysis |
| 74 | + |
| 75 | +### When writing tests for components |
| 76 | + |
| 77 | +1. Always follow `.agents/testing/unit-tests/components_testing_guidelines.md` |
| 78 | + |
| 79 | +### After tests are complete |
| 80 | + |
| 81 | +1. Analyze code coverage (statements, branches, functions, lines) |
| 82 | +2. Report any gaps with specific line numbers |
| 83 | +3. For each gap, explain if it CAN be tested or if it's fundamentally untestable |
| 84 | +4. If 100% is achievable, ask if user wants to achieve it and list needed tests |
| 85 | +5. If 100% is NOT achievable, explain why and what maximum coverage is realistic |
| 86 | +6. Only add coverage tests after user confirmation |
| 87 | + |
| 88 | +## Coverage Analysis Format |
| 89 | + |
| 90 | +``` |
| 91 | +Coverage Analysis: |
| 92 | +- Statements: X% |
| 93 | +- Branches: X% |
| 94 | +- Functions: X% |
| 95 | +- Lines: X% |
| 96 | +
|
| 97 | +[If not 100%] |
| 98 | +Missing Coverage: |
| 99 | +1. Line X: [what's not tested] |
| 100 | + - Testable: YES/NO |
| 101 | + - Reason if not testable: [explanation] |
| 102 | +
|
| 103 | +[If 100% is achievable] |
| 104 | +Would you like to achieve 100% coverage? |
| 105 | +To reach 100%, we need: |
| 106 | +- [Specific test needed] |
| 107 | +
|
| 108 | +[If 100% is NOT achievable] |
| 109 | +Maximum achievable coverage: X% |
| 110 | +Reason 100% is not possible: [explanation] |
| 111 | +Recommended: Accept X% coverage because [reasoning] |
| 112 | +``` |
| 113 | + |
| 114 | +## Coverage Requirements |
| 115 | + |
| 116 | +- Focus on behavior coverage, not just line coverage |
| 117 | +- Accept build artifact gaps (HMR, source maps) |
| 118 | +- If coverage is less than 80% for the file being tested, iterate |
| 119 | + |
| 120 | +## Quality Checklist |
| 121 | + |
| 122 | +- Analysis phase completed and confirmed |
| 123 | +- All assertions use concrete values (no typeof, toMatch, toContain) |
| 124 | +- Testing behavior, not implementation |
| 125 | +- Common setup in beforeEach, test-specific constants in test functions |
| 126 | +- Edge cases covered with concrete expectations |
| 127 | +- Async operations properly awaited |
| 128 | +- Mocks cleared between tests |
| 129 | +- Try to cover more with fewer and more precise tests. Avoid having too many tests if it is not increasing the coverage. |
| 130 | +- Follow the best practices from Vitest and @testing-library/preact |
0 commit comments