3.7 KiB
3.7 KiB
Testing Improvements Design
Date: 2026-04-03 Scope: Unit tests for new server code + Playwright E2E test setup with seeded database
Part 1: Unit/Integration Tests (Bun test runner)
tests/lib/params.test.ts
Tests for parseId helper in src/server/lib/params.ts:
- Valid positive integers (1, 42, 999) return the number
- Zero returns null
- Negative numbers (-1, -100) return null
- Decimals (1.5, 3.14) return null
- Non-numeric strings ("abc", "", "hello") return null
- NaN-producing values return null
tests/middleware/rateLimit.test.ts
Tests for rate limiter in src/server/middleware/rateLimit.ts:
- First request passes through (200)
- 5 requests succeed, 6th returns 429
- 429 response includes
Retry-Afterheader - Different IPs tracked independently
- After window expires, requests succeed again
Since the rate limiter uses a module-level Map, tests need to either:
- Reset the store between tests (export a
resetStorefor testing), OR - Use unique paths/IPs per test to avoid interference
Recommended: export a _resetForTesting() function from rateLimit.ts that clears the store. Only used in tests.
tests/routes/params.test.ts
Route-level integration tests verifying 400 responses for invalid IDs:
GET /api/items/abc→ 400GET /api/items/-1→ 400GET /api/items/0→ 400DELETE /api/categories/notanumber→ 400GET /api/threads/abc→ 400GET /api/setups/abc→ 400
Uses existing test app pattern with in-memory DB.
Part 2: Playwright E2E Setup
Installation
bun add -d @playwright/testbunx playwright install chromium(only Chromium needed)
Configuration: playwright.config.ts
export default defineConfig({
testDir: "./e2e",
webServer: {
command: "DATABASE_PATH=./e2e/test.db bun run dev:server",
port: 3000,
reuseExistingServer: !process.env.CI,
},
use: {
baseURL: "http://localhost:3000",
},
projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
Database Seeding: e2e/seed.ts
Script that creates e2e/test.db with:
- Run Drizzle migrations against the file
- Seed data:
- 1 user (username: "admin", password: "password123")
- 3 categories: Shelter, Sleep System, Cook Kit
- 6 items across categories with realistic weights/prices
- 1 active thread with 3 candidates (with pros/cons, sort_order)
- 1 resolved thread
- 1 setup with 4 items (mixed classifications)
- Settings: weightUnit=g, currency=USD, onboardingComplete=true
Run before E2E tests via e2e/global-setup.ts (Playwright globalSetup).
E2E Test Files
e2e/dashboard.spec.ts
- Dashboard page loads
- Summary cards show item count, weight, cost
- Navigation links to collection work
e2e/collection.spec.ts
- Gear tab renders items grouped by category
- Search input filters items by name
- Category filter dropdown works
- Tab switching between gear/planning/setups
e2e/threads.spec.ts
- Thread detail page loads with candidates
- Comparison view toggle works (shows table)
- Rank badges visible on candidates
e2e/auth.spec.ts
- Login page renders
- Login with valid credentials succeeds
- Login with wrong password shows error
- Rate limiting returns error after 5 attempts
e2e/error-boundary.spec.ts
- App doesn't white-screen on unknown routes
- Navigating to a non-existent thread/setup shows appropriate error
Scripts
Add to package.json:
"test:e2e": "bunx playwright test""test:e2e:ui": "bunx playwright test --ui"(for debugging)
Files to .gitignore
e2e/test.dbtest-results/playwright-report/
Commit Strategy
- Unit tests for parseId, rate limiter, route params
- Playwright setup (install, config, seed, global-setup)
- Playwright E2E test files