const fs = require("node:fs/promises"); const os = require("node:os"); const path = require("node:path"); const fp = require("fastify-plugin"); const startJobs = vi.fn(async () => ({ driver: "disabled" })); const { buildApp } = require("../../src/app"); function createPrismaPlugin() { return fp(async (app) => { app.decorate("prisma", { $queryRaw: vi.fn().mockResolvedValue([{ ok: 1 }]), employee: { findUnique: vi.fn(), }, }); }, { name: "test-prisma" }); } async function createClientDistFixture() { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "hyb-oa-static-cache-")); await fs.mkdir(path.join(tempDir, "assets"), { recursive: true }); await fs.writeFile(path.join(tempDir, "index.html"), "
"); await fs.writeFile(path.join(tempDir, "sw.js"), "self.addEventListener('install', () => undefined);"); await fs.writeFile(path.join(tempDir, "manifest.webmanifest"), JSON.stringify({ name: "hyb-oa" })); await fs.writeFile(path.join(tempDir, "registerSW.js"), "export const register = () => undefined;"); await fs.writeFile(path.join(tempDir, "workbox-abc123.js"), "self.__WB_MANIFEST = [];"); await fs.writeFile(path.join(tempDir, "assets/index-abc123.js"), "console.log('asset');"); return tempDir; } async function buildStaticApp(clientDistDir) { vi.stubEnv("NODE_ENV", "test"); vi.stubEnv("JWT_SECRET", "test-secret"); vi.stubEnv("SERVE_CLIENT_DIST", "true"); vi.stubEnv("CLIENT_DIST_DIR", clientDistDir); vi.stubEnv("STORAGE_DIR", path.join(clientDistDir, "..", "storage")); vi.stubEnv("JOBS_ENABLED", "false"); vi.stubEnv("DATABASE_URL", ""); return buildApp({ prismaPlugin: createPrismaPlugin(), startJobs, }); } describe("app static cache headers", () => { afterEach(() => { vi.clearAllMocks(); vi.unstubAllEnvs(); }); it("serves shell files with no-cache and fingerprinted assets with immutable cache", async () => { const clientDistDir = await createClientDistFixture(); const app = await buildStaticApp(clientDistDir); try { const indexResponse = await app.inject({ method: "GET", url: "/", headers: { accept: "text/html" }, }); const swResponse = await app.inject({ method: "GET", url: "/sw.js" }); const manifestResponse = await app.inject({ method: "GET", url: "/manifest.webmanifest" }); const registerResponse = await app.inject({ method: "GET", url: "/registerSW.js" }); const assetResponse = await app.inject({ method: "GET", url: "/assets/index-abc123.js" }); const workboxResponse = await app.inject({ method: "GET", url: "/workbox-abc123.js" }); expect(indexResponse.statusCode).toBe(200); expect(swResponse.statusCode).toBe(200); expect(manifestResponse.statusCode).toBe(200); expect(registerResponse.statusCode).toBe(200); expect(assetResponse.statusCode).toBe(200); expect(workboxResponse.statusCode).toBe(200); expect(indexResponse.headers["cache-control"]).toBe("no-cache, no-store, must-revalidate"); expect(swResponse.headers["cache-control"]).toBe("no-cache, no-store, must-revalidate"); expect(manifestResponse.headers["cache-control"]).toBe("no-cache, no-store, must-revalidate"); expect(registerResponse.headers["cache-control"]).toBe("no-cache, no-store, must-revalidate"); expect(assetResponse.headers["cache-control"]).toBe("public, max-age=31536000, immutable"); expect(workboxResponse.headers["cache-control"]).toBe("public, max-age=31536000, immutable"); } finally { await app.close(); await fs.rm(clientDistDir, { recursive: true, force: true }); } }, 20_000); });