Framework-agnostic HTTP API route testing patterns, authentication strategies, and integration testing best practices. Supports REST APIs with JWT cookie authentication and other common auth patterns.
From hugin-v0npx claudepluginhub michelve/hugin-marketplace --plugin hugin-v0This skill uses the workspace's default tool permissions.
examples/authentication-testing.mdexamples/http-method-patterns.mdreference/response-validation.mdresources/api-integration-testing.mdresources/authentication-testing.mdresources/http-testing-fundamentals.mdGuides browser automation with Playwright, Puppeteer, Selenium for e2e testing and scraping. Teaches reliable selectors, auto-waits, isolation to fix flaky tests.
Provides checklists to review code for functionality, quality, security, performance, tests, and maintainability. Use for PRs, audits, team standards, and developer training.
Enforces A/B test setup with gates for hypothesis locking, metrics definition, sample size calculation, assumptions checks, and execution readiness before implementation.
!`cat package.json 2>/dev/null || echo '{"error": "No package.json found."}'`
This skill provides guidance for testing HTTP API routes and endpoints. Primary examples use Express with TypeScript, but patterns adapt to other frameworks.
Unit Tests
Integration Tests
End-to-End Tests
See authentication-testing.md for JWT cookie and bearer token authentication test patterns.
See http-method-patterns.md for GET, POST, PUT/PATCH, and DELETE request test examples.
See response-validation.md for status code testing and response schema validation patterns.
describe("Error Handling", () => {
it("should return structured error response", async () => {
const response = await request(app).post("/api/users").send({ invalid: "data" });
expect(response.status).toBe(400);
expect(response.body).toEqual({
error: expect.any(String),
message: expect.any(String),
errors: expect.any(Array),
});
});
it("should handle database errors gracefully", async () => {
mockDatabase.findOne.mockRejectedValue(new Error("Connection lost"));
const response = await request(app).get("/api/users/123");
expect(response.status).toBe(500);
expect(response.body.error).toBe("Internal Server Error");
});
it("should sanitize error messages in production", async () => {
process.env.NODE_ENV = "production";
const response = await request(app).get("/api/error-prone-route");
expect(response.status).toBe(500);
expect(response.body.message).not.toContain("stack trace");
expect(response.body.message).not.toContain("SQL");
});
});
describe("API Tests", () => {
let testDatabase;
beforeAll(async () => {
// Initialize test database
testDatabase = await initTestDatabase();
});
afterAll(async () => {
// Clean up test database
await testDatabase.close();
});
beforeEach(async () => {
// Seed test data
await testDatabase.seed();
});
afterEach(async () => {
// Clear test data
await testDatabase.clear();
});
// Tests...
});
While this skill provides framework-agnostic patterns, here are common testing libraries per framework:
ā Don't share state between tests
// Bad
let userId;
it("creates user", async () => {
const response = await request(app).post("/api/users").send(userData);
userId = response.body.id; // Shared state!
});
it("deletes user", async () => {
await request(app).delete(`/api/users/${userId}`); // Depends on previous test
});
ā Do create fresh state for each test
// Good
it("creates user", async () => {
const response = await request(app).post("/api/users").send(userData);
expect(response.status).toBe(201);
});
it("deletes user", async () => {
const user = await createTestUser();
const response = await request(app).delete(`/api/users/${user.id}`);
expect(response.status).toBe(204);
});
See the resources/ directory for more detailed guides:
http-testing-fundamentals.md - Deep dive into HTTP testing conceptsauthentication-testing.md - Authentication strategies and edge casesapi-integration-testing.md - Integration testing patterns and toolsTest Structure
describe('Resource Name', () => {
describe('HTTP Method /path', () => {
it('should describe expected behavior', async () => {
// Arrange
const testData = {...};
// Act
const response = await request(app)
.method('/path')
.set('Cookie', authCookie)
.send(testData);
// Assert
expect(response.status).toBe(expectedStatus);
expect(response.body).toMatchObject(expectedData);
});
});
});
Authentication Pattern
let authCookie: string;
beforeEach(async () => {
const response = await request(app)
.post('/api/auth/login')
.send({ email: 'test@example.com', password: 'password123' });
authCookie = response.headers['set-cookie'][0];
});
// Use authCookie in protected route tests
.set('Cookie', authCookie)