Skip to content

Commit 1c3a8e4

Browse files
authored
Merge pull request #780 from Adyen/group/increase-unit-test-coverage
Increase unit test coverage
2 parents 7fc1dcc + e15b29c commit 1c3a8e4

File tree

8 files changed

+802
-22
lines changed

8 files changed

+802
-22
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Testing Guidelines - Components
2+
3+
## What to Test
4+
5+
**Do test:**
6+
7+
- What users see and interact with
8+
- Behavior that would break if the feature is broken
9+
- Public API (props, callbacks, rendered output)
10+
11+
**Don't test:**
12+
13+
- Internal state variables or private methods
14+
- Exact DOM structure or CSS classes (unless functional)
15+
- Third-party library internals
16+
- Implementation details that could change during refactoring
17+
18+
## Organization
19+
20+
Group related tests in describe blocks: rendering, interactions, edge cases.
21+
22+
```typescript
23+
describe('MyComponent', () => {
24+
describe('Rendering', () => {
25+
test('should render with default props', () => {
26+
/* ... */
27+
});
28+
});
29+
30+
describe('Interactions', () => {
31+
test('should call onClick when button is clicked', () => {
32+
/* ... */
33+
});
34+
});
35+
36+
describe('Edge Cases', () => {
37+
test('should handle null props gracefully', () => {
38+
/* ... */
39+
});
40+
});
41+
});
42+
```
43+
44+
## Priority Order
45+
46+
### High Priority
47+
48+
1. Component renders expected content based on props
49+
2. User interactions (clicks, typing, form submission) trigger correct behavior
50+
3. Conditional rendering (loading states, error states, empty states)
51+
4. Accessibility (ARIA attributes, keyboard navigation)
52+
5. Callback props fire with correct arguments
53+
54+
## ESLint Rules
55+
56+
- **react/jsx-no-literals**: Store string literals in centralized constants with `as const`
57+
- **arrow-parens**: Always wrap arrow function parameters in parentheses
58+
59+
## Mocking
60+
61+
- Keep mocks simple and behavior-focused
62+
- Re-use mocks from ./mocks folder whenever possible
63+
- Avoid hoisting in mock factories
64+
65+
## Common Anti-Patterns
66+
67+
- Direct DOM access via container or document.querySelector (use Testing Library queries)
68+
- Testing internal state instead of rendered output
69+
- Over-specific assertions (exact DOM structure, innerHTML)
70+
- Not using semantic queries (prefer getByRole over getByTestId)
71+
72+
## Test Naming
73+
74+
Write descriptive names that explain behavior:
75+
76+
- Good: "should disable submit button when form is invalid"
77+
- Bad: "button test"
78+
79+
## Keep Tests Focused
80+
81+
- One primary assertion per test when possible
82+
- Extract repetitive setup into helper functions
83+
84+
## Coverage Approach
85+
86+
Focus on behavior coverage, not line coverage percentages:
87+
88+
- Happy path for primary use case
89+
- Key edge cases (empty, null, extreme values)
90+
- Error states and error handling
91+
- Critical accessibility features
92+
93+
## Balance DRY and Readability
94+
95+
Don't over-abstract tests. Sometimes repetition is clearer than excessive abstraction.
96+
97+
## Quality Checklist
98+
99+
- Using semantic queries over test IDs
100+
- No direct DOM manipulation
101+
- Testing user-visible behavior
102+
- Accessibility features tested
103+
- All user interactions tested
104+
- Conditional rendering tested
105+
- Callback props tested
106+
- Edge cases covered
107+
- String literals in constants
108+
- Arrow functions use parentheses
109+
- Mocks are reused
110+
- Async operations awaited
111+
- Test names are descriptive
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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

Comments
 (0)