Skip to main content

Overview

PyqDeck uses a pragmatic testing strategy: unit tests for backend logic and component tests for UI. We prioritize tests that give the most confidence with the least maintenance burden.

Testing Stack

When to Write What

Backend Tests (Vitest)

Write Vitest tests for:
  • Services - Business logic (e.g., paper parsing, question extraction)
  • Repositories - Database queries and aggregations
  • Controllers - Request/response handling, validation
  • Middleware - Auth, pagination, rate limiting, error handling
  • Utilities - Formatters, validators, error classes
Rule of thumb: If it has logic (conditionals, loops, transformations), it needs tests.

Load Tests (k6)

Write k6 tests for:
  • Critical paths - /papers, /questions, /search
  • Before major releases - Verify performance hasn’t degraded
  • After database changes - Ensure query performance is acceptable

Frontend Tests (Storybook + Vitest)

Write component tests for:
  • Complex UI components - Those with multiple states (loading, error, empty)
  • Interactive components - Forms, filters, modals
  • Accessibility-critical components - Navigation, forms, modals
Rule of thumb: If a component has props that change its appearance/behavior, test it.

Backend Testing Guide

Test Structure

Tests live in backend/tests/ mirroring the source structure:

Example: Service Test

Running Tests

Coverage Thresholds

The project enforces minimum coverage:

Load Testing Guide

Running Load Tests

Smoke Test Example

Frontend Testing Guide

Component Testing with Storybook

Each UI component has a matching Storybook story:
Run Storybook tests:

Running Frontend Tests

CI Integration

All tests run in CI on every PR:
  1. Backend tests - Vitest with coverage thresholds
  2. Contract check - Verifies openapi.json is in sync
  3. Frontend build - Validates SDK generation and Next.js build
  4. Load tests - Run against a live MongoDB service
Tests must pass before deployment. No exceptions.

Anti-Patterns to Avoid

  • Don’t test implementation details - Test behavior, not internal state
  • Don’t mock everything - Use real MongoDB (via MongoMemoryServer) when possible
  • Don’t skip error path tests - Test failure cases as thoroughly as success cases
  • Don’t write E2E tests for everything - Reserve E2E for critical user journeys only

Next Steps