import { mkdtemp, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, test } from "vitest"; import { __resetStaticAssetMetadataCacheForTests, createStaticEtag, getStaticAssetMetadata, getStaticCacheControl, isStaticAssetNotModified, selectStaticRepresentation, } from "./static-assets"; const temporaryDirectories: string[] = []; afterEach(async () => { __resetStaticAssetMetadataCacheForTests(); await Promise.all(temporaryDirectories.splice(0).map((directory) => rm(directory, { force: true, recursive: true }))); }); async function createAssetFixture() { const directory = await mkdtemp(path.join(os.tmpdir(), "hivegrid-static-")); temporaryDirectories.push(directory); const filePath = path.join(directory, "asset.js"); await Promise.all([writeFile(filePath, "identity"), writeFile(`${filePath}.br`, "br"), writeFile(`${filePath}.gz`, "gzip")]); return filePath; } describe("static asset metadata", () => { test("selects the highest-quality available precompressed representation", async () => { const metadata = await getStaticAssetMetadata(await createAssetFixture()); expect(metadata).not.toBeNull(); expect(selectStaticRepresentation(metadata!, "gzip;q=1, br;q=0.5").encoding).toBe("gzip"); expect(selectStaticRepresentation(metadata!, "gzip;q=0, br").encoding).toBe("br"); expect(selectStaticRepresentation(metadata!, undefined).encoding).toBe("identity"); }); test("uses representation-specific validators and honours conditional requests", async () => { const metadata = await getStaticAssetMetadata(await createAssetFixture()); const representation = selectStaticRepresentation(metadata!, "br"); const etag = createStaticEtag(representation); expect(etag).toContain("-br"); expect(isStaticAssetNotModified({ etag, ifNoneMatch: etag, mtimeMs: representation.stat.mtimeMs })).toBe(true); expect(isStaticAssetNotModified({ etag, ifNoneMatch: 'W/"different"', mtimeMs: representation.stat.mtimeMs })).toBe(false); expect( isStaticAssetNotModified({ etag, ifModifiedSince: new Date(representation.stat.mtimeMs + 1_000).toUTCString(), mtimeMs: representation.stat.mtimeMs, }) ).toBe(true); }); test("gives revisioned locales immutable caching and unversioned locales a short revalidation window", () => { expect(getStaticCacheControl("/assets/app-hash.js", false)).toContain("immutable"); expect(getStaticCacheControl("/locales/de/common.json", true)).toContain("immutable"); expect(getStaticCacheControl("/locales/de/common.json", false)).toContain("must-revalidate"); }); });