Typescript TDD Behavioural Test Specifications

Encourages a Test-Driven Design approach, with behaviour-like descriptions. The output of the test run should resemble a specification. Tests will be co-located with the actual code files and follow the *.spec.ts naming convention. The final rule is "Definition of Done", which prompts the AI assistant to ensure that the code is in a good state with all tests passing and no errors or warnings. Note: Linting examples assume `npm lint:fix` script exists.

TypeScript
React
NextJS
Vue.js

@walmsles

Author

Submitted on April 23, 2025
# TypeScript Testing Rules for AI Agents

## Test-First Approach

- Always write tests first following Test-Driven Development principles
- Tests serve as specification documents for the code
- Each test should be written before the implementation code

## Test File Organization

- Place test files in the same folder as the code being tested
- NEVER create a separate "tests" folder
- Name test files with the same name as the source file plus `.spec.ts` suffix
  - Example: For `WebSocketClient.ts`, the test file should be `WebSocketClient.spec.ts`

## Test Structure

- Organize tests using nested `describe` blocks for each component
- Prefix every feature with `[Feature-Name]`, e.g., `[WebSocket-Connector] When an event is received`
- Format `describe` blocks with behavioral "When \<action\>" pattern
- Write `it` blocks with behavioral "should" statements
- Place all `it` blocks inside appropriate `describe` blocks
- Never use top-level `it` blocks
- Ensure `it` tests are inserted in-line within their parent `describe` blocks
- Tests must add value to the application.  `expect(true).toBe(true)` is not a useful test outcome and MUST be avoided.  
- When the same test fails several times, zoom out and reread the code while you THINK on the best solution before moving to the next attempt

### Example of Correct Test Structure:

```typescript
// CORRECT:
describe('[Calculator] When using the addition feature', () => {
  it('should correctly add two positive numbers', () => {
    // test implementation
  });
  
  it('should handle negative numbers', () => {
    // test implementation
  });
});

// INCORRECT:
it('should add two numbers', () => {
  // This is a top-level it block - not allowed
});
```

## Test Descriptions

- Use descriptive, behavior-focused language
- Tests should effectively document specifications

### Example of Good Test Descriptions:

```typescript
// GOOD:
describe('[Authentication] When a user attempts to authenticate', () => {
  it('should reject login attempts with invalid credentials', () => {
    // test implementation
  });
  
  it('should grant access with valid credentials', () => {
    // test implementation
  });
});

// BAD:
describe('Authentication', () => {
  it('invalid login fails', () => {
    // test implementation
  });
});
```

## Specification-Driven Development

- Tests act as living documentation of the code's behavior
- When tests fail, focus on fixing the code to match the tests, not vice versa
- The tests are the specification, so don't modify them to suit the code
- Tests should describe what the code should do, not how it does it

## Process Sequence

1. Run linting first (`npm run lint:fix` to auto-fix when possible)
2. Build the code to verify compilation
3. Run tests to verify functionality and coverage

## Linting

- Linting must be run before tests
- Start with `npm run lint:fix` to automatically fix some lint errors
- All remaining linting errors must be manually resolved

## Test Coverage Requirements

- Maintain 100% test coverage for all code
- No exceptions to the coverage rule
- NEVER adjust coverage rules to less than 100% for any reason
- When working on test coverage, only add new tests without modifying existing tests

## Definition of Done

- No linting warnings or errors
- Successful build with no errors or warnings
- All tests passing with no warnings or errors
- 100% test coverage for ALL files