Skip to content

Testing

Technical reference for the helldivers.bot testing infrastructure. Audience: project owner and AI assistants.


Overview

The project uses Vitest for all tests, with two separate configs:

  • Unit tests (vitest.config.mjs) — utilities, validators, API route handlers, queries, features, and shared modules
  • Smoke tests (vitest.smoke.config.mjs) — HTTP-level checks against a running dev server

Tests live in src/__tests__/ following conventions from the euraika/aegis projects.

graph TD
    subgraph Unit["VITEST UNIT TESTS"]
        UTILS["src/__tests__/unit/utils/"]
        VALS["src/__tests__/unit/validators/"]
        SHARED["src/__tests__/unit/shared/"]
        QUERIES["src/__tests__/unit/queries/"]
        ROUTES["src/__tests__/unit/routes/"]
        FEATURES["src/__tests__/unit/features/"]
        DB["src/__tests__/unit/db/"]
        UPDATE["src/__tests__/unit/update/"]
        APP["src/__tests__/unit/app/"]
    end

    subgraph Smoke["VITEST SMOKE TESTS"]
        SMOKETEST["smoke.test.mjs<br/><small>Page loads + API checks</small>"]
    end

    subgraph Mocks["GLOBAL MOCKS (vitest.setup.mjs)"]
        AUTH_M["BetterAuth mock<br/><small>null session default</small>"]
        PRISMA_M["Prisma mock<br/><small>All model CRUD stubs</small>"]
        NEXT_M["Next.js mocks<br/><small>navigation, headers, image</small>"]
    end

    subgraph Utils["TEST UTILITIES (@test-utils)"]
        MR["createMockRequest()"]
        MS["createMockSession()"]
        MM["createMockModel()"]
    end

    Mocks --> Unit
    Utils --> Unit
    SMOKETEST -->|"http://localhost:3000"| DEV["Dev Server"]

    style Unit fill:#0f1a0f,stroke:#22c55e,color:#4ade80
    style Smoke fill:#1e293b,stroke:#3b82f6,color:#60a5fa
    style Mocks fill:#1c1917,stroke:#f59e0b,color:#fbbf24
    style Utils fill:#1a1a2e,stroke:#a855f7,color:#c084fc

Directory Structure

src/__tests__/
├── unit/                    # Vitest unit tests
│   ├── app/                 # Tests for App Router routes (e.g. api/h1/live)
│   ├── db/                  # Tests for src/db/* helpers
│   ├── features/            # Tests for src/features/* (archives, galaxy, stats, timeline, admin)
│   ├── queries/             # Tests for src/db/queries/*
│   ├── routes/              # Tests for API route handlers
│   ├── shared/              # Tests for src/shared/* (enums, hooks, utils)
│   ├── update/              # Tests for update pipeline (season, status, fetch, push)
│   ├── utils/               # Tests for src/utils/* (admin, format)
│   └── validators/          # Tests for src/validators/*
├── smoke/                   # Vitest smoke tests (against running dev server)
│   └── smoke.test.mjs       # Page loads + API endpoint checks
└── utils/                   # Shared test utilities
    └── index.mjs            # Mock factories and helpers

Root-level config files:

FilePurpose
vitest.config.mjsVitest unit test config (env, aliases, coverage)
vitest.setup.mjsGlobal mocks (auth, Prisma, Next.js modules)
vitest.smoke.config.mjsVitest smoke test config (30s timeout, node env)

NPM Scripts

ScriptDescription
npm testRun unit tests then smoke tests sequentially
npm run test:unitVitest single run (unit tests only)
npm run test:coverageVitest with v8 coverage report
npm run test:e2eSmoke tests via vitest.smoke.config.mjs

Note: Smoke tests require a running dev server at http://localhost:3000. Never start the dev server from Claude — ask the user.


Vitest Configuration

Environment: node (default). Component tests opt in to jsdom via per-file comment:

// @vitest-environment jsdom

Globals: truedescribe, test, expect, vi are available without import.

Path aliases:

  • @./src (matches jsconfig.json)
  • @test-utils./src/__tests__/utils

Coverage:

  • Provider: v8
  • Reporters: text, html
  • Excludes: src/generated/**, test files, src/__tests__/**, malformed enum files

No global thresholds are set yet — add them once meaningful coverage exists.


Global Mocks (vitest.setup.mjs)

The setup file runs before each test file and provides mocks for:

BetterAuth

// Default: logged out (null session)
// Override in tests:
import { auth } from '@/auth';
vi.mocked(auth.api.getSession).mockResolvedValue(createMockSession());

Prisma Client

All models from the schema are mocked with stub CRUD methods (findMany, findUnique, create, update, delete, etc.). The mock targets @/db/db (the singleton export).

import db from '@/db/db';
vi.mocked(db.h1_season.findMany).mockResolvedValue([{ id: 1, season: 1 }]);

Next.js Modules

  • next/navigationuseRouter, usePathname, useSearchParams, redirect, notFound
  • next/headersheaders, cookies
  • next/image — passthrough (no optimization)
  • next/link — passthrough

All mocks are cleared via vi.clearAllMocks() in beforeEach.


Test Utilities

Location: src/__tests__/utils/index.mjs (importable as @test-utils)

createMockRequest(url, method, body, headers)

Wraps new Request() for API route handler tests. Sets content-type: application/json by default.

createMockSession(overrides)

Returns a BetterAuth session object with user and session sub-objects (test user, 24h expiry). Merge overrides for custom scenarios.

createMockModel()

Returns a Prisma model stub with all standard CRUD methods as vi.fn(). Useful for ad-hoc mocks beyond what vitest.setup.mjs provides.


Test Naming Conventions

TypePatternLocation
Unit test*.test.mjssrc/__tests__/unit/
Smoke test*.test.mjssrc/__tests__/smoke/
Test utility*.mjssrc/__tests__/utils/

API Route Testing Pattern

App Router route handlers are tested by importing the handler directly:

import { GET } from '@/app/api/healthcheck/route';

test('returns 200 with alive: true', async () => {
    const req = new Request('http://localhost/api/healthcheck');
    const res = await GET(req);
    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body.alive).toBe(true);
});

For routes that depend on Prisma or auth, mock those modules first — the global mocks in vitest.setup.mjs handle the defaults.


Smoke Test Configuration

Smoke tests use a separate Vitest config (vitest.smoke.config.mjs) — not Playwright.

  • Test directory: src/__tests__/smoke/
  • Config: vitest.smoke.config.mjs
  • Timeout: 30 seconds per test (network requests to running dev server)
  • Base URL: http://localhost:3000

Gitignore

Test artifacts are excluded from version control:

/coverage            # Vitest coverage reports
/test-results/       # Legacy Playwright output
/playwright-report/  # Playwright HTML report
/playwright/         # Playwright screenshots & artifacts
.playwright-mcp/     # Playwright MCP state