smithery/madooei

test-routes

Test route configurations with integration-style tests. Use when testing complete request/response cycles through routes. Triggers on "test routes", "test note routes", "integration test".

Installation

$ npx skills add smithery/madooei --skill test-routes

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/madooei · top by installs.

npx skills add smithery/madooei

Browse all from smithery/madooei

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,638 B
  • docs SUMMARY.md 207 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Test Routes

Integration-style tests that exercise the full request/response cycle through routes.

Quick Reference

Location: tests/routes/{entity-name}.router.test.ts Key technique: Use app.request(), mock middleware, use real MockDB

Test Structure

import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
import type { Mock } from "vitest";
import { Hono, type Next } from "hono";
import { createNoteRoutes } from "@/routes/note.router";
import { NoteController } from "@/controllers/note.controller";
import { NoteService } from "@/services/note.service";
import { MockDbNoteRepository } from "@/repositories/mockdb/note.mockdb.repository";
import type { AppEnv } from "@/schemas/app-env.schema";
import type { AuthenticatedUserContextType } from "@/schemas/user.schemas";
import {
  globalErrorHandler,
  UnauthenticatedError,
  BadRequestError,
} from "@/errors";

describe("Note Routes", () => {
  let app: Hono<AppEnv>;
  let mockDbRepo: MockDbNoteRepository;
  let noteService: NoteService;
  let noteController: NoteController;
  let mockAuthMiddleware: Mock;
  let mockValidateFactory: Mock;

  const testUser: AuthenticatedUserContextType = {
    userId: "user-test-123",
    globalRole: "user",
  };

  beforeEach(async () => {
    // Mock auth middleware - sets user by default
    mockAuthMiddleware = vi.fn(async (c: any, next: Next) => {
      c.set("user", testUser);
      await next();
    });

    // Mock validation factory
    mockValidateFactory = vi.fn((config: any) => {
      return vi.fn(async (c: any, next: Next) => {
        if (config.source === "params") {
          c.set(config.varKey, { id: c.req.param("id") });
        } else if (config.source === "query") {
          c.set(config.varKey, c.req.query());
        } else if (config.source === "body") {
          c.set(config.varKey, await c.req.json());
        }
        await next();
      });
    });

    // Set up real repository and services
    mockDbRepo = new MockDbNoteRepository();
    mockDbRepo.clear();
    noteService = new NoteService(mockDbRepo);
    noteController = new NoteController(noteService);

    // Create app with error handler
    app = new Hono<AppEnv>();
    app.onError(globalErrorHandler);
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  const setupRoutes = () => {
    app.route(
      "/notes",
      createNoteRoutes({
        noteController,
        authMiddleware: mockAuthMiddleware,
        validate: mockValidateFactory,
      }),
    );
  };

  // Tests...
});

Test Categories

1. Success Cases

it("GET /notes - returns all notes for user", async () => {
  setupRoutes();
  await mockDbRepo.create({ content: "Note 1" }, testUser.userId);
  await mockDbRepo.create({ content: "Note 2" }, testUser.userId);

  const response = await app.request("/notes", { method: "GET" });

  expect(response.status).toBe(200);
  const body = await response.json();
  expect(body.data).toHaveLength(2);
});

it("GET /notes/:id - returns specific note", async () => {
  setupRoutes();
  const note = await mockDbRepo.create({ content: "Test" }, testUser.userId);

  const response = await app.request(`/notes/${note.id}`, { method: "GET" });

  expect(response.status).toBe(200);
  const body = await response.json();
  expect(body.id).toBe(note.id);
});

it("POST /notes - creates new note", async () => {
  setupRoutes();

  const response = await app.request("/notes", {
    method: "POST",
    body: JSON.stringify({ content: "New note" }),
    headers: { "Content-Type": "application/json" },
  });

  expect(response.status).toBe(200);
  const body = await response.json();
  expect(body.content).toBe("New note");
  expect(body.createdBy).toBe(testUser.userId);
});

it("PUT /notes/:id - updates note", async () => {
  setupRoutes();
  const note = await mockDbRepo.create(
    { content: "Original" },
    testUser.userId,
  );

  const response = await app.request(`/notes/${note.id}`, {
    method: "PUT",
    body: JSON.stringify({ content: "Updated" }),
    headers: { "Content-Type": "application/json" },
  });

  expect(response.status).toBe(200);
  const body = await response.json();
  expect(body.content).toBe("Updated");
});

it("DELETE /notes/:id - deletes note", async () => {
  setupRoutes();
  const note = await mockDbRepo.create(
    { content: "To delete" },
    testUser.userId,
  );

  const response = await app.request(`/notes/${note.id}`, { method: "DELETE" });

  expect(response.status).toBe(200);
  const dbNote = await mockDbRepo.findById(note.id);
  expect(dbNote).toBeNull();
});

2. Error Cases

it("returns 404 for non-existent resource", async () => {
  setupRoutes();

  const response = await app.request("/notes/non-existent", { method: "GET" });

  expect(response.status).toBe(404);
});

it("returns 401 when not authenticated", async () => {
  mockAuthMiddleware.mockImplementationOnce(async () => {
    throw new UnauthenticatedError("Not authenticated");
  });
  setupRoutes();

  const response = await app.request("/notes", { method: "GET" });

  expect(response.status).toBe(401);
});

it("returns 400 for invalid request body", async () => {
  mockValidateFactory.mockImplementation((config: any) => {
    if (config.source === "body") {
      return vi.fn(async () => {
        throw new BadRequestError("Invalid");
      });
    }
    return vi.fn(async (c: any, next: Next) => await next());
  });
  setupRoutes();

  const response = await app.request("/notes", {
    method: "POST",
    body: JSON.stringify({}),
    headers: { "Content-Type": "application/json" },
  });

  expect(response.status).toBe(400);
});

it("returns 403 when accessing other user's resource", async () => {
  setupRoutes();
  const otherUsersNote = await mockDbRepo.create(
    { content: "Other" },
    "other-user",
  );

  const response = await app.request(`/notes/${otherUsersNote.id}`, {
    method: "PUT",
    body: JSON.stringify({ content: "Hack" }),
    headers: { "Content-Type": "application/json" },
  });

  expect(response.status).toBe(403);
});

Key Patterns

Use app.request()

// GET request
const response = await app.request("/notes", { method: "GET" });

// POST with body
const response = await app.request("/notes", {
  method: "POST",
  body: JSON.stringify({ content: "test" }),
  headers: { "Content-Type": "application/json" },
});

Assert Status and Body

expect(response.status).toBe(200);
const body = await response.json();
expect(body.data).toHaveLength(2);

Override Middleware for Error Tests

mockAuthMiddleware.mockImplementationOnce(async () => {
  throw new UnauthenticatedError();
});
setupRoutes(); // Set up AFTER mock override

Use Real MockDB for State

// Create test data
const note = await mockDbRepo.create({ content: "Test" }, testUser.userId);

// Verify database state after operation
const dbNote = await mockDbRepo.findById(note.id);
expect(dbNote).toBeNull();

What NOT to Do

  • Do NOT make actual HTTP requests to a running server
  • Do NOT use production database
  • Do NOT skip error case testing
  • Do NOT forget to set up routes AFTER mock overrides

See Also

  • create-routes - Creating routes
  • test-controller - Unit testing controllers
  • test-middleware - Unit testing middleware