__tests__
Test suite covering unit, integration, end-to-end, and code quality tests.
Test Suite (__tests__/)
Test suite covering unit, integration, end-to-end, and code quality tests.
Purpose
Ensures codebase quality, correctness, and maintainability through:
- Unit Tests: Isolated component and function testing
- Integration Tests: Multi-component workflows
- End-to-End Tests: Full user journeys via browser automation
- Code Quality Tests: Enforce architectural and documentation standards
Test Structure
__tests__/
βββ code-quality/ # Code standards and architectural rules
β βββ documentation-quality.test.ts
β βββ no-dynamic-imports.test.ts
β βββ readme-coverage.test.ts
βββ e2e/ # Browser-based end-to-end tests
β βββ acceptance.spec.ts
β βββ accessibility.spec.ts
β βββ edge-cases.spec.ts
β βββ theme-toggle.spec.ts
βββ helpers/ # Test utilities and fixtures
βββ fake-services.ts
βββ fake-services.test.ts
βββ test-data-generators.ts
βββ test-data-generators.test.ts
Test Philosophy
Unit Tests (Co-located)
Most unit tests live next to their source files:
src/domain/entities/municipality.ts
src/domain/entities/municipality.test.ts β Unit test
src/adapters/cache/in-memory-cache.ts
src/adapters/cache/in-memory-cache.test.ts β Unit test
Benefits:
- Easy to find related tests
- Clear ownership and responsibility
- Faster test discovery during development
Integration Tests (Feature-based)
Integration tests live in __tests__/ when they:
- Span multiple modules
- Test full workflows
- Require complex setup/teardown
E2E Tests (Browser-based)
Playwright tests in __tests__/e2e/ simulate real user interactions:
- Navigate actual routes
- Fill forms and click buttons
- Verify rendered output
- Test accessibility
Code Quality Tests
Enforce non-negotiable standards:
- Documentation coverage (every directory has README)
- No dynamic imports (performance and security)
- Consistent coding patterns
Test Coverage
Current coverage: 99.97% line coverage, 99.84% function coverage
Coverage by Layer
| Layer | Line Coverage | Function Coverage |
|---|---|---|
| Domain Entities | 100% | 100% |
| Domain Use Cases | 100% | 100% |
| Domain Errors | 100% | 100% |
| Adapters | 99.5% | 99.8% |
| Lib (Utilities) | 100% | 100% |
| App (Server Actions) | 98% | 98% |
Uncovered Code
The 0.03% uncovered lines are:
- Unreachable code required by TypeScript type checker
- Marked with comments explaining why they're unreachable
Running Tests
# Run all tests
bun run test
# Run unit tests only (co-located + helpers)
bun run test --exclude e2e
# Run E2E tests
bun run test:e2e
# Run code quality tests
bun run test code-quality/
# Run with coverage
bun run test --coverage
# Watch mode
bun run test --watch
# Specific test file
bun run test municipality.test.ts
# Run tests matching pattern
bun run test geocoding
Test Utilities
Fake Services (helpers/fake-services.ts)
Fake implementations (not mocks) for testing without external dependencies:
import {
createFakeGeocodingService,
createFakeCache,
} from "@/__tests__/helpers/fake-services";
// Returns predictable results without API calls
const geocoder = createFakeGeocodingService();
const result = await geocoder.geocodeAddress(address);
// In-memory cache for testing
const cache = createFakeCache();
await cache.set("key", "value");
Why Fakes vs Mocks?
- Fakes have working implementations
- Tests verify actual behavior, not just method calls
- More resilient to refactoring
Test Data Generators (helpers/test-data-generators.ts)
Concise generators for creating test data:
import {
genAddress,
genMunicipality,
genGeocodingResult,
} from "@/__tests__/helpers/test-data-generators";
// Generate test address (uses real NJ addresses)
const address = genAddress(REAL_NJ_ADDRESSES.njit);
// Generate municipality
const municipality = genMunicipality("Newark", "Essex", "City");
// Generate geocoding result
const result = genGeocodingResult({ municipality });
Real NJ Addresses:
Test data uses actual NJ government addresses:
- NJIT: 323 Dr Martin Luther King Jr Blvd, Newark
- State House: 125 West State Street, Trenton
- Drumthwacket: 354 Stockton Street, Princeton
- Rutgers: 83 Somerset Street, New Brunswick
- NJCU: 2039 John F Kennedy Boulevard, Jersey City
This ensures tests work with real geocoding API responses.
Test Patterns
Unit Test Pattern
import { expect, test, describe } from "bun:test";
describe("createMunicipality", () => {
test("should create valid municipality", () => {
const muni = createMunicipality({
name: "Newark",
county: "Essex",
type: "City",
});
expect(muni.name).toBe("Newark");
expect(muni.county).toBe("Essex");
expect(muni.type).toBe("City");
});
test("should reject invalid input", () => {
expect(() =>
createMunicipality({ name: "", county: "Essex", type: "City" }),
).toThrow();
});
});
Integration Test Pattern
test("should lookup address with cache", async () => {
const cache = createFakeCache();
const geocoder = createFakeGeocodingService();
const useCase = createLookupAddressUseCase(geocoder, cache);
const address = genAddress();
const result = await useCase.execute(address);
expect(result.municipality.name).toBe("Newark");
expect(result.fromCache).toBe(false);
// Second call should hit cache
const cachedResult = await useCase.execute(address);
expect(cachedResult.fromCache).toBe(true);
});
E2E Test Pattern
import { test, expect } from "@playwright/test";
test("should display municipality on successful lookup", async ({ page }) => {
await page.goto("/lookup");
await page
.getByRole("textbox", { name: /street/i })
.fill("323 Dr Martin Luther King Jr Blvd");
await page.getByRole("textbox", { name: /city/i }).fill("Newark");
await page.getByRole("textbox", { name: /zip/i }).fill("07102");
await page.getByRole("button", { name: /lookup/i }).click();
await expect(page.getByText(/municipality/i)).toBeVisible();
await expect(page.getByText(/newark/i)).toBeVisible();
await expect(page.getByText(/essex/i)).toBeVisible();
});
Continuous Integration
Tests run on every commit via GitHub Actions:
- name: Run tests
run: bun run test --coverage
- name: Run E2E tests
run: bun run test:e2e
- name: Check coverage threshold
run: bun coverage --check-coverage --lines 95
Related Documentation
- Code Quality Tests - Architectural and standards enforcement
- E2E Tests - Browser-based acceptance tests
- Test Helpers - Utilities and fixtures
- Domain Tests - Domain layer testing approach
- Adapter Tests - Adapter testing patterns