Respondeo
Development

Testing

Testing strategy and load test results

Test Strategy

Respondeo uses unit tests, integration tests that run against real backing services, and k6 load tests.

Unit Tests

Unit tests are colocated with the code they cover, as *.test.ts next to the module. They need no database or cache and are the bulk of the suite:

AreaFile
Attempt grading and de-duplicationapps/web/lib/quiz/grading.test.ts
Signed attempt-start tokens and timingapps/web/lib/quiz/attempt-token.test.ts
Pagination parameter parsingapps/web/lib/pagination.test.ts
Attempt submission schemasapps/web/lib/validations/attempt.test.ts
Rate limitingapps/web/lib/rate-limit.test.ts
Redis target formattingapps/web/lib/cache/client.test.ts
CLI project-name validationpackages/create-respondeo-app/src/validate.test.ts

Run them from the repository root:

pnpm test

This runs in CI on every push and pull request.

Integration Tests

Integration tests are named *.integration.test.ts and exercise behaviour that only a real service demonstrates — foreign-key cascades, transaction rollback, and Redis SCAN-based invalidation:

AreaFile
Quiz content persistence, cascades, rollbackapps/web/lib/quiz/content.integration.test.ts
Cache invalidation against Valkeyapps/web/lib/cache/invalidation.integration.test.ts

They skip themselves unless DATABASE_URL / REDIS_URL are set, so pnpm test stays fast and dependency-free. To run everything against the local Docker Compose stack:

pnpm --filter web test:integration

That script starts Postgres and Valkey, applies migrations, and runs the full suite. Credentials come from apps/web/.env.compose, which is created from .env.compose.example on first run. The containers can be managed directly with pnpm --filter web docker:up and pnpm --filter web docker:down.

Load Tests

Load tests simulate high-traffic scenarios using k6.

Load Test Results

The app has been tested to sustain 5000 concurrent users with 0% error rate.

Latest Results (January 4, 2026)

MetricValue
Peak VUs5000 (3000 browsers, 1500 players, 500 spectators)
Error Rate0.00% ✅
Throughput834 req/s
Total Requests319,511
Test Duration6m 23s
Data Transferred1.7 GB received, 109 MB sent

Performance Optimizations

The following optimizations enabled this performance level:

  1. Redis/Valkey caching — 5-10 minute TTL on read-heavy data
  2. PostgreSQL tuning — Increased connections and memory
  3. Cached quiz data for attempts — Eliminates 3 DB queries per attempt

Endpoint Latency

EndpointMedianp90p95p99
Quiz List9.31ms295ms1.04s2.32s
Quiz Detail9.65ms311ms1.07s2.31s
Attempt Submit20.19ms532ms1.32s2.67s
Global Leaderboard8.86ms330ms1.05s2.34s
Quiz Leaderboard9.08ms374ms1.14s2.40s

Notes:

  • Median latencies are excellent (~10ms) thanks to caching
  • p95+ latencies are elevated under peak load but acceptable
  • Write path (attempt submission) has highest latency as expected

Comparison: Before vs After Caching

MetricWithout CacheWith CacheImprovement
Max Stable VUs~1,6005,0003.1x
Error Rate0.01%0.00%
Throughput~400 req/s834 req/s2x
Median Latency~15ms~10ms33% faster

Running Load Tests

Prerequisites

Install k6:

# macOS
brew install k6

# Linux
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

# Windows
choco install k6

Run Load Test

# Start the backing services and the app
pnpm --filter web docker:up
pnpm dev

# In another terminal (requires k6 on your PATH)
pnpm --filter web loadtest

The load test script is located at apps/web/tests/loadtest.js.

Test Scenarios

The load test simulates three user types:

  1. Browsers (60%) — View quiz list and details
  2. Players (30%) — Play quizzes and submit attempts
  3. Spectators (10%) — View leaderboards

Customizing Load Tests

Edit apps/web/tests/loadtest.js:

export const options = {
  stages: [
    { duration: "30s", target: 100 }, // Ramp up to 100 users
    { duration: "1m", target: 100 }, // Stay at 100 users
    { duration: "30s", target: 0 }, // Ramp down to 0
  ],
  thresholds: {
    http_req_failed: ["rate<0.01"], // <1% errors
    http_req_duration: ["p(95)<1000"], // 95% requests <1s
  },
};

Performance Monitoring

Database

Monitor PostgreSQL performance:

docker compose exec db psql -U quiz_app -c "SELECT * FROM pg_stat_activity;"

Cache

Monitor Redis/Valkey:

docker compose exec valkey redis-cli INFO stats
docker compose exec valkey redis-cli INFO memory

Application

Next.js performance monitoring is available through:

  • Vercel Analytics (if deployed on Vercel)
  • Custom logging in server actions and API routes

Next Steps

On this page