Skip to content

Commit 8a94ac4

Browse files
committed
Add unit tests for route handler
1 parent 612f09f commit 8a94ac4

File tree

7 files changed

+176
-0
lines changed

7 files changed

+176
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lnRb3bjsx2nspyrLXPfpa
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":4,"routes":{"/middleware-rewrite-with-isr-destination":{"initialRevalidateSeconds":10,"srcRoute":null,"dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/middleware-rewrite-with-isr-destination.json"},"/isr":{"initialRevalidateSeconds":10,"srcRoute":null,"dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/isr.json"},"/ssg-preview/hello":{"initialRevalidateSeconds":false,"srcRoute":"/ssg-preview/[id]","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-preview/hello.json"},"/ssg-preview/world":{"initialRevalidateSeconds":false,"srcRoute":"/ssg-preview/[id]","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-preview/world.json"},"/ssg":{"initialRevalidateSeconds":false,"srcRoute":null,"dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg.json"},"/ssg-dynamic/1":{"initialRevalidateSeconds":false,"srcRoute":"/ssg-dynamic/[id]","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-dynamic/1.json"}},"dynamicRoutes":{"/ssg-dynamic-fallback/[id]":{"routeRegex":"^/ssg\\-dynamic\\-fallback/([^/]+?)(?:/)?$","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-dynamic-fallback/[id].json","fallback":"/ssg-dynamic-fallback/[id].html","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic\\-fallback/([^/]+?)\\.json$"},"/ssg-preview/[id]":{"routeRegex":"^/ssg\\-preview/([^/]+?)(?:/)?$","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-preview/[id].json","fallback":false,"dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-preview/([^/]+?)\\.json$"},"/ssg-dynamic/[id]":{"routeRegex":"^/ssg\\-dynamic/([^/]+?)(?:/)?$","dataRoute":"/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg-dynamic/[id].json","fallback":false,"dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic/([^/]+?)\\.json$"}},"notFoundRoutes":[],"preview":{"previewModeId":"a4f0a4586498ab90ef6af5c106920f7e","previewModeSigningKey":"61c53747d3c40a6a1e809ecae2a7c625643701bb390321f6c57813e7a78363d9","previewModeEncryptionKey":"d9108ce7f77f85f1f07ea2fc9e7355805cf11ddd28c85f1a61cfce1810515a60"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":1,"config":{"env":{},"webpack":null,"eslint":{"ignoreDuringBuilds":true},"typescript":{"ignoreBuildErrors":false,"tsconfigPath":"tsconfig.json"},"distDir":".next","cleanDistDir":true,"assetPrefix":"","configOrigin":"next.config.js","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"analyticsId":"","images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[16,32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":60,"formats":["image/webp"],"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"inline","remotePatterns":[{"hostname":"**.unsplash.com"}],"unoptimized":false},"devIndicators":{"buildActivity":true,"buildActivityPosition":"bottom-right"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"amp":{"canonicalBase":""},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"optimizeFonts":true,"excludeDefaultMomentLocales":true,"serverRuntimeConfig":{},"publicRuntimeConfig":{},"reactProductionProfiling":false,"reactStrictMode":true,"httpAgentOptions":{"keepAlive":true},"outputFileTracing":true,"staticPageGenerationTimeout":60,"swcMinify":true,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"date-fns":{"transform":"date-fns/{{member}}"},"lodash":{"transform":"lodash/{{member}}"},"lodash-es":{"transform":"lodash-es/{{member}}"},"ramda":{"transform":"ramda/es/{{member}}"},"react-bootstrap":{"transform":"react-bootstrap/{{member}}"},"antd":{"transform":"antd/lib/{{kebabCase member}}"},"ahooks":{"transform":"ahooks/es/{{member}}"},"@ant-design/icons":{"transform":"@ant-design/icons/lib/icons/{{member}}"}},"experimental":{"serverMinification":false,"serverSourceMaps":false,"caseSensitiveRoutes":false,"useDeploymentId":false,"useDeploymentIdServerActions":false,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","middlewarePrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"legacyBrowsers":false,"newNextLinkBehavior":true,"cpus":7,"memoryBasedWorkersCount":false,"sharedPool":true,"isrFlushToDisk":true,"workerThreads":false,"pageEnv":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"swcFileReading":true,"craCompat":false,"esmExternals":true,"appDir":true,"isrMemoryCacheSize":52428800,"fullySpecified":false,"outputFileTracingRoot":"/Users/socsieng/Projects/opennextjs-aws","swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"adjustFontFallbacks":false,"adjustFontFallbacksWithSizeAdjust":false,"typedRoutes":false,"instrumentationHook":false,"trustHostHeader":false},"configFileName":"next.config.js"},"appDir":"/Users/socsieng/Projects/opennextjs-aws/example","relativeAppDir":"example","files":[".next/routes-manifest.json",".next/server/pages-manifest.json",".next/build-manifest.json",".next/prerender-manifest.json",".next/server/middleware-manifest.json",".next/server/middleware-build-manifest.js",".next/server/middleware-react-loadable-manifest.js",".next/react-loadable-manifest.json",".next/server/font-manifest.json",".next/BUILD_ID",".next/server/next-font-manifest.js",".next/server/next-font-manifest.json"],"ignore":["../node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*"]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":3,"pages404":true,"caseSensitive":false,"basePath":"","redirects":[{"source":"/:path+/","destination":"/:path+","internal":true,"statusCode":308,"regex":"^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))/$"}],"headers":[],"dynamicRoutes":[{"page":"/api/auth/[...nextauth]","regex":"^/api/auth/(.+?)(?:/)?$","routeKeys":{"nxtPnextauth":"nxtPnextauth"},"namedRegex":"^/api/auth/(?<nxtPnextauth>.+?)(?:/)?$"},{"page":"/ssg-dynamic/[id]","regex":"^/ssg\\-dynamic/([^/]+?)(?:/)?$","routeKeys":{"nxtPid":"nxtPid"},"namedRegex":"^/ssg\\-dynamic/(?<nxtPid>[^/]+?)(?:/)?$"},{"page":"/ssg-dynamic-fallback/[id]","regex":"^/ssg\\-dynamic\\-fallback/([^/]+?)(?:/)?$","routeKeys":{"nxtPid":"nxtPid"},"namedRegex":"^/ssg\\-dynamic\\-fallback/(?<nxtPid>[^/]+?)(?:/)?$"},{"page":"/ssg-preview/[id]","regex":"^/ssg\\-preview/([^/]+?)(?:/)?$","routeKeys":{"nxtPid":"nxtPid"},"namedRegex":"^/ssg\\-preview/(?<nxtPid>[^/]+?)(?:/)?$"}],"staticRoutes":[{"page":"/","regex":"^/(?:/)?$","routeKeys":{},"namedRegex":"^/(?:/)?$"},{"page":"/404","regex":"^/404(?:/)?$","routeKeys":{},"namedRegex":"^/404(?:/)?$"},{"page":"/api-route","regex":"^/api\\-route(?:/)?$","routeKeys":{},"namedRegex":"^/api\\-route(?:/)?$"},{"page":"/font-css-font","regex":"^/font\\-css\\-font(?:/)?$","routeKeys":{},"namedRegex":"^/font\\-css\\-font(?:/)?$"},{"page":"/font-next-font","regex":"^/font\\-next\\-font(?:/)?$","routeKeys":{},"namedRegex":"^/font\\-next\\-font(?:/)?$"},{"page":"/image-html-tag","regex":"^/image\\-html\\-tag(?:/)?$","routeKeys":{},"namedRegex":"^/image\\-html\\-tag(?:/)?$"},{"page":"/image-optimization-imported","regex":"^/image\\-optimization\\-imported(?:/)?$","routeKeys":{},"namedRegex":"^/image\\-optimization\\-imported(?:/)?$"},{"page":"/image-optimization-remote","regex":"^/image\\-optimization\\-remote(?:/)?$","routeKeys":{},"namedRegex":"^/image\\-optimization\\-remote(?:/)?$"},{"page":"/isr","regex":"^/isr(?:/)?$","routeKeys":{},"namedRegex":"^/isr(?:/)?$"},{"page":"/middleware-geolocation","regex":"^/middleware\\-geolocation(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-geolocation(?:/)?$"},{"page":"/middleware-redirect","regex":"^/middleware\\-redirect(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-redirect(?:/)?$"},{"page":"/middleware-redirect-destination","regex":"^/middleware\\-redirect\\-destination(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-redirect\\-destination(?:/)?$"},{"page":"/middleware-rewrite","regex":"^/middleware\\-rewrite(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-rewrite(?:/)?$"},{"page":"/middleware-rewrite-with-isr","regex":"^/middleware\\-rewrite\\-with\\-isr(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-rewrite\\-with\\-isr(?:/)?$"},{"page":"/middleware-rewrite-with-isr-destination","regex":"^/middleware\\-rewrite\\-with\\-isr\\-destination(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-rewrite\\-with\\-isr\\-destination(?:/)?$"},{"page":"/middleware-set-header","regex":"^/middleware\\-set\\-header(?:/)?$","routeKeys":{},"namedRegex":"^/middleware\\-set\\-header(?:/)?$"},{"page":"/next-auth","regex":"^/next\\-auth(?:/)?$","routeKeys":{},"namedRegex":"^/next\\-auth(?:/)?$"},{"page":"/ssg","regex":"^/ssg(?:/)?$","routeKeys":{},"namedRegex":"^/ssg(?:/)?$"},{"page":"/ssr","regex":"^/ssr(?:/)?$","routeKeys":{},"namedRegex":"^/ssr(?:/)?$"},{"page":"/ssr-not-found","regex":"^/ssr\\-not\\-found(?:/)?$","routeKeys":{},"namedRegex":"^/ssr\\-not\\-found(?:/)?$"},{"page":"/ssr-redirect","regex":"^/ssr\\-redirect(?:/)?$","routeKeys":{},"namedRegex":"^/ssr\\-redirect(?:/)?$"},{"page":"/ssr-redirect-destination","regex":"^/ssr\\-redirect\\-destination(?:/)?$","routeKeys":{},"namedRegex":"^/ssr\\-redirect\\-destination(?:/)?$"}],"dataRoutes":[{"page":"/isr","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/isr.json$"},{"page":"/middleware-geolocation","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/middleware-geolocation.json$"},{"page":"/middleware-rewrite","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/middleware-rewrite.json$"},{"page":"/middleware-rewrite-with-isr-destination","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/middleware-rewrite-with-isr-destination.json$"},{"page":"/middleware-set-header","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/middleware-set-header.json$"},{"page":"/ssg","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg.json$"},{"page":"/ssg-dynamic/[id]","routeKeys":{"nxtPid":"nxtPid"},"dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic/(?<nxtPid>[^/]+?)\\.json$"},{"page":"/ssg-dynamic-fallback/[id]","routeKeys":{"nxtPid":"nxtPid"},"dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic\\-fallback/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-dynamic\\-fallback/(?<nxtPid>[^/]+?)\\.json$"},{"page":"/ssg-preview/[id]","routeKeys":{"nxtPid":"nxtPid"},"dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-preview/([^/]+?)\\.json$","namedDataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssg\\-preview/(?<nxtPid>[^/]+?)\\.json$"},{"page":"/ssr","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssr.json$"},{"page":"/ssr-not-found","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssr-not-found.json$"},{"page":"/ssr-redirect","dataRouteRegex":"^/_next/data/lnRb3bjsx2nspyrLXPfpa/ssr-redirect.json$"}],"rsc":{"header":"RSC","varyHeader":"RSC, Next-Router-State-Tree, Next-Router-Prefetch","contentTypeHeader":"text/x-component"},"rewrites":[]}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"sortedMiddleware": [
3+
"/"
4+
],
5+
"middleware": {
6+
"/": {
7+
"files": [
8+
"server/edge-runtime-webpack.js",
9+
"server/middleware.js"
10+
],
11+
"name": "middleware",
12+
"page": "/",
13+
"matchers": [
14+
{
15+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-rewrite(.json)?[\\/#\\?]?$",
16+
"originalSource": "/middleware-rewrite"
17+
},
18+
{
19+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-rewrite-with-isr(.json)?[\\/#\\?]?$",
20+
"originalSource": "/middleware-rewrite-with-isr"
21+
},
22+
{
23+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-redirect(.json)?[\\/#\\?]?$",
24+
"originalSource": "/middleware-redirect"
25+
},
26+
{
27+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-set-header(.json)?[\\/#\\?]?$",
28+
"originalSource": "/middleware-set-header"
29+
},
30+
{
31+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-fetch(.json)?[\\/#\\?]?$",
32+
"originalSource": "/middleware-fetch"
33+
},
34+
{
35+
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/middleware-geolocation(.json)?[\\/#\\?]?$",
36+
"originalSource": "/middleware-geolocation"
37+
}
38+
],
39+
"wasm": [],
40+
"assets": []
41+
}
42+
},
43+
"functions": {},
44+
"version": 2
45+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"/_error": "pages/_error.js",
3+
"/_app": "pages/_app.js",
4+
"/404": "pages/404.html",
5+
"/api-route": "pages/api-route.html",
6+
"/api/hello": "pages/api/hello.js",
7+
"/font-css-font": "pages/font-css-font.html",
8+
"/font-next-font": "pages/font-next-font.html",
9+
"/api/preview": "pages/api/preview.js",
10+
"/image-html-tag": "pages/image-html-tag.html",
11+
"/image-optimization-imported": "pages/image-optimization-imported.html",
12+
"/": "pages/index.html",
13+
"/image-optimization-remote": "pages/image-optimization-remote.html",
14+
"/middleware-redirect-destination": "pages/middleware-redirect-destination.html",
15+
"/middleware-redirect": "pages/middleware-redirect.html",
16+
"/next-auth": "pages/next-auth.html",
17+
"/middleware-rewrite-with-isr": "pages/middleware-rewrite-with-isr.html",
18+
"/ssr-redirect-destination": "pages/ssr-redirect-destination.html",
19+
"/api/auth/[...nextauth]": "pages/api/auth/[...nextauth].js",
20+
"/middleware-geolocation": "pages/middleware-geolocation.js",
21+
"/isr": "pages/isr.js",
22+
"/middleware-rewrite-with-isr-destination": "pages/middleware-rewrite-with-isr-destination.js",
23+
"/middleware-rewrite": "pages/middleware-rewrite.js",
24+
"/middleware-set-header": "pages/middleware-set-header.js",
25+
"/ssg-preview/[id]": "pages/ssg-preview/[id].js",
26+
"/ssg-dynamic-fallback/[id]": "pages/ssg-dynamic-fallback/[id].js",
27+
"/ssr-not-found": "pages/ssr-not-found.js",
28+
"/ssg": "pages/ssg.js",
29+
"/ssr": "pages/ssr.js",
30+
"/ssg-dynamic/[id]": "pages/ssg-dynamic/[id].js",
31+
"/_document": "pages/_document.js",
32+
"/ssr-redirect": "pages/ssr-redirect.js"
33+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import "@opennextjs/aws/core/createGenericHandler.js";
2+
3+
import { convertFromQueryString } from "@opennextjs/aws/core/routing/util.js";
4+
import routingHandler from "@opennextjs/aws/core/routingHandler.js";
5+
import {
6+
InternalEvent,
7+
InternalResult,
8+
} from "@opennextjs/aws/types/open-next.js";
9+
import fs from "fs";
10+
import path from "path";
11+
import { vi } from "vitest";
12+
13+
type PartialEvent = Partial<
14+
Omit<InternalEvent, "body" | "rawPath" | "query">
15+
> & { body?: string };
16+
17+
function createEvent(event: PartialEvent): InternalEvent {
18+
const [rawPath, qs] = (event.url ?? "/").split("?", 1);
19+
return {
20+
type: "core",
21+
method: event.method ?? "GET",
22+
rawPath,
23+
url: event.url ?? "/",
24+
body: Buffer.from(event.body ?? ""),
25+
headers: event.headers ?? {},
26+
query: convertFromQueryString(qs ?? ""),
27+
cookies: event.cookies ?? {},
28+
remoteAddress: event.remoteAddress ?? "::1",
29+
};
30+
}
31+
32+
globalThis.openNextConfig = {};
33+
34+
vi.mock("fs", async () => {
35+
const actualFs = (await vi.importActual("fs")) as typeof fs;
36+
const actualPath = (await vi.importActual("path")) as typeof path;
37+
38+
const fileExpression =
39+
/^(?<prefix>.+)\/\.(?<relativePath>(next|open-next)\/.+)$/;
40+
41+
// remap the file path to the mock directory
42+
const readFileSyncMock = vi.fn().mockImplementation((filename, encoding) => {
43+
const match = fileExpression.exec(filename);
44+
const mappedFilename = match
45+
? actualPath.join(__dirname, "__mocks__", match.groups!.relativePath)
46+
: filename;
47+
48+
return actualFs.readFileSync(mappedFilename, encoding);
49+
});
50+
51+
return {
52+
...actualFs,
53+
readFileSync: readFileSyncMock,
54+
default: {
55+
...(actualFs as any).default,
56+
readFileSync: readFileSyncMock,
57+
},
58+
};
59+
});
60+
61+
beforeEach(() => {
62+
vi.resetAllMocks();
63+
});
64+
65+
it("should return 404 for data requests that don't match the buildId", async () => {
66+
const event = createEvent({
67+
url: "/_next/data/abc/test",
68+
});
69+
70+
const response = (await routingHandler(event)) as InternalResult;
71+
72+
expect(response.statusCode).toEqual(404);
73+
});
74+
75+
it("should not return 404 for data requests that match the buildId", async () => {
76+
const event = createEvent({
77+
url: "/_next/data/lnRb3bjsx2nspyrLXPfpa/test",
78+
});
79+
80+
const response = (await routingHandler(event)) as InternalResult;
81+
82+
expect(response.statusCode).not.toEqual(404);
83+
});
84+
85+
it("should redirect trailing slashes", async () => {
86+
const event = createEvent({
87+
url: "/api-route/",
88+
});
89+
90+
const response = (await routingHandler(event)) as InternalResult;
91+
92+
expect(response.statusCode).toEqual(308);
93+
expect(response.headers.Location).toEqual("/api-route");
94+
});

0 commit comments

Comments
 (0)