import { PrerenderManifest } from "next/dist/build"; import { ApiManifest, handleApi, prepareBuildManifests, RoutesManifest } from "../../src"; import { mockEvent } from "./utils"; describe("Api handler", () => { let pagesManifest: { [key: string]: string }; let manifest: ApiManifest; let routesManifest: RoutesManifest; let getPage: any; beforeAll(async () => { const prerenderManifest: PrerenderManifest = { version: 3, notFoundRoutes: [], routes: {}, dynamicRoutes: {}, preview: { previewModeId: "test-id", previewModeEncryptionKey: "test-key", previewModeSigningKey: "test-sig-key" } }; routesManifest = { basePath: "", headers: [ { source: "/api/static", headers: [ { key: "X-Test-Header", value: "value" } ] } ], redirects: [ { source: "/api/redirect-simple", destination: "/api/static", statusCode: 307 }, { source: "/redirect/:dynamic", destination: "/api/dynamic/:dynamic", statusCode: 308 }, { source: "/api/redirect-query", destination: "/api/static?foo=bar", statusCode: 307 } ], rewrites: [ { source: "/rewrite", destination: "/api/static" }, { source: "/rewrite-not-found", destination: "/api/not/found" }, { source: "/rewrite/:slug", destination: "/api/dynamic/:slug" }, { source: "/rewrite-query/:slug", destination: "/api/static" }, { source: "/rewrite-external", destination: "https://ext.example.com" } ] }; pagesManifest = { "/": "pages/index.html", "/404": "pages/404.html", "/500": "pages/500.html", "/api": "pages/api/index.js", "/api/static": "pages/api/static.js", "/api/dynamic/[id]": "pages/api/dynamic/[id].js" }; const buildId = "test-build-id"; const publicFiles = ["favicon.ico", "name with spaces.txt"]; const manifests = await prepareBuildManifests( { buildId, domainRedirects: { "www.example.com": "https://example.com" } }, {}, routesManifest, pagesManifest, prerenderManifest, publicFiles ); manifest = manifests.apiManifest; }); beforeEach(() => { jest.spyOn(console, "error").mockReturnValueOnce(); getPage = jest.fn(); getPage.mockReturnValueOnce({ default: jest.fn() }); }); describe("Api pages", () => { it.each` uri | page ${"/api"} | ${"pages/api/index.js"} ${"/api/static"} | ${"pages/api/static.js"} ${"/api/dynamic/1"} | ${"pages/api/dynamic/[id].js"} ${"/rewrite"} | ${"pages/api/static.js"} ${"/rewrite/2"} | ${"pages/api/dynamic/[id].js"} ${"/rewrite-query/3"} | ${"pages/api/static.js"} `("Routes api request $uri to page $page", async ({ uri, page }) => { const event = mockEvent(uri); const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeFalsy(); expect(getPage).toHaveBeenCalledWith(page); expect((event.req as any).originalRequest).toBe(event.req); expect((event.res as any).originalResponse).toBe(event.res); }); it.each` uri | page ${"/api"} | ${"pages/api/index.js"} ${"/api/static"} | ${"pages/api/static.js"} ${"/api/dynamic/1"} | ${"pages/api/dynamic/[id].js"} ${"/rewrite"} | ${"pages/api/static.js"} ${"/rewrite/2"} | ${"pages/api/dynamic/[id].js"} ${"/rewrite-query/3"} | ${"pages/api/static.js"} `( "Routes api request $uri to page $page with NodeNextRequest & NodeNextResponse", async ({ uri, page }) => { const event: any = mockEvent(uri); event.req.originalRequest = {}; event.res.originalResponse = {}; const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeFalsy(); expect(getPage).toHaveBeenCalledWith(page); expect((event.req as any).originalRequest).toBe( (event.req as any).originalRequest ); expect((event.res as any).originalResponse).toBe( (event.res as any).originalResponse ); } ); it.each` uri ${"/api/notfound"} ${"/api/dynamic/not/found"} ${"/rewrite-not-found"} `("Returns 404 for $uri", async ({ uri }) => { const event = mockEvent(uri); const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeFalsy(); expect(event.res.statusCode).toEqual(404); }); }); describe("Headers", () => { it.each` uri ${"/api/static"} `("Sets headers for $uri", async ({ uri }) => { const event = mockEvent(uri); await handleApi(event, manifest, routesManifest, getPage); expect(event.res.setHeader).toHaveBeenCalledWith( "X-Test-Header", "value" ); }); }); describe("Redirects", () => { it.each` uri | code | destination ${"/api/redirect-simple"} | ${307} | ${"/api/static"} ${"/redirect/test"} | ${308} | ${"/api/dynamic/test"} ${"/api/redirect-query?key=val"} | ${307} | ${"/api/static?key=val&foo=bar"} `( "Redirects $uri to $destination with code $code", async ({ code, destination, uri }) => { const event = mockEvent(uri); const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeFalsy(); expect(event.res.statusCode).toEqual(code); expect(event.res.setHeader).toHaveBeenCalledWith( "Location", destination ); expect(event.res.end).toHaveBeenCalled(); } ); it.each` uri | code | destination ${"/api"} | ${308} | ${"https://example.com/api"} ${"/api/static"} | ${308} | ${"https://example.com/api/static"} ${"/api?query"} | ${308} | ${"https://example.com/api?query"} `( "Redirects www.example.com$uri to $destination with code $code", async ({ code, destination, uri }) => { const event = mockEvent(uri, { Host: "www.example.com" }); const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeFalsy(); expect(event.res.statusCode).toEqual(code); expect(event.res.setHeader).toHaveBeenCalledWith( "Location", destination ); expect(event.res.end).toHaveBeenCalled(); } ); }); describe("External rewrite", () => { it.each` uri | path ${"/rewrite-external"} | ${"https://ext.example.com"} `("Returns external rewrite from $uri to $path", async ({ path, uri }) => { const event = mockEvent(uri); const route = await handleApi(event, manifest, routesManifest, getPage); expect(route).toBeTruthy(); if (route) { expect(route.isExternal).toBeTruthy(); expect((route as any).path).toEqual(path); } }); }); });