import { describe, it, expect, vi, beforeEach } from "vitest"; const responseMock = vi.hoisted(() => { function makeResponseMock() { const store = new Map(); return { _store: store, headers: { set: vi.fn((k: string, v: string) => store.set(k, v)), get: vi.fn((k: string) => store.get(k) ?? null), }, }; } return { makeResponseMock }; }); vi.mock("next/server", () => ({ NextResponse: { next: vi.fn(), }, })); import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; import { middleware } from "../../middleware"; const ALL_SIX_HEADERS = [ "Strict-Transport-Security", "X-Frame-Options", "X-Content-Type-Options", "Referrer-Policy", "Permissions-Policy", "Content-Security-Policy", ] as const; function makeRequest(): NextRequest { return { headers: new Headers() } as unknown as NextRequest; } describe("web-next middleware", () => { let mock: ReturnType; beforeEach(() => { mock = responseMock.makeResponseMock(); vi.mocked(NextResponse.next).mockReturnValue( mock as unknown as ReturnType, ); }); it("sets all six security headers on the response", () => { middleware(makeRequest()); for (const header of ALL_SIX_HEADERS) { expect(mock._store.has(header)).toBe(true); } }); it("sets x-nonce header on the response", () => { middleware(makeRequest()); const nonce = mock._store.get("x-nonce"); expect(nonce).toBeDefined(); expect(typeof nonce).toBe("string"); expect((nonce as string).length).toBeGreaterThan(0); }); it("CSP contains nonce in production mode", () => { vi.stubEnv("NODE_ENV", "production"); middleware(makeRequest()); const nonce = mock._store.get("x-nonce"); const csp = mock._store.get("Content-Security-Policy"); expect(csp).toContain(`'nonce-${nonce}'`); }); it("CSP is permissive (unsafe-inline) in development mode", () => { vi.stubEnv("NODE_ENV", "development"); middleware(makeRequest()); const csp = mock._store.get("Content-Security-Policy"); expect(csp).toContain("'unsafe-inline'"); }); it("x-nonce is forwarded in request headers passed to NextResponse.next", () => { middleware(makeRequest()); const call = vi.mocked(NextResponse.next).mock.calls[0] as [ { request?: { headers?: Headers } } | undefined, ]; expect(call[0]?.request?.headers?.get("x-nonce")).toBeTruthy(); }); });