AI Tools Compared

When you work with Claude Code or similar AI coding assistants, the quality of output depends heavily on how well the AI understands your project’s conventions. A well-crafted CLAUDE.md file transforms generic AI responses into context-aware assistance that respects your team’s testing patterns, frameworks, and quality standards.

This guide shows you how to write CLAUDE.md files that effectively teach AI assistants about your testing conventions and patterns.

Why Testing Conventions Belong in CLAUDE.md

Your test suite likely follows specific patterns that new developers (and AI) need to learn. Without explicit guidance, AI assistants generate tests that work but don’t match your project’s style. They might use different assertion libraries, naming conventions, or setup patterns than your team prefers.

A CLAUDE.md file solves this by providing persistent context. Unlike chat prompts that reset between sessions, CLAUDE.md gets loaded with every new conversation, ensuring consistent behavior across your entire project.

Core Sections for Testing Conventions

Test Framework and Dependencies

Start by documenting which testing frameworks your project uses and any related plugins or assertion libraries.

## Testing Stack

- Test Framework: Jest 29.x
- Assertion Library: Jest built-in expect
- Testing Utilities: @testing-library/react, @testing-library/jest-dom
- Coverage: jest-coverage-threshold at 80% for branches and lines

This section prevents AI from suggesting alternative frameworks like Mocha or Vitest when you’re working in a Jest project.

File Organization Patterns

Define where tests live and how they’re structured relative to source files.

## Test File Organization

- Unit tests: __tests__/ directory alongside source files
- Integration tests: tests/integration/ directory
- E2E tests: tests/e2e/ with Playwright
- Test file naming: *.test.ts (not *.spec.ts)
- Mock files: __mocks__/ directory at package root

Naming Conventions

Clear naming conventions make test intent obvious at a glance.

## Test Naming Conventions

- Describe blocks: Use sentence case starting with "should"
  - describe('UserService', () => { ... })
  - it('should return user by id', () => { ... })
- Test prefixes: When behavior-driven, use "given/when/then"
  - it('given valid email, when creating user, then returns success')
- Snapshot files: *.snap in __snapshots__ subdirectory

Documenting Test Patterns

Setup and Teardown Patterns

Every project has specific patterns for test setup. Document yours explicitly.

## Test Setup Patterns

### Before Each
- Always call jest.clearAllMocks() in global beforeEach
- Reset test database state using test fixtures
- Initialize Redux store with mock state using configureStore

### After Each
- Wait for all async operations using waitFor
- Clean up any timers using jest.runAllTimers()
- Close database connections in global afterAll

Mocking Strategies

AI assistants need to understand your mocking preferences.

## Mocking Conventions

### Module Mocks
- Use jest.mock() with factory parameter for external modules
- Mock AWS services with aws-sdk-client-mock
- Mock React components using mock component libraries

### Function Mocks
- Use jest.fn() for simple mocks
- Use jest.spyOn() when wrapping existing methods
- Always implement returnValue or mockImplementation

### API Mocks
- Use MSW (Mock Service Worker) for HTTP mocks
- Define handlers in tests/__mocks__/handlers.ts
- Use rest.get() and rest.post() with path matching

Async Testing Patterns

Different projects handle async operations differently. Make your approach clear.

## Async Testing

- Use async/await with expect(await ...).resolves/rejects
- For hooks: use renderHook from @testing-library/react-hooks
- For components: use waitFor from @testing-library/react
- Avoid using done callbacks unless necessary
- Set default timeout: jest.setTimeout(10000)

Integration with CI/CD

Testing conventions often tie into your CI pipeline. Document these requirements.

## CI Testing Requirements

- All tests must pass before merge (no skipped tests allowed)
- Coverage threshold enforced in CI
- Run unit tests on PR: npm test -- --coverage
- Integration tests run on merge to main branch only
- Use --detectOpenHandles to catch async issues

Real-World Examples

React Component Testing

## React Component Tests

- Use @testing-library/react (not enzyme)
- Query priority: getByRole > getByLabelText > getByText > getByTestId
- Test user interactions, not implementation details
- Snapshot tests only for static components (headers, footers)
- Always include accessibility tests for interactive elements

Backend API Testing

## API Endpoint Tests

- Test in isolation using dependency injection
- Use supertest for Express/REST APIs
- Test happy path, edge cases, and error responses
- Validate response status codes and payload structure
- Mock database layer, test actual handlers

Advanced Patterns: Coverage and Reporting

Teams with strong quality cultures go beyond basic naming and setup conventions. Document your coverage expectations explicitly so AI-generated tests meet the bar from the start, not after review feedback.

Document your minimum thresholds and the commands used to enforce them. Include which directories or files should be excluded, since generated code, migration scripts, and vendor adapters typically should not count against coverage metrics.

Also document your reporting format expectations. Some teams generate HTML reports for code review context, others pipe coverage JSON to internal dashboards. AI needs to know which reporters to include in commands it generates.

Practical Examples: Teaching AI Your Project Idioms

Beyond naming and setup, your project likely has idioms — patterns that are not official conventions but are understood team-wide. Document these directly so AI generates code that fits without friction.

If you have in-house test utilities, describe them with their location and when to use them instead of the standard alternative. For example: if your team uses a custom renderWithProviders wrapper that sets up Redux, Router, and ThemeProvider, document that AI should always use it instead of bare render() for any component that touches shared state or routing.

For error boundary and edge case testing, spell out your team’s minimum expectations. Specify that optional props should always be tested with null and undefined values, that loading states need explicit test coverage, and that empty states — empty arrays, empty strings, zero counts — require separate tests from populated states.

Step-by-Step: Building Your First CLAUDE.md Testing Section

If you are starting from scratch, here is a practical sequence that takes about 30 minutes and produces a useful file immediately.

Step 1: Audit your test files. Open five recent test files and note what they have in common: how describe blocks are named, how mocks are set up, where test utilities come from, and what assertion style is used. These patterns belong in CLAUDE.md whether or not they are official policy.

Step 2: Note where AI previously went wrong. Look at past pull request comments that corrected AI-generated tests. Each recurring correction is a missing CLAUDE.md rule. If reviewers wrote “use waitFor, not await act” three times this month, that belongs in your file.

Step 3: Write rules as commands, not suggestions. Use phrases like “always,” “never,” “use X instead of Y.” Hedging with “prefer” or “consider” gives AI room to revert to defaults.

Step 4: Validate with a real prompt. Write a new test using Claude Code after adding your CLAUDE.md. Check whether the output respects the conventions. If it misses something, add a more specific rule. Iteration is normal — most CLAUDE.md files reach a stable state after two or three revision cycles.

Step 5: Commit and share. Check CLAUDE.md into version control alongside your codebase. When onboarding new developers, point them to CLAUDE.md as the source of truth for AI-assisted coding conventions, not just human ones.

Common Pitfalls When Writing Testing Conventions for AI

Being too abstract. “Write good tests” tells AI nothing. Specifics like “use getByRole over getByTestId” give AI a concrete decision rule it can apply consistently.

Documenting aspirations, not reality. If your codebase has 300 tests using getByTestId and your CLAUDE.md says to use getByRole, AI will produce inconsistent output. Document what the codebase actually does, or add a migration note explaining the transition direction.

Missing the “why.” Claude follows instructions more reliably when they include reasoning. Instead of “don’t use toMatchSnapshot for dynamic content,” write “avoid toMatchSnapshot for components with dynamic dates or IDs because diffs become noisy and unreviewed snapshots mask regressions.”

Skipping anti-patterns. Explicitly listing what not to do is often more valuable than listing what to do. A section like “Patterns to Avoid” prevents AI from reverting to common but unwanted approaches such as testing implementation details, using enzyme-style wrappers, or adding hardcoded sleeps in async tests.

Maintaining Your CLAUDE.md

Testing conventions evolve. Schedule periodic reviews of your CLAUDE.md to keep it current.

  1. Update on framework upgrades - When upgrading Jest or adding libraries

  2. Review in code reviews - Check if new patterns need documentation

  3. Test with AI output - If AI consistently misses patterns, add guidance

A CLAUDE.md that doesn’t reflect reality wastes everyone’s time. Keep it honest and current.

Built by theluckystrike — More at zovo.one