Aller au contenu

Testing Standards

This document outlines the testing requirements for all contributions to Plus261.

All code contributions must include appropriate tests. This ensures code quality and prevents regressions.

When adding new features, you must include:

  1. Unit Tests - Test individual functions and methods
  2. Integration Tests - Test component interactions
  3. Edge Case Tests - Test error conditions and boundaries

When fixing bugs, you must:

  1. Write a Test - That reproduces the bug
  2. Fix the Bug - Make the test pass
  3. Verify - Ensure no regressions

Any code change should:

  1. Maintain Coverage - Don’t decrease test coverage
  2. Update Tests - Update existing tests if behavior changes
  3. Add Tests - For new functionality

Test individual functions and classes in isolation.

Required for:

  • Business logic functions
  • Utility functions
  • Service methods
  • Complex calculations

Example:

describe('calculateTotal', () => {
it('should sum item prices', () => {
const items = [{ price: 10 }, { price: 20 }];
expect(calculateTotal(items)).toBe(30);
});
});

Test that multiple components work together.

Required for:

  • API endpoints
  • Database operations
  • Service interactions
  • Module integrations

Example:

describe('Product API', () => {
it('should create and retrieve product', async () => {
const product = await createProduct({ name: 'Test' });
const retrieved = await getProduct(product.id);
expect(retrieved.name).toBe('Test');
});
});

Test that permissions work correctly.

Required for:

  • All protected endpoints
  • Permission checks
  • Role-based access

Example:

describe('Product Authorization', () => {
it('should deny access without permission', async () => {
const result = await queryProducts({ userId: 'user-without-permission' });
expect(result.errors[0].message).toContain('Unauthorized');
});
});
  • Critical paths: 100%
  • Business logic: >80%
  • Utilities: >70%
  • Overall project: >75%

Some code may be excluded from coverage:

  • Type definitions
  • Configuration files
  • Generated code
  • Test utilities

Document exceptions with comments:

/* istanbul ignore next */
function debugOnlyFunction() {
// ...
}

Follow the Arrange-Act-Assert pattern:

it('should calculate discount', () => {
// Arrange
const price = 100;
const discountPercent = 10;
// Act
const result = calculateDiscount(price, discountPercent);
// Assert
expect(result).toBe(90);
});

Use descriptive test names:

// ✅ Good
it('should throw NotFoundError when user does not exist', () => {});
// ❌ Bad
it('test getUserById', () => {});

Each test should be independent:

// ✅ Good
beforeEach(() => {
// Set up fresh test data
});
// ❌ Bad
let sharedData; // Tests depend on each other
Fenêtre de terminal
# Run all tests
bun test
# Check coverage
bun test --coverage
# Code quality (monorepo root)
bun --bun run check:code
Fenêtre de terminal
# Run all tests
bun test
# Run in watch mode
bun test:watch
# Run with coverage
bun test --coverage
# Run specific test file
bun test path/to/test.test.ts

When reviewing PRs, check:

  • Tests are included for new features
  • Tests cover edge cases
  • Tests are independent
  • Test names are descriptive
  • Coverage meets requirements
  • Tests pass in CI
  • No flaky tests

Flaky tests are tests that sometimes pass and sometimes fail.

Causes:

  • Timing issues
  • Shared state
  • Random data
  • External dependencies

Solutions:

  • Use fake timers
  • Isolate test data
  • Mock external dependencies
  • Use deterministic data

Tests should run quickly.

Optimization:

  • Use mocks instead of real services
  • Use in-memory database for tests
  • Parallelize tests when possible
  • Skip expensive setup when not needed