All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 50s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.8 KiB
TypeScript
75 lines
2.8 KiB
TypeScript
import { BASE_URL, TEST_DIR } from "../helpers.ts";
|
|
import { assertEquals, assertFalse, assertStringIncludes } from "@std/assert";
|
|
import { Application } from "@oak/oak";
|
|
import { routeStaticFilesFrom } from "../../lib/static.ts";
|
|
|
|
async function handle(
|
|
app: Application,
|
|
path: string,
|
|
headers: HeadersInit = {},
|
|
) {
|
|
const res = await app.handle(new Request(`${BASE_URL}${path}`, { headers }));
|
|
if (!res) throw new Error("no response");
|
|
return { res, text: await res.text() };
|
|
}
|
|
|
|
Deno.test("routeStaticFilesFrom: index, SPA fallback, cache rules, precompressed files", async () => {
|
|
const root = `${TEST_DIR}/static-${crypto.randomUUID()}`;
|
|
await Deno.mkdir(`${root}/assets`, { recursive: true });
|
|
await Deno.writeTextFile(
|
|
`${root}/index.html`,
|
|
`<html><head><title>__SITE_NAME__</title></head><body>__BANDCAMP_PLAYER__</body></html>`,
|
|
);
|
|
const js = "console.log('app');".repeat(50);
|
|
await Deno.writeTextFile(`${root}/assets/app-abc123.js`, js);
|
|
const br = new Uint8Array([1, 2, 3]);
|
|
await Deno.writeFile(`${root}/assets/app-abc123.js.br`, br);
|
|
await Deno.writeTextFile(`${root}/robots.txt`, "User-agent: *");
|
|
|
|
const app = new Application();
|
|
app.use(routeStaticFilesFrom([root]));
|
|
|
|
const index = await handle(app, "/");
|
|
assertEquals(index.res.headers.get("cache-control"), "no-cache");
|
|
assertEquals(
|
|
index.text,
|
|
"<html><head><title>gerbeur</title></head><body>embed</body></html>",
|
|
);
|
|
|
|
const spa = await handle(app, "/users/someone");
|
|
assertEquals(spa.res.status, 200);
|
|
assertEquals(spa.text, index.text);
|
|
|
|
// No Accept-Encoding header: the plain file, not the .br sibling.
|
|
const asset = await handle(app, "/assets/app-abc123.js");
|
|
assertEquals(asset.text, js);
|
|
assertEquals(asset.res.headers.get("content-encoding"), null);
|
|
assertStringIncludes(asset.res.headers.get("cache-control")!, "immutable");
|
|
assertStringIncludes(
|
|
asset.res.headers.get("cache-control")!,
|
|
"max-age=31536000",
|
|
);
|
|
assertStringIncludes(asset.res.headers.get("vary")!, "Accept-Encoding");
|
|
|
|
const compressed = await handle(app, "/assets/app-abc123.js", {
|
|
"Accept-Encoding": "br, gzip",
|
|
});
|
|
assertEquals(compressed.res.headers.get("content-encoding"), "br");
|
|
assertEquals(compressed.text, "\x01\x02\x03"); // the .br file's bytes
|
|
|
|
const plain = await handle(app, "/robots.txt");
|
|
assertEquals(plain.text, "User-agent: *");
|
|
assertFalse(
|
|
(plain.res.headers.get("cache-control") ?? "").includes("immutable"),
|
|
);
|
|
|
|
// A chunk from an older build 404s rather than being answered with the index.
|
|
const stale = await handle(app, "/assets/app-old999.js");
|
|
assertEquals(stale.res.status, 404);
|
|
assertFalse(stale.text.includes("<html>"));
|
|
assertEquals(
|
|
(await handle(app, "/emojibase/17.0.0/missing.json")).res.status,
|
|
404,
|
|
);
|
|
});
|