---
description: Best practices and conventions for testing JavaScript and TypeScript code
globs: **/*.test.js, **/*.test.ts, **/*.test.tsx
---

# Testing

## General principle

**Important**: Aim for the smallest high-value test set that protects behavior, interface contracts, invariants, and regression-prone paths. Focus on testing behavior rather than implementation details.

## Structure & Organization

- Order of tests: Match the order of tests to the order of symbols in the source file
- One describe per export: Provide a describe block for each exported symbol (function, class, constant)
- Hierarchical grouping: Use nested describe() blocks - outer for function/class, inner for scenarios
- Logical categorization: Group by behavior, input type, or state (e.g., "with valid input", "error handling")
- Each it() should test a single behavior

## Test Coverage

- Happy path: Test expected behavior with typical inputs
- Edge cases: Test boundaries, empty values, maximum/minimum values
- Error scenarios: Test all failure modes with proper error type/message validation
- Type variations: Test all relevant data types (primitives, objects, arrays, functions)
- Falsy values: Explicitly test null, undefined, 0, "", false, NaN

## Type Safety

- Type annotations: Include explicit types in test variables to verify inference
- Compile-time checks: Some tests exist just to verify type compatibility
- Type tests for generics: Add type tests for generic functions, classes, etc. Use the test runner's type testing tool when available (e.g. with Vitest: `expectTypeOf`)

## Best Practices

- Descriptive names: Use clear it() descriptions stating expected behavior
- Avoid "should" phrasing in it(): Use verbs like "does" or "returns" to describe behavior
- Isolation: Each test should be independent and not rely on others
- Arrange-Act-Assert: Follow AAA pattern for test structure
- DRY with helpers: Extract repetitive setup into helper functions
- Use real-life examples and descriptive names for test data

## Assertions

- Prefer `.toMatchObject()` over `.toEqual()` for object/array content checks
- Do not over-assert: Only include relevant data into the expected value using `.toMatchObject()`
- Check for reference equality only if it matters for the test
- Multiple assertions: Group related checks in single test when testing same behavior
- Use `.toThrowErrorMatchingInlineSnapshot()` for exact error messages
