Skip to content

Testing Strategy

Automated testing is critical to our development lifecycle. It gives us the confidence to refactor, upgrade dependencies, and deploy frequently.

1. The Test Pyramid

We aim for a healthy balance of tests: - Unit Tests (Many): Test individual functions, classes, or React components in isolation. Fast to write, fast to run. - Integration Tests (Some): Test how multiple units work together (e.g., a Use Case talking to a real Database repository). - E2E Tests (Few): Test the entire system from the user's perspective, running in a real browser against a real environment.

2. Frontend Testing

  • Tool: Vitest for Unit/Integration, Playwright for E2E.
  • Component Testing: Use React Testing Library. Focus on testing behavior (what the user sees and interacts with) rather than implementation details (internal component state).
  • E2E with Serenity BDD: Use the Screenplay Pattern to write business-readable, maintainable tests. E2E tests should verify critical user journeys (e.g., user signup, checkout flow).

3. Backend Testing

  • Mocking: Mock external services (e.g., third-party APIs) to keep tests deterministic.
  • Database Testing: Avoid mocking the database. Use Testcontainers to spin up a real PostgreSQL instance via Docker for repository and integration tests. This ensures your SQL and migrations actually work.

4. Test-Driven Development (TDD)

While not strictly mandated for every single line of code, TDD is highly encouraged, especially for complex business logic. 1. Red: Write a failing test. 2. Green: Write the simplest code to make it pass. 3. Refactor: Clean up the code while the test keeps you safe.

5. Test Quality

  • Tests should follow the Arrange, Act, Assert (or Given, When, Then) structure.
  • Tests must be deterministic. Flaky tests (tests that pass/fail randomly without code changes) must be fixed or deleted immediately, as they erode trust in the CI pipeline.