9.8 KiB
9.8 KiB
Testing Patterns
Analysis Date: 2026-04-18
Test Framework
Runner:
vitestviavitest.config.ts.package.jsondeclaresvitestindevDependenciesand exposespnpm test.- Verified on 2026-04-18:
pnpm testexecuted with Vitestv2.1.9and passed all current test files.
Assertion Library:
- Vitest built-ins:
describe,it,expect,beforeEach, andvi, as seen insrc/lib/auth.test.ts,src/lib/validations.test.ts, andsrc/app/api/tags/maintenance/route.test.ts.
Config:
vitest.config.tssetsenvironment: "node", aliases@to./src, disables watch mode, and includes onlysrc/**/*.test.ts.- No separate setup file, coverage config, browser environment, or integration test project was detected in
vitest.config.ts.
Run Commands:
pnpm test # Run all configured Vitest suites
pnpm lint # Run ESLint quality checks
pnpm build # Run production build, lint, and type validation
Test File Organization
Location:
- Tests are co-located beside the source they exercise.
- Library tests live next to utilities, for example
src/lib/auth.test.ts,src/lib/validations.test.ts, andsrc/lib/validations.tag-maintenance.test.ts. - API tests live next to route or service modules, for example
src/app/api/tags/route.test.ts,src/app/api/tags/reset-projects/route.test.ts,src/app/api/tags/maintenance/route.test.ts, andsrc/app/api/tags/maintenance/service.test.ts.
Naming:
- Use
*.test.ts. No*.spec.tsfiles were detected undersrcon 2026-04-18. - The include pattern in
vitest.config.tsmeans*.test.tsxand files outsidesrcare not picked up by default.
Structure:
src/
lib/
auth.ts
auth.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(() => {
// create hoisted mocks here
});
vi.mock("@/lib/prisma", () => ({ prisma: { $transaction: transactionMock } }));
vi.mock("next/cache", () => ({ revalidatePath: revalidatePathMock }));
function buildRequest(body: unknown): NextRequest {
return new NextRequest("http://localhost:3000/api/tags/maintenance", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
}
describe("POST /api/tags/maintenance", () => {
beforeEach(() => {
process.env.WEBHOOK_API_KEY = "k".repeat(32);
vi.clearAllMocks();
});
it("returns 401 for wrong API key", async () => {
const response = await POST(buildRequest({ apiKey: "a".repeat(32), updates: [], merges: [] }));
expect(response.status).toBe(401);
});
});
Patterns:
- Use a top-level
describe(...)per module or endpoint, with test names phrased as behavior statements. - Reset spies and mock state in
beforeEach, as insrc/app/api/tags/route.test.ts,src/app/api/tags/reset-projects/route.test.ts, andsrc/app/api/tags/maintenance/route.test.ts. - For API routes, call the exported
GETorPOSTfunction directly and assert on bothresponse.statusandawait response.json(). - For pure helpers and schemas, call the function directly and assert return values or thrown errors, as in
src/lib/auth.test.tsandsrc/lib/validations.test.ts.
Mocking
Framework:
- Vitest mocking via
vi.mock,vi.fn,vi.hoisted,mockResolvedValue, andmockRejectedValue.
Patterns:
const { findManyMock } = vi.hoisted(() => ({
findManyMock: vi.fn(),
}));
vi.mock("@/lib/prisma", () => ({
prisma: {
tag: {
findMany: findManyMock,
},
},
}));
findManyMock.mockResolvedValue([
{
id: "tag-1",
name: "机器学习",
slug: "machine-learning",
_count: { projects: 4 },
},
]);
vi.mock("next/cache", () => ({
revalidatePath: revalidatePathMock,
}));
What to Mock:
- Mock Prisma client calls for route and service tests instead of hitting a real database. This is the established pattern in
src/app/api/tags/route.test.ts,src/app/api/tags/reset-projects/route.test.ts, andsrc/app/api/tags/maintenance/route.test.ts. - Mock Next.js side effects such as
revalidatePathwhen testing mutation endpoints, as insrc/app/api/tags/reset-projects/route.test.tsandsrc/app/api/tags/maintenance/route.test.ts. - Set environment variables inline per suite when auth behavior depends on them, as in
process.env.WEBHOOK_API_KEYusage insrc/app/api/tags/reset-projects/route.test.tsandsrc/app/api/tags/maintenance/route.test.ts.
What NOT to Mock:
- Do not mock pure validation or auth utilities when they can be tested directly.
src/lib/auth.test.tsandsrc/lib/validations.tag-maintenance.test.tsexercise real implementation logic without mocks. - There is no current pattern for browser, React component, or DOM mocking because no component tests are checked in.
Fixtures and Helpers
Test Data:
function buildValidPayload(apiKey: string) {
return {
apiKey,
projects: [
{
projectSlug: "project-one",
selectedTagSlugsByCategory: {
FIXED_PROJECT_TYPE: ["agent-tooling"],
TECH_STACK: ["typescript"],
AI_PARADIGM: ["ai-agents"],
PRODUCT_FORM: ["web-application"],
DOMAIN_SCENARIO: ["code-dev"],
},
},
],
};
}
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" }],
};
Location:
- Builders and fixtures are defined inline in each test file. No shared
test-utils, factory module, or fixture directory was detected undersrcor repository root. - Reuse small local helpers such as
buildRequest,buildValidPayload,createTxMock, andbaseProjectInputinstead of creating cross-suite abstractions.
Coverage
Requirements:
- No coverage thresholds or coverage command are configured in
package.jsonorvitest.config.ts. - No CI coverage upload or report configuration was detected.
View Coverage:
Not configured
Test Types
Unit Tests:
- Pure utility tests cover security and schema logic in
src/lib/auth.test.ts,src/lib/validations.test.ts, andsrc/lib/validations.tag-maintenance.test.ts. - Service-level unit tests cover tag maintenance merge behavior in
src/app/api/tags/maintenance/service.test.ts.
Route-Level Tests:
- Route handler tests call Next.js App Router handlers directly with mocked dependencies in
src/app/api/tags/route.test.ts,src/app/api/tags/reset-projects/route.test.ts, andsrc/app/api/tags/maintenance/route.test.ts. - These are closer to isolated handler tests than full integration tests because Prisma and cache modules are mocked.
Integration Tests:
- Not detected. No test currently exercises a real Prisma client, live database, or full Next.js server.
E2E Tests:
- Not detected in the repository. No
e2e/directory and noplaywright.config.*file were found on 2026-04-18. - Repository guidance mentions
pnpm test:e2e, butpackage.jsondoes not define that script. Treat E2E support as undocumented or not yet checked in.
Common Patterns
Async 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");
await expect(
executeTagMaintenance(tx as Parameters<typeof executeTagMaintenance>[0], {
updates: [{ tagId: "missing-tag", nameEn: "Missing" }],
merges: [],
})
).rejects.toMatchObject({
status: 400,
message: "Validation error",
});
Current Gaps
Untested Server Modules:
- No tests were detected for
src/app/api/projects/route.ts,src/app/api/projects/[slug]/route.ts,src/app/api/search/ai/route.ts,src/app/api/signals/route.ts, orsrc/app/api/webhook/signals/route.ts. - 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, orsrc/lib/github/badges.ts.
Untested UI:
- No component tests were detected for large client components such as
src/app/[locale]/projects/ProjectsResultsClient.tsx(784 lines),src/components/project/TagFilterPanel.tsx(698 lines), orsrc/components/signals/SignalFeedClient.tsx(603 lines). - No tests were detected for route pages under
src/app/[locale].
Test Infrastructure Gaps:
- No shared test helpers, factories, or fixture libraries are present.
- No browser or DOM test environment is configured.
- No E2E harness or Playwright configuration is present.
- No CI workflow files were detected under
.github/.
Verification Signals
Current Quality Checks:
pnpm testpassed on 2026-04-18 with 7 test files and 24 tests passing.pnpm lintpassed on 2026-04-18 with no warnings or errors.pnpm buildpassed on 2026-04-18. The build completed static generation and route analysis successfully.
Observed Test Output Notes:
pnpm testprints expected stderr from the error-path test insrc/app/api/tags/route.test.tsbecausesrc/app/api/tags/route.tslogs withconsole.error.- Vitest emitted a Vite deprecation notice about the CJS Node API during the run. This is a tooling signal, not a failing test.
Testing analysis: 2026-04-18