文件
hyb-oa/server/tests/unit/app.static-cache.test.js
T
wangsli 8353efcbd7
ci-e2e / e2e (push) Waiting to run
ci-minimal / check-minimal (push) Waiting to run
R65 A1-A6:Session 稳定性与 409 资源错误修复
2026-04-16 20:23:54 +08:00

94 行
3.7 KiB
JavaScript

const fs = require("node:fs/promises");
const os = require("node:os");
const path = require("node:path");
const createPrismaClient = vi.fn(() => ({
prisma: {
$connect: vi.fn().mockResolvedValue(undefined),
$disconnect: vi.fn().mockResolvedValue(undefined),
employee: {
findUnique: vi.fn(),
},
},
pool: {
end: vi.fn().mockResolvedValue(undefined),
},
}));
const startJobs = vi.fn(async () => ({ driver: "disabled" }));
vi.mock("../../src/prismaClient", () => ({
createPrismaClient,
}));
vi.mock("../../src/jobs/jobSystem", () => ({
startJobs,
}));
const { buildApp } = require("../../src/app");
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"), "<!doctype html><html><body><div id=\"root\"></div></body></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");
return buildApp();
}
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);
});