import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterAll, describe, expect, it } from "vitest"; import { createApp } from "../src/http/app.ts"; import { EventBus } from "../src/http/sse.ts"; import { json, memoryLogger } from "./helpers.ts"; const root = mkdtempSync(join(tmpdir(), "umt-web-")); mkdirSync(join(root, "assets")); writeFileSync(join(root, "index.html"), "SPA"); writeFileSync(join(root, "assets", "app.js"), "console.log(1)"); afterAll(() => rmSync(root, { recursive: true, force: true })); function app() { return createApp({ config: { NODE_ENV: "production" }, logger: memoryLogger().logger, bus: new EventBus(5), role: "all", version: "0.0.0-test", webRoot: root, }); } describe("单容器静态托管(WEB_ROOT)", () => { it("存在的文件直接返回", async () => { const res = await app().request("/assets/app.js"); expect(res.status).toBe(200); expect(await res.text()).toBe("console.log(1)"); }); it("首页与前端路由回退 index.html", async () => { for (const path of ["/", "/settings", "/library/123"]) { const res = await app().request(path); expect(res.status, path).toBe(200); expect(res.headers.get("content-type")).toContain("text/html"); expect(await res.text()).toContain("SPA"); } }); it("/api 下的未知路径不回退,仍是 JSON", async () => { const health = await app().request("/api/v1/health"); expect((await json(health)).ok).toBe(true); const res = await app().request("/api/nope"); expect(res.status).toBe(404); expect((await json(res)).error.code).toBe("not_found"); }); });