Instruction file imported from maverock24/soundscape (
.github/instructions/testing.instructions.md). Copyright stays with the author.
Testing Standards
Testing Philosophy
- Tests are documentation — a new developer should understand the feature by reading the tests.
- Test behavior, not implementation details.
- Every test must be independent, deterministic, and fast.
- Prefer many small focused tests over few large integration tests.
Test Structure
Naming Convention
Test files must be co-located with the code they test or in a parallel __tests__/ directory.
src/features/users/users.service.ts
src/features/users/users.service.spec.ts ← co-located
Test Naming
Use descriptive names that explain the scenario:
✓ should return user profile when valid ID is provided
✓ should return 404 error when user does not exist
✓ should reject request when authentication token is missing
✗ test1
✗ works correctly
✗ handles edge case
Test Organization
Group tests logically by method or behavior:
describe('UserService', () => {
describe('findById', () => {
it('should return user when found', ...);
it('should return error when not found', ...);
it('should handle database timeout', ...);
});
});
Unit Tests
- Test one unit of logic in isolation.
- Mock external dependencies (databases, APIs, file systems).
- Cover: happy path, error paths, edge cases, boundary conditions.
- Target: minimum 75% coverage for new code.
Integration Tests
- Test the interaction between multiple components.
- Use real (or test) databases where practical.
- Focus on API contracts, data flow, and error propagation.
- Test authorization and authentication flows.
E2E Tests
- Test complete user workflows through the UI.
- Keep E2E tests focused on critical paths — they are expensive to run.
- Include accessibility checks (axe-core or equivalent).
- Use stable selectors (data-testid, aria-label) — never CSS class selectors.
Test Quality Rules
- No test interdependency: Tests must not depend on execution order or shared mutable state.
- No flakiness: Mock all non-deterministic dependencies (time, random, network).
- No debugging artifacts: Remove
console.log,.only,.skipbefore commit. - Minimal setup: Only mock/setup what the specific test needs.
- Assertions per test: One logical assertion per test (multiple
expectfor one behavior is fine).
Mocking Standards
- Mock at the boundary (external services, databases, APIs).
- Never mock the unit under test.
- Use the project's established mocking framework.
- Keep mock data realistic — don't use placeholder values like "test" or "foo".
Review Checklist
- All new logic has corresponding tests.
- Both success and error paths are tested.
- Edge cases are covered (null, empty, boundary values).
- Tests are independent and deterministic.
- No
.onlyor.skipleft in committed code. - Test names are descriptive.
- Mocking is done at boundaries, not internals.