Files
cloudflare__vinext/tests/app-route-handler-response.test.ts
T

137 lines
4.3 KiB
TypeScript

import { describe, expect, it } from "vite-plus/test";
import type { CachedRouteValue } from "../packages/vinext/src/shims/cache.js";
import {
applyRouteHandlerMiddlewareContext,
applyRouteHandlerRevalidateHeader,
buildAppRouteCacheValue,
buildRouteHandlerCachedResponse,
finalizeRouteHandlerResponse,
markRouteHandlerCacheMiss,
} from "../packages/vinext/src/server/app-route-handler-response.js";
function buildCachedRouteValue(
body: string,
headers: Record<string, string> = {},
): CachedRouteValue {
return {
kind: "APP_ROUTE",
body: new TextEncoder().encode(body).buffer,
status: 200,
headers,
};
}
describe("app route handler response helpers", () => {
it("returns the original response when no middleware context exists", () => {
const response = new Response("hello");
expect(
applyRouteHandlerMiddlewareContext(response, {
headers: null,
status: null,
}),
).toBe(response);
});
it("applies middleware headers and status overrides to route handler responses", async () => {
const response = new Response("hello", {
status: 200,
headers: {
"content-type": "text/plain",
"x-response": "app",
},
});
const result = applyRouteHandlerMiddlewareContext(response, {
headers: new Headers([
["x-middleware", "mw"],
["x-response", "middleware-copy"],
]),
status: 202,
});
expect(result.status).toBe(202);
expect(result.headers.get("content-type")).toBe("text/plain");
expect(result.headers.get("x-response")).toBe("app, middleware-copy");
expect(result.headers.get("x-middleware")).toBe("mw");
await expect(result.text()).resolves.toBe("hello");
});
it("builds cached HIT and STALE route handler responses", async () => {
const cachedValue = buildCachedRouteValue("from-cache", {
"content-type": "text/plain",
});
const hit = buildRouteHandlerCachedResponse(cachedValue, {
cacheState: "HIT",
isHead: false,
revalidateSeconds: 60,
});
expect(hit.headers.get("x-vinext-cache")).toBe("HIT");
expect(hit.headers.get("cache-control")).toBe("s-maxage=60, stale-while-revalidate");
await expect(hit.text()).resolves.toBe("from-cache");
const staleHead = buildRouteHandlerCachedResponse(cachedValue, {
cacheState: "STALE",
isHead: true,
revalidateSeconds: 60,
});
expect(staleHead.headers.get("x-vinext-cache")).toBe("STALE");
expect(staleHead.headers.get("cache-control")).toBe("s-maxage=0, stale-while-revalidate");
await expect(staleHead.text()).resolves.toBe("");
});
it("serializes APP_ROUTE cache values without cache bookkeeping headers", async () => {
const response = new Response("cache me", {
status: 201,
headers: {
"content-type": "text/plain",
"cache-control": "s-maxage=60, stale-while-revalidate",
"x-vinext-cache": "MISS",
"x-extra": "kept",
},
});
const value = await buildAppRouteCacheValue(response);
expect(value.kind).toBe("APP_ROUTE");
expect(value.status).toBe(201);
expect(value.headers).toEqual({
"content-type": "text/plain",
"x-extra": "kept",
});
expect(new TextDecoder().decode(value.body)).toBe("cache me");
});
it("finalizes route handler responses with cookies and auto-head semantics", async () => {
const response = new Response("body", {
status: 202,
statusText: "Accepted",
headers: {
"content-type": "text/plain",
},
});
const result = finalizeRouteHandlerResponse(response, {
pendingCookies: ["a=1; Path=/"],
draftCookie: "draft=1; Path=/",
isHead: true,
});
expect(result.status).toBe(202);
expect(result.statusText).toBe("Accepted");
expect(result.headers.getSetCookie?.()).toEqual(["a=1; Path=/", "draft=1; Path=/"]);
await expect(result.text()).resolves.toBe("");
});
it("applies revalidate and MISS headers separately", () => {
const response = new Response("hello");
applyRouteHandlerRevalidateHeader(response, 30);
markRouteHandlerCacheMiss(response);
expect(response.headers.get("cache-control")).toBe("s-maxage=30, stale-while-revalidate");
expect(response.headers.get("x-vinext-cache")).toBe("MISS");
});
});