Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add sgcarstrends/sgcarstrends --skill "api-testing"
Install specific skill from multi-skill repository
# Description
Write and run API tests with Vitest for endpoints, middleware, and integrations. Use when testing API functionality, request/response validation, or error handling.
# SKILL.md
name: api-testing
description: Write and run API tests with Vitest for endpoints, middleware, and integrations. Use when testing API functionality, request/response validation, or error handling.
allowed-tools: Read, Edit, Write, Bash, Grep, Glob
API Testing Skill
Running Tests
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:coverage # With coverage
pnpm -F @sgcarstrends/web test # Run web tests
pnpm -F @sgcarstrends/web test:watch # Watch mode for web
Test Structure
apps/web/__tests__/
βββ setup.ts # Test setup
βββ helpers.ts # Test utilities
βββ queries/ # Query tests
βββ components/ # Component tests
βββ utils/ # Utility tests
Testing API Routes
Basic Endpoint Test
import { describe, it, expect } from "vitest";
describe("GET /api/health", () => {
it("returns 200 OK", async () => {
const res = await fetch("http://localhost:3000/api/health");
expect(res.status).toBe(200);
expect(await res.json()).toEqual({ status: "ok" });
});
});
Testing with Query Params
describe("GET /api/cars", () => {
it("filters by month", async () => {
const res = await fetch("http://localhost:3000/api/cars?month=2024-01");
expect(res.status).toBe(200);
});
it("returns 400 for invalid month", async () => {
const res = await fetch("http://localhost:3000/api/cars?month=invalid");
expect(res.status).toBe(400);
});
});
Testing POST Endpoints
describe("POST /api/posts", () => {
it("creates a new post", async () => {
const res = await fetch("http://localhost:3000/api/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Test", content: "Content" }),
});
expect(res.status).toBe(201);
});
});
Mocking
Mock Database
import { vi } from "vitest";
import { db } from "../src/config/database";
vi.spyOn(db.query.cars, "findMany").mockResolvedValue([
{ make: "Toyota", model: "Corolla", number: 100 },
]);
Mock External APIs
const mockFetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ records: [] }),
});
global.fetch = mockFetch;
Mock Redis
vi.mock("@sgcarstrends/utils", () => ({
redis: {
get: vi.fn(),
set: vi.fn(),
del: vi.fn(),
},
}));
Test Helpers
// apps/web/__tests__/helpers.ts
export const createAuthHeader = (token: string) => ({
Authorization: `Bearer ${token}`,
});
export const seedDatabase = async (data: any[]) => {
await db.insert(cars).values(data);
};
export const clearDatabase = async () => {
await db.delete(cars);
};
Best Practices
- Isolate tests - Each test should be independent
- Test error cases - Test both happy and error paths
- Use mocks - Mock external dependencies
- Clean up - Reset state in afterEach
- Descriptive names - Clear test descriptions
- Coverage goals - Aim for 80%+ coverage
Coverage Configuration
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: "v8",
thresholds: { lines: 80, functions: 80, branches: 80 },
},
},
});
References
- Vitest: https://vitest.dev
- Next.js Testing: https://nextjs.org/docs/app/building-your-application/testing
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.