Skip to main content

api-test

Generate an integration test for an API route with all required mocks and boilerplate. Use when creating tests for API endpoints.

インストールへ移動

ソース情報

リポジトリ
ahembree/librariarr
ソースの最終更新活動
2026年6月13日 20:16
検出された SKILL.md の言語
英語
スター
5
フォーク
1

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
api-test
description
Generate an integration test for an API route with all required mocks and boilerplate. Use when creating tests for API endpoints.
argument-hint
<route-import-path>
# Integration Test Generator Generate an integration test for the API route at `$ARGUMENTS`. ## Required Boilerplate (copy exactly) ### File header — imports and standard mocks: ```typescript import { describe, it, expect, beforeEach, afterAll, vi } from "vitest"; import { cleanDatabase, disconnectTestDb } from "../../setup/test-db"; import { setMockSession, clearMockSession } from "../../setup/mock-session"; import { callRoute, callRouteWithParams, expectJson, createTestUser, // Add other factories as needed: // createTestServer, createTestLibrary, createTestMediaItem, // createTestRuleSet, createTestSonarrInstance, createTestRadarrInstance, // createTestLidarrInstance, createTestSeerrInstance, createTestExternalId, // createTestLogEntry, createTestMediaStream } from "../../setup/test-helpers"; // Redirect prisma to test database — MUST come before route imports vi.mock("@/lib/db", async () => { const { getTestPrisma } = await import("../../setup/test-db"); return { prisma: getTestPrisma() }; }); // Suppress logger DB writes vi.mock("@/lib/logger", () => ({ logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() }, apiLogger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() }, dbLogger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() }, })); ``` ### External service mocks (if needed): ```typescript // CRITICAL: Constructor mocks MUST use function() keyword, NOT arrow functions const mockTestConnection = vi.fn(); vi.mock("@/lib/arr/sonarr-client", () => ({ SonarrClient: vi.fn().mockImplementation(function () { return { testConnection: mockTestConnection }; }), })); ``` ### vi.hoisted() pattern — use when mock variables are referenced inside vi.mock() factories: ```typescript const { mockFn } = vi.hoisted(() => ({ mockFn: vi.fn(), })); vi.mock("@/lib/some-module", () => ({ someFunction: mockFn, })); ``` ### Route imports — MUST come AFTER all vi.mock() calls: ```typescript import { GET, POST } from "@/app/api/path/to/route"; ``` ### Lifecycle hooks: ```typescript describe("API endpoint description", () => { beforeEach(async () => { await cleanDatabase(); clearMockSession(); vi.clearAllMocks(); }); afterAll(async () => { await disconnectTestDb(); }); // tests go here }); ``` ## Standard Test Cases ### For every route — 401 unauthorized: ```typescript it("returns 401 when not authenticated", async () => { const response = await callRoute(GET); await expectJson(response, 401); }); ``` ### GET list endpoints: ```typescript it("returns empty array when user has no data", async () => { const user = await createTestUser(); setMockSession({ userId: user.id, plexToken: "tok", isLoggedIn: true }); const response = await callRoute(GET); const body = await expectJson<{ items: unknown[] }>(response, 200); expect(body.items).toEqual([]); }); it("returns data belonging to authenticated user", async () => { const user = await createTestUser(); setMockSession({ userId: user.id, plexToken: "tok", isLoggedIn: true }); // Create test data... const response = await callRoute(GET); const body = await expectJson<{ items: unknown[] }>(response, 200); expect(body.items).toHaveLength(1); }); it("does not return data belonging to another user", async () => { const user1 = await createTestUser(); const user2 = await createTestUser({ data: { plexId: "other", plexUsername: "other" } }); // Create data for user2... setMockSession({ userId: user1.id, plexToken: "tok", isLoggedIn: true }); const response = await callRoute(GET); const body = await expectJson<{ items: unknown[] }>(response, 200); expect(body.items).toHaveLength(0); }); ``` ### POST endpoints: ```typescript it("returns 400 with invalid body", async () => { const user = await createTestUser(); setMockSession({ userId: user.id, plexToken: "tok", isLoggedIn: true }); const response = await callRoute(POST, { body: {} }); await expectJson(response, 400); }); it("creates resource with valid data", async () => { const user = await createTestUser(); setMockSession({ userId: user.id, plexToken: "tok", isLoggedIn: true }); const response = await callRoute(POST, { body: { name: "Test", /* fields */ }, }); const body = await expectJson<{ item: { id: string } }>(response, 201); expect(body.item.id).toBeDefined(); }); ``` ### PUT/DELETE with [id] — ownership check: ```typescript it("returns 404 when resource belongs to another user", async () => { const user1 = await createTestUser(); const user2 = await createTestUser({ data: { plexId: "other", plexUsername: "other" } }); // Create resource owned by user2... setMockSession({ userId: user1.id, plexToken: "tok", isLoggedIn: true }); const response = await callRouteWithParams(DELETE, { id: resource.id }); await expectJson(response, 404); }); ``` ## Route Handler Invocation - Simple routes: `callRoute(GET)` or `callRoute(POST, { body: { ... } })` - With URL: `callRoute(GET, { url: "/api/path?param=value" })` - Dynamic params: `callRouteWithParams(PUT, { id: "abc" }, { body: { ... } })` - Assert response: `const body = await expectJson<{ key: Type }>(response, 200);` ## Steps 1. Read the route file to identify which HTTP methods it exports 2. Check imports for external services that need mocking (Plex, Sonarr, Radarr, etc.) 3. Identify which data factories are needed based on Prisma models used 4. Create test file at `tests/integration/<category>/<name>.test.ts` 5. Include all standard test cases plus route-specific edge cases 6. Run the test to verify: `pnpm exec vitest run tests/integration/<category>/<name>.test.ts`
GitHubで見る