Skip to content

Commit

Permalink
Tests for middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
ragokan committed Sep 27, 2024
1 parent e7427fa commit 108a5d3
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 0 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## [0.0.29] - 2024-09-27

- Add "createNodeServer" wrapper for NodeJS environments

## [0.0.28] - 2024-09-25

- Add cache middleware and globam middleware wrappers

## [0.0.27] - 2024-09-17

- Fixes to query parsing
Expand Down
157 changes: 157 additions & 0 deletions tests/src/middleware.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import {
type Mock,
afterEach,
beforeEach,
describe,
expect,
it,
jest,
} from "bun:test";
import bunicornClient from "@bunicorn/client";
import { BunicornApp, Router, createMiddleware } from "@bunicorn/server";
import { type AppType, startServer } from "./server/middleware.server.ts";

// Mock console.log
const mockConsoleLog = jest.fn();
console.log = mockConsoleLog as Mock<any>;

describe("Middleware Tests", () => {
let server: any;
const client = bunicornClient<AppType>({
serverPath: "http://localhost:8080",
});

beforeEach(() => {
server = startServer(8080);
mockConsoleLog.mockClear();
});

afterEach(() => {
server.stop(true);
});

it("should call all middlewares and handler exactly once in correct order", async () => {
const response = await client.get("/", {}).assert();

expect(response.success).toBe(true);
expect(response.data).toEqual({ message: "Hello World! 3 5" });

expect(mockConsoleLog.mock.calls).toEqual([
["Request received."],
["Count middleware called."],
["Age middleware called."],
["Handler called."],
["Response sent with body:", '{"message":"Hello World! 3 5"}'],
[
expect.stringMatching(
/Response time for url http:\/\/localhost:8080\/: \d+ms/,
),
],
]);

// Check that each middleware and handler is called exactly once
const callCounts = mockConsoleLog.mock.calls.reduce(
(acc, call) => {
acc[call[0]] = (acc[call[0]] || 0) + 1;
return acc;
},
{} as Record<string, number>,
);

expect(callCounts["Request received."]).toBe(1);
expect(callCounts["Count middleware called."]).toBe(1);
expect(callCounts["Age middleware called."]).toBe(1);
expect(callCounts["Handler called."]).toBe(1);
expect(
Object.keys(callCounts).find((key) =>
key.startsWith("Response time for url"),
),
).toBeTruthy();
expect(
Object.keys(callCounts).find((key) =>
key.startsWith("Response sent with body"),
),
).toBeTruthy();
});

it("should handle errors in middlewares", async () => {
const errorMiddleware = createMiddleware(async () => {
throw new Error("Test error");
});

const errorRoute = new Router()
.use(errorMiddleware)
.get("/error", (ctx) => {
return ctx.json({ message: "This should not be reached" });
});

const errorApp = new BunicornApp().addRoute(errorRoute);
const errorServer = errorApp.serve({ port: 8081 });
const errorClient = bunicornClient<typeof errorApp>({
serverPath: "http://localhost:8081",
});

try {
await errorClient.get("/error", {});
} catch (error: any) {
expect(error.message).toBe("Test error");
}

errorServer.stop(true);
});

it("should modify response in middleware", async () => {
const modifyResponseMiddleware = createMiddleware(async (_, next) => {
const response = await next();
const json = await response.clone().json();
json.modified = true;
return new Response(JSON.stringify(json), response);
});

const modifyRoute = new Router()
.use(modifyResponseMiddleware)
.get("/modify", (ctx) => {
return ctx.json({ message: "Original response" });
});

const modifyApp = new BunicornApp().addRoute(modifyRoute);
const modifyServer = modifyApp.serve({ port: 8082 });
const modifyClient = bunicornClient<typeof modifyApp>({
serverPath: "http://localhost:8082",
});

const response = await modifyClient.get("/modify", {}).assert();

expect(response.success).toBe(true);
expect(response.data).toContainKey("modified");
expect(response.data as unknown).toEqual({
message: "Original response",
modified: true,
});

modifyServer.stop(true);
});

it("should ensure middlewares are not called for non-existent routes", async () => {
await client.get("/non-existent" as any, {}).catch(() => {});

expect(mockConsoleLog.mock.calls).toEqual([]);

// Ensure other middlewares and handler were not called
expect(
mockConsoleLog.mock.calls.every(
(call) => !call[0].includes("Count middleware called."),
),
).toBe(true);
expect(
mockConsoleLog.mock.calls.every(
(call) => !call[0].includes("Age middleware called."),
),
).toBe(true);
expect(
mockConsoleLog.mock.calls.every(
(call) => !call[0].includes("Handler called."),
),
).toBe(true);
});
});
41 changes: 41 additions & 0 deletions tests/src/server/middleware.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { BunicornApp, Router, createMiddleware } from "@bunicorn/server";

export const loggerMiddleware = createMiddleware(async (_, next) => {
console.log("Request received.");
const response = await next();
console.log("Response sent with body:", await response.clone().text());
return response;
});

export const responseTimeMiddleware = createMiddleware(async (ctx, next) => {
const start = Date.now();
const response = await next();
const time = Date.now() - start;
console.log(`Response time for url ${ctx.req.url}: ${time}ms`);
return response;
});

export const countMiddleware = createMiddleware(async () => {
console.log("Count middleware called.");
return { count: 3 };
});

export const ageMiddleware = createMiddleware(async () => {
console.log("Age middleware called.");
return { age: 5 };
});

const route = new Router()
.use(responseTimeMiddleware)
.use(loggerMiddleware)
.use(countMiddleware)
.use(ageMiddleware)
.get("/", (ctx) => {
console.log("Handler called.");
return ctx.json({ message: `Hello World! ${ctx.count} ${ctx.age}` });
});

export const app = new BunicornApp().addRoute(route);
export type AppType = typeof app;

export const startServer = (port: number) => app.serve({ port });

0 comments on commit 108a5d3

Please sign in to comment.