39 lines
1.9 KiB
TypeScript
39 lines
1.9 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import path from "node:path";
|
|
|
|
import { describe, expect, test } from "vitest";
|
|
|
|
// Source-level checks: importing entry.server.tsx pulls in the Sentry SDK
|
|
// and the React Router runtime, which is heavier than this test needs.
|
|
// Reading the file as text is enough to enforce the asset-CDN cache contract.
|
|
// See docs/improvement-plan/03-scaling-infrastructure/asset-cdn.md.
|
|
const entrySource = readFileSync(
|
|
path.join(path.dirname(fileURLToPath(import.meta.url)), "entry.server.tsx"),
|
|
"utf8"
|
|
);
|
|
|
|
describe("entry.server cache-control contract", () => {
|
|
test("sets `no-store` on HTML responses when no loader-provided value exists", () => {
|
|
expect(entrySource).toContain('responseHeaders.set("Content-Type", "text/html")');
|
|
expect(entrySource).toMatch(/if \(!responseHeaders\.has\("Cache-Control"\)\)/);
|
|
expect(entrySource).toContain('responseHeaders.set("Cache-Control", "no-store")');
|
|
});
|
|
|
|
test("does not override loader-provided Cache-Control headers", () => {
|
|
// The implementation uses `has()` to opt-in to the default rather than
|
|
// unconditionally setting it — this means a loader returning a
|
|
// `Cache-Control: public, max-age=300` (e.g. a marketing landing page)
|
|
// keeps its value. Drift here would silently break loader-defined
|
|
// caching, so guard it with a structural assertion.
|
|
expect(entrySource).not.toMatch(/responseHeaders\.set\("Cache-Control"[^)]*\);[^!]*responseHeaders\.set\("Cache-Control"/);
|
|
});
|
|
|
|
test("sets the cache header before constructing the response", () => {
|
|
const setIndex = entrySource.indexOf('responseHeaders.set("Cache-Control", "no-store")');
|
|
const responseIndex = entrySource.indexOf("new Response(stream", setIndex);
|
|
expect(setIndex).toBeGreaterThan(0);
|
|
expect(responseIndex).toBeGreaterThan(setIndex);
|
|
});
|
|
});
|