import { describe, expect, test } from "bun:test";
import { createFetchHandler, type StaticAssets } from "../../src/server/app";
const staticAssets: StaticAssets = {
indexHtml: new Blob(['
Gateway Checker Demo'], {
type: "text/html",
}),
files: {
"/assets/app.js": new Blob(["console.log('demo');"], { type: "text/javascript" }),
},
};
describe("Bun fullstack runtime", () => {
const fetchHandler = createFetchHandler({ mode: "test", staticAssets });
const productionFetchHandler = createFetchHandler({ mode: "production", staticAssets });
test("/api/demo 返回 JSON demo 响应", async () => {
const response = await fetchHandler(new Request("http://localhost/api/demo"));
const body = await response.json();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain("application/json");
expect(body.message).toContain("/api/demo");
expect(body.runtime.mode).toBe("test");
});
test("/health 返回机器可读健康检查", async () => {
const response = await fetchHandler(new Request("http://localhost/health"));
const body = await response.json();
expect(response.status).toBe(200);
expect(body.ok).toBe(true);
expect(body.service).toBe("gateway-checker");
});
test("HEAD 请求运行时端点返回 headers 但无 body", async () => {
const response = await fetchHandler(new Request("http://localhost/api/demo", { method: "HEAD" }));
const body = await response.text();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain("application/json");
expect(body).toBe("");
});
test("HEAD 请求健康检查端点返回 headers 但无 body", async () => {
const response = await fetchHandler(new Request("http://localhost/health", { method: "HEAD" }));
const body = await response.text();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain("application/json");
expect(body).toBe("");
});
test("运行时端点拒绝不支持的 method", async () => {
const response = await fetchHandler(new Request("http://localhost/api/demo", { method: "POST" }));
const body = await response.json();
expect(response.status).toBe(405);
expect(response.headers.get("allow")).toBe("GET, HEAD");
expect(response.headers.get("content-type")).toContain("application/json");
expect(body.status).toBe(405);
expect(body.error).toBe("Method not allowed");
});
test("健康检查端点拒绝不支持的 method", async () => {
const response = await fetchHandler(new Request("http://localhost/health", { method: "POST" }));
const body = await response.json();
expect(response.status).toBe(405);
expect(response.headers.get("allow")).toBe("GET, HEAD");
expect(response.headers.get("content-type")).toContain("application/json");
expect(body.status).toBe(405);
expect(body.error).toBe("Method not allowed");
});
test("未知 /api/* 路由返回 JSON 404", async () => {
const response = await fetchHandler(new Request("http://localhost/api/missing"));
const body = await response.json();
expect(response.status).toBe(404);
expect(response.headers.get("content-type")).toContain("application/json");
expect(body.error).toBe("API route not found");
expect(body.status).toBe(404);
});
test("生产根路径返回前端入口", async () => {
const response = await fetchHandler(new Request("http://localhost/"));
const body = await response.text();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain("text/html");
expect(response.headers.get("cache-control")).toBe("no-cache");
expect(body).toContain("Gateway Checker Demo");
});
test("生产静态资源返回正确内容类型", async () => {
const response = await fetchHandler(new Request("http://localhost/assets/app.js"));
const body = await response.text();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain("text/javascript");
expect(response.headers.get("cache-control")).toBe("public, max-age=31536000, immutable");
expect(body).toContain("demo");
});
test("未知静态资源返回 404 且不 fallback 到入口 HTML", async () => {
const response = await fetchHandler(new Request("http://localhost/assets/missing.js"));
const body = await response.text();
expect(response.status).toBe(404);
expect(body).not.toContain("Gateway Checker Demo");
});
test("前端路由 fallback 到入口 HTML", async () => {
const response = await fetchHandler(new Request("http://localhost/dashboard"));
const body = await response.text();
expect(response.status).toBe(200);
expect(body).toContain("Gateway Checker Demo");
});
test("生产响应包含低风险安全 headers", async () => {
const json = await productionFetchHandler(new Request("http://localhost/api/demo"));
const html = await productionFetchHandler(new Request("http://localhost/"));
const asset = await productionFetchHandler(new Request("http://localhost/assets/app.js"));
for (const response of [json, html, asset]) {
expect(response.headers.get("x-content-type-options")).toBe("nosniff");
expect(response.headers.get("referrer-policy")).toBe("strict-origin-when-cross-origin");
}
});
});