// deno-lint-ignore-file require-await import { assertEquals } from "@std/assert"; import { beforeEach, describe, it } from "@std/testing/bdd"; import Router from "./router.ts"; describe("Router", () => { let router: Router; beforeEach(() => { router = new Router(); }); describe("Basic Routing", () => { it("should handle basic GET request", async () => { router.route("/test") .get(async () => new Response("test response")); const req = new Request("http://localhost/test", { method: "GET", }); const res = await router.handle(req); assertEquals(res.status, 200); assertEquals(await res.text(), "test response"); }); it("should return 404 for non-existent route", async () => { const req = new Request("http://localhost/nonexistent", { method: "GET", }); const res = await router.handle(req); assertEquals(res.status, 404); }); it("should return 405 for unsupported method", async () => { router.route("/test") .get(async () => new Response("test")); const req = new Request("http://localhost/test", { method: "POST", }); const res = await router.handle(req); assertEquals(res.status, 405); }); }); describe("Route Parameters", () => { it("should handle route parameters", async () => { router.route("/users/:id") .get(async (_, ctx) => new Response(ctx.params.id)); const req = new Request("http://localhost/users/123", { method: "GET", }); const res = await router.handle(req); assertEquals(await res.text(), "123"); }); it("should handle multiple route parameters", async () => { router.route("/users/:userId/posts/:postId") .get(async (_, ctx) => { return new Response(JSON.stringify(ctx.params)); }); const req = new Request("http://localhost/users/123/posts/456", { method: "GET", }); const res = await router.handle(req); const params = JSON.parse(await res.text()); assertEquals(params.userId, "123"); assertEquals(params.postId, "456"); }); }); describe("Middleware", () => { it("should execute global middleware", async () => { let middlewareExecuted = false; router.use(async (_ctx, next) => { middlewareExecuted = true; return await next(); }); router.route("/test") .get(async () => new Response("test")); const req = new Request("http://localhost/test", { method: "GET", }); await router.handle(req); assertEquals(middlewareExecuted, true); }); it("should execute path-specific middleware", async () => { let middlewareExecuted = false; router.use("/test", async (_ctx, next) => { middlewareExecuted = true; console.log('middlware happened') return await next(); }); router.route("/test") .get(async () => new Response("test")); const req = new Request("http://localhost/test", { method: "GET", }); await router.handle(req); assertEquals(middlewareExecuted, true); }); it("should handle middleware parameters", async () => { const capturedParams: Record = {}; router.use("/:version/.*", async (ctx, next) => { capturedParams.version = ctx.params.version; return await next(); }); router.route("/:version/test") .get(async () => new Response("test")); const req = new Request("http://localhost/v1/test", { method: "GET", }); await router.handle(req); assertEquals(capturedParams.version, "v1"); }); it("should execute middleware in correct order", async () => { const order: number[] = []; router.use(async (_ctx, next) => { order.push(1); return await next(); }); router.use("/test", async (_ctx, next) => { order.push(2); return await next(); }); router.route("/test") .get(async () => { order.push(3); return new Response("test"); }); const req = new Request("http://localhost/test", { method: "GET", }); await router.handle(req); assertEquals(order, [1, 2, 3]); }); }); describe("Nested Routers", () => { it("should handle nested routes", async () => { const apiRouter = new Router(); apiRouter.route("/test") .get(async () => new Response("api test")); router.use("/api", apiRouter); const req = new Request("http://localhost/api/test", { method: "GET", }); const res = await router.handle(req); assertEquals(await res.text(), "api test"); }); it("should handle nested routes with parameters", async () => { const apiRouter = new Router(); apiRouter.route("/users/:id") .get(async (_, ctx) => new Response(ctx.params.id)); router.use("/api/:version", apiRouter); const req = new Request("http://localhost/api/v1/users/123", { method: "GET", }); const res = await router.handle(req); assertEquals(await res.text(), "123"); }); it("should handle nested middleware", async () => { const apiRouter = new Router(); let middlewareExecuted = false; apiRouter.use(async (_ctx, next) => { middlewareExecuted = true; return await next(); }); apiRouter.route("/test") .get(async () => new Response("test")); router.use("/api", apiRouter); const req = new Request("http://localhost/api/test", { method: "GET", }); await router.handle(req); assertEquals(middlewareExecuted, true); }); }); describe("Context State", () => { it("should maintain state across middleware chain", async () => { router.use(async (ctx, next) => { ctx.state.test = "value"; return await next(); }); router.route("/test") .get(async (_, ctx) => { return new Response(ctx.state.test as string); }); const req = new Request("http://localhost/test", { method: "GET", }); const res = await router.handle(req); assertEquals(await res.text(), "value"); }); }); describe("Error Handling", () => { it("should handle errors in handlers", async () => { router.route("/error") .get(async () => { throw new Error("Test error"); }); const req = new Request("http://localhost/error", { method: "GET", }); const res = await router.handle(req); assertEquals(res.status, 500); assertEquals(await res.text(), "Internal Server Error"); }); it("should handle errors in middleware", async () => { router.use(async () => { throw new Error("Middleware error"); }); router.route("/test") .get(async () => new Response("test")); const req = new Request("http://localhost/test", { method: "GET", }); const res = await router.handle(req); assertEquals(res.status, 500); }); }); describe("HTTP Methods", () => { const methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]; methods.forEach(method => { it(`should handle ${method} requests`, async () => { const route = router.route("/test"); route[method.toLowerCase() as keyof typeof route]( async () => new Response(method) ); const req = new Request("http://localhost/test", { method: method, }); const res = await router.handle(req); assertEquals(res.status, 200); assertEquals(await res.text(), method); }); }); }); });