Files
agent-park/.planning/codebase/TESTING.md
T
2026-04-20 18:59:15 +08:00

8.9 KiB

Testing Patterns

Analysis Date: 2026-04-20

Test Framework

Runner:

  • Use vitest via vitest.config.ts and pnpm test from package.json.
  • vitest.config.ts sets environment: "node", resolves @ to ./src, disables watch mode, and only includes src/**/*.test.ts.
  • Current verification on 2026-04-20: pnpm test passed with 8 test files and 26 tests.

Assertion Library:

  • Use Vitest built-ins from vitest, including describe, it, expect, beforeEach, afterEach, and vi, as seen in src/lib/auth.test.ts, src/lib/prisma-url.test.ts, and src/app/api/tags/maintenance/route.test.ts.

Run Commands:

pnpm test              # Run all configured Vitest suites
pnpm lint              # Run ESLint quality checks
pnpm build             # Run production build checks
  • AGENTS.md also reserves pnpm test:e2e for Playwright, but no test:e2e script or playwright.config.* file is present in the current workspace.

Test File Organization

Location:

  • Keep tests co-located beside the code they exercise under src, for example src/lib/auth.test.ts, src/lib/prisma-url.test.ts, src/app/api/tags/route.test.ts, and src/app/api/tags/maintenance/service.test.ts.
  • No e2e/ directory is present in the repository snapshot analyzed on 2026-04-20.

Naming:

  • Use *.test.ts. No *.spec.ts or *.test.tsx files were detected by rg --files or included by vitest.config.ts.
  • Keep route tests adjacent to route.ts or service.ts files, for example src/app/api/tags/reset-projects/route.test.ts next to src/app/api/tags/reset-projects/route.ts.

Structure:

src/
  lib/
    auth.ts
    auth.test.ts
    prisma-url.ts
    prisma-url.test.ts
  app/api/tags/
    route.ts
    route.test.ts
    maintenance/
      route.ts
      route.test.ts
      service.ts
      service.test.ts

Test Structure

Suite Organization:

import { beforeEach, describe, expect, it, vi } from "vitest";
import { NextRequest } from "next/server";
import { POST } from "./route";

const { transactionMock, revalidatePathMock, txMock } = vi.hoisted(() => {
  const tx = {
    projectTag: {
      deleteMany: vi.fn(),
      createMany: vi.fn(),
    },
  };

  return {
    transactionMock: vi.fn(async (callback) => callback(tx)),
    revalidatePathMock: vi.fn(),
    txMock: tx,
  };
});

Patterns:

  • Use one top-level describe(...) block per module or endpoint, with behavior-based test names such as returns 401 for wrong API key in src/app/api/tags/maintenance/route.test.ts and returns 500 when prisma query fails in src/app/api/tags/route.test.ts.
  • Build local request helpers for route tests, such as buildRequest(...) in src/app/api/tags/maintenance/route.test.ts and src/app/api/tags/reset-projects/route.test.ts.
  • Use inline fixture builders for reusable payloads, such as buildValidPayload(...) in src/app/api/tags/reset-projects/route.test.ts and baseProjectInput in src/lib/validations.test.ts.
  • Reset mocks and environment state in beforeEach or afterEach, as seen in src/app/api/tags/route.test.ts, src/app/api/tags/maintenance/route.test.ts, and src/lib/prisma-url.test.ts.

Mocking

Framework:

  • Use Vitest mocks via vi.fn, vi.mock, vi.hoisted, mockResolvedValue, and mockRejectedValue.

Patterns:

vi.mock("@/lib/prisma", () => ({
  prisma: {
    tag: {
      findMany: findManyMock,
    },
  },
}));

vi.mock("next/cache", () => ({
  revalidatePath: revalidatePathMock,
}));
  • Hoist shared mocks before module import so route modules capture mocked dependencies, as in src/app/api/tags/route.test.ts, src/app/api/tags/maintenance/route.test.ts, and src/app/api/tags/reset-projects/route.test.ts.
  • Mock Prisma reads and writes rather than using a real database in route tests.
  • Mock next/cache side effects when mutation routes call revalidatePath, as in src/app/api/tags/maintenance/route.test.ts and src/app/api/tags/reset-projects/route.test.ts.

What to Mock:

  • Mock Prisma modules for handler and service tests, as in src/app/api/tags/route.test.ts, src/app/api/tags/maintenance/route.test.ts, and src/app/api/tags/reset-projects/route.test.ts.
  • Set process.env.WEBHOOK_API_KEY inline for auth-path tests, as in src/app/api/tags/maintenance/route.test.ts and src/app/api/tags/reset-projects/route.test.ts.
  • Mock cache revalidation side effects instead of asserting real filesystem or ISR behavior.

What NOT to Mock:

  • Test pure helpers directly without mocks when possible, as in src/lib/auth.test.ts and src/lib/validations.tag-maintenance.test.ts.
  • There is no current pattern for DOM, browser, or component mocking because no component tests are checked in.

Fixtures and Environment Handling

Test Data:

const baseProjectInput = {
  name: "Agent Park",
  description: "A curated list of practical AI agent tools.",
  tags: [{ name: "ai-agent" }],
  links: [{ type: "GITHUB" as const, url: "https://github.com/example/repo" }],
};
const ENV_KEYS = [
  "DATABASE_URL",
  "PG_SSL_ROOT_CERT_B64",
  "PG_SSL_IDENTITY_P12_B64",
  "PG_SSL_IDENTITY_PASSWORD",
  "PG_SSL_MODE",
  "PG_SSL_CERT_DIR",
] as const;
  • src/lib/prisma-url.test.ts snapshots selected env vars and restores them in afterEach, which is the current pattern for tests that mutate process.env.
  • Fixtures are inline per file. No shared test-utils or factory directory exists.

Coverage

Requirements:

  • No coverage thresholds or coverage command are configured in package.json or vitest.config.ts.
  • No CI workflow, coverage upload, or Playwright setup was detected under .github/ or repository root.

View Coverage:

Not configured

Test Types

Unit Tests:

  • Pure utility coverage exists for src/lib/auth.ts, src/lib/prisma-url.ts, src/lib/validations.ts, and tag-maintenance schema rules in src/lib/validations.tag-maintenance.test.ts.

Service Tests:

  • Business logic in src/app/api/tags/maintenance/service.ts is tested separately in src/app/api/tags/maintenance/service.test.ts, including deduped tag migration and validation failure behavior.

Route-Level Tests:

  • Direct route-handler tests exist for src/app/api/tags/route.ts, src/app/api/tags/maintenance/route.ts, and src/app/api/tags/reset-projects/route.ts.
  • These tests assert status codes, JSON bodies, auth failures, validation failures, and revalidatePath(...) side effects.

n8n-Related Coverage:

  • src/app/api/search/ai/route.ts has no corresponding src/app/api/search/ai/route.test.ts.
  • src/app/api/webhook/signals/route.ts has no corresponding src/app/api/webhook/signals/route.test.ts.
  • This means the n8n-facing search proxy and the authenticated signals webhook currently rely on runtime behavior rather than automated handler tests.

E2E Tests:

  • Not detected. AGENTS.md reserves e2e/ for Playwright, but there is no e2e/ directory, no Playwright config, and no pnpm test:e2e script in package.json.

Common Patterns

Async Route Testing:

const response = await POST(buildRequest(payload));
const json = await response.json();

expect(response.status).toBe(200);
expect(json.success).toBe(true);

Error Testing:

findManyMock.mockRejectedValue(new Error("db unavailable"));
const response = await GET();
const json = await response.json();

expect(response.status).toBe(500);
expect(json.error).toBe("Internal server error");
expect(json.details).toContain("db unavailable");

Current Gaps

Untested API Routes:

  • No tests were detected for src/app/api/projects/route.ts, src/app/api/projects/[slug]/route.ts, src/app/api/signals/route.ts, src/app/api/search/ai/route.ts, or src/app/api/webhook/signals/route.ts.
  • The missing n8n-related tests are especially important because src/app/api/search/ai/route.ts depends on the N8N_AI_SEARCH_WEBHOOK contract and src/app/api/webhook/signals/route.ts handles authenticated ingestion plus Prisma upserts.

Untested Query and UI Modules:

  • No tests were detected for src/hooks/useProjects.ts, src/hooks/useHome.ts, src/lib/cache.ts, src/lib/signal-hotness.ts, src/lib/tag-taxonomy.ts, src/lib/github/badges.ts, or large client components under src/components and src/app/[locale].

Infrastructure Gaps:

  • No shared fixture library, no DOM test environment, no Playwright harness, and no CI workflow files were detected.

Verification Signals

Current Quality Checks:

  • pnpm test passed on 2026-04-20 with 8 test files and 26 tests.
  • pnpm lint passed on 2026-04-20 with no warnings or errors.

Observed Output Notes:

  • pnpm test prints expected stderr from the deliberate error-path assertion in src/app/api/tags/route.test.ts because src/app/api/tags/route.ts logs failures with console.error.
  • The current Vitest run emits a Vite deprecation notice about the CJS Node API. This is a tooling signal, not a failing test.

Testing analysis: 2026-04-20