Testing Guide
Drop Testing Guide
Last updated: 2026-03-03
Source: src/drop-app/vitest.config.ts, playwright.config.ts, package.json, tests/
Test Frameworks
| Framework | Version | Type | Config |
|---|---|---|---|
| Vitest | ^4.0.18 | Unit, Integration, Performance, Regression | vitest.config.ts |
| Playwright | ^1.58.2 | E2E (browser) | playwright.config.ts |
Prerequisites
Docker is required. Tests run against a real PostgreSQL 16 instance (port 5433). There is no in-memory SQLite fallback.
# One-time setup (first time or after fresh clone)
make db-test-setup
# This: starts Docker, creates drop_test DB, enables pgcrypto, pushes Drizzle schema
The DATABASE_URL for tests is set automatically by tests/setup.ts:
postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test
Running Tests
Unit + Integration Tests (Vitest)
# Recommended: via Makefile (handles Docker + DATABASE_URL automatically)
make test
# Direct run (Docker must already be up)
cd src/drop-app && DATABASE_URL=postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test npx vitest run
# Watch mode (development)
cd src/drop-app && DATABASE_URL=postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test npx vitest
# Run specific test file
cd src/drop-app && DATABASE_URL=postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test npx vitest run tests/integration/api-endpoints.test.ts
# Run with coverage
cd src/drop-app && DATABASE_URL=postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test npx vitest run --coverage
Configuration (vitest.config.ts):
- Environment:
node - Test pattern:
tests/**/*.test.ts - Setup file:
tests/setup.ts(setsNODE_ENV=test, setsDATABASE_URL) - Path alias:
@->./src fileParallelism: false— tests run sequentially to avoid PostgreSQL race conditions
E2E Tests (Playwright)
# Run all E2E tests
npx playwright test
# Run specific project
npx playwright test --project=user-flows
npx playwright test --project=full-flows
npx playwright test --project=input-chaos
# Run with UI mode
npx playwright test --ui
# View HTML report
npx playwright show-report
Configuration (playwright.config.ts:3-38):
- Serial execution (1 worker) to avoid rate limit conflicts
- Auto-starts dev server (
npm run dev) if not running - HTML reporter
- Trace on first retry (CI mode: 2 retries)
Test Architecture
Setup
File: tests/setup.ts
Sets NODE_ENV=test and DATABASE_URL=postgresql://drop:dev_only_not_a_secret@localhost:5433/drop_test for all Vitest tests.
Database Strategy (PostgreSQL — ADR-014)
All integration tests use a shared PostgreSQL test helper (tests/helpers/pg-test-db.ts):
- Connects to the real
drop_testdatabase on port 5433 - Runs Drizzle schema push once before each test suite
- Truncates all tables between tests for isolation
- No in-memory SQLite — full test/prod parity
// Integration test pattern (post-migration)
import { getTestDb, cleanupTestDb } from "../helpers/pg-test-db";
import { db } from "@/lib/db";
beforeAll(async () => { await getTestDb(); });
afterEach(async () => { await cleanupTestDb(); });
Unit tests that test pure logic (validation, auth utilities) mock @/lib/db directly without a real DB connection.
Note: better-sqlite3 has been removed. There is no new Database(":memory:") pattern anymore.
E2E Test Helpers
File: tests/e2e/input-chaos.spec.ts:21-42
loginAsDemo(page) -- Mocks the /api/auth/me endpoint to bypass rate limiting in chaos tests. Returns a pre-authenticated user object.
CHAOS_STRINGS -- Dictionary of malicious/edge-case inputs used across E2E tests:
- Empty, spaces, XSS, SQL injection, HTML injection
- Unicode, RTL override, null bytes
- Very long strings (10K chars)
- Norwegian (aeoa), Bosnian (sdccz), Japanese characters
- Zalgo text, special characters
Writing Tests
Integration Test Pattern (PostgreSQL)
import { describe, it, expect, beforeAll, afterEach } from "vitest";
import { getTestDb, cleanupTestDb } from "../helpers/pg-test-db";
// DATABASE_URL is set by tests/setup.ts — no manual config needed
describe("Feature", () => {
beforeAll(async () => {
await getTestDb(); // Ensure schema is pushed to drop_test
});
afterEach(async () => {
await cleanupTestDb(); // Truncate all tables between tests
});
it("does something with DB", async () => {
// Arrange, Act, Assert against real PostgreSQL
});
});
Unit Test Pattern (pure logic, no DB)
import { describe, it, expect, vi } from "vitest";
// Mock @/lib/db entirely for pure unit tests
vi.mock("@/lib/db", () => ({
db: { select: vi.fn(), insert: vi.fn() },
}));
describe("Feature", () => {
it("validates input", () => {
// Arrange, Act, Assert — no DB needed
});
});
E2E Test Pattern
import { test, expect } from "@playwright/test";
test.describe.configure({ mode: "serial" }); // Avoid rate limits
test.describe("Feature", () => {
test("user flow", async ({ page }) => {
await page.goto("http://localhost:3000/login");
await page.locator('input[type="email"]').fill("[email protected]");
await page.locator('input[type="password"]').fill("demo1234");
await page.locator('button[type="submit"]').click();
await page.waitForURL("**/dashboard", { timeout: 15000 });
});
});
Test Results
Current status (2026-03-03): Migrated to PostgreSQL. All tests run against drop_test on port 5433.
Vitest
# Run: make test
# All test files use PostgreSQL — no SQLite, no better-sqlite3
Playwright
- 3 test projects configured:
user-flows,full-flows,input-chaos input-chaosdepends onuser-flows
Test Coverage Areas
| Area | Unit | Integration | E2E | Performance |
|---|---|---|---|---|
| Password hashing (bcrypt) | auth.test.ts | api-routes.test.ts | -- | api-benchmarks.test.ts |
| JWT sign/verify | auth.test.ts | -- | -- | -- |
| Rate limiting | middleware.test.ts | api-routes.test.ts | user-flows.spec.ts | api-benchmarks.test.ts |
| Input validation | validation.test.ts | -- | input-chaos.spec.ts | -- |
| Database schema | db.test.ts | api-endpoints.test.ts | -- | -- |
| Feature flags | feature-flags.test.ts | -- | -- | -- |
| Utility functions | utils.test.ts | -- | -- | -- |
| Registration flow | -- | api-endpoints.test.ts | user-flows.spec.ts | -- |
| Login flow | -- | api-endpoints.test.ts | user-flows.spec.ts | -- |
| Remittance | -- | api-endpoints.test.ts | full-flows.spec.ts | -- |
| QR Payment | -- | api-endpoints.test.ts | full-flows.spec.ts | -- |
| XSS/SQLi prevention | validation.test.ts | -- | input-chaos.spec.ts | -- |
| Session management | -- | api-routes.test.ts | full-flows.spec.ts | -- |
| Known bug regressions | -- | known-bugs.test.ts | -- | -- |