feat: 初始提交
This commit is contained in:
127
tests/server/static.test.ts
Normal file
127
tests/server/static.test.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import {
|
||||
contentTypeFor,
|
||||
hasFileExtension,
|
||||
htmlResponse,
|
||||
serveStaticAsset,
|
||||
type StaticAssets,
|
||||
} from "../../src/server/static";
|
||||
|
||||
function createTestAssets(): StaticAssets {
|
||||
return {
|
||||
files: {
|
||||
"/assets/index-a1b2c3.css": new Blob([".app{}"], { type: "text/css" }),
|
||||
"/assets/index-a1b2c3.js": new Blob(["console.log(1)"], { type: "text/javascript" }),
|
||||
"/assets/vendor-react-x9y8z7.js": new Blob(["react"], { type: "text/javascript" }),
|
||||
"/favicon.svg": new Blob(["<svg/>"], { type: "image/svg+xml" }),
|
||||
},
|
||||
indexHtml: new Blob(["<!doctype html><html></html>"], { type: "text/html" }),
|
||||
};
|
||||
}
|
||||
|
||||
describe("contentTypeFor", () => {
|
||||
test("JavaScript 文件", () => {
|
||||
expect(contentTypeFor("/assets/index-a1b2c3.js")).toBe("text/javascript; charset=utf-8");
|
||||
});
|
||||
|
||||
test("mjs 文件", () => {
|
||||
expect(contentTypeFor("/assets/chunk.mjs")).toBe("text/javascript; charset=utf-8");
|
||||
});
|
||||
|
||||
test("CSS 文件", () => {
|
||||
expect(contentTypeFor("/assets/style.css")).toBe("text/css; charset=utf-8");
|
||||
});
|
||||
|
||||
test("SVG 文件", () => {
|
||||
expect(contentTypeFor("/icon.svg")).toBe("image/svg+xml");
|
||||
});
|
||||
|
||||
test("未知扩展名返回 octet-stream", () => {
|
||||
expect(contentTypeFor("/file.xyz")).toBe("application/octet-stream");
|
||||
});
|
||||
|
||||
test("无扩展名返回 octet-stream", () => {
|
||||
expect(contentTypeFor("/noext")).toBe("application/octet-stream");
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasFileExtension", () => {
|
||||
test("有扩展名", () => {
|
||||
expect(hasFileExtension("/assets/index.js")).toBe(true);
|
||||
expect(hasFileExtension("/favicon.svg")).toBe(true);
|
||||
});
|
||||
|
||||
test("无扩展名", () => {
|
||||
expect(hasFileExtension("/dashboard")).toBe(false);
|
||||
expect(hasFileExtension("/")).toBe(false);
|
||||
expect(hasFileExtension("/api/targets")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("htmlResponse", () => {
|
||||
test("返回 HTML 响应带正确 headers", async () => {
|
||||
const blob = new Blob(["<html></html>"]);
|
||||
const response = htmlResponse(blob);
|
||||
|
||||
expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
|
||||
expect(response.headers.get("Cache-Control")).toBe("no-cache");
|
||||
expect(await response.text()).toBe("<html></html>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("serveStaticAsset", () => {
|
||||
test("根路径返回 indexHtml", async () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/", assets);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
|
||||
expect(response.headers.get("Cache-Control")).toBe("no-cache");
|
||||
expect(await response.text()).toBe("<!doctype html><html></html>");
|
||||
});
|
||||
|
||||
test("已知资源返回对应文件和 immutable 缓存", async () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/assets/index-a1b2c3.js", assets);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("Content-Type")).toBe("text/javascript; charset=utf-8");
|
||||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=31536000, immutable");
|
||||
expect(await response.text()).toBe("console.log(1)");
|
||||
});
|
||||
|
||||
test("未知带扩展名路径返回 404", () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/assets/missing.js", assets);
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
test("SPA fallback — 无扩展名路径返回 indexHtml", async () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/dashboard", assets);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
|
||||
expect(response.headers.get("Cache-Control")).toBe("no-cache");
|
||||
expect(await response.text()).toBe("<!doctype html><html></html>");
|
||||
});
|
||||
|
||||
test("SVG 资源返回正确 Content-Type", () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/favicon.svg", assets);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("Content-Type")).toBe("image/svg+xml");
|
||||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=31536000, immutable");
|
||||
});
|
||||
|
||||
test("CSS 资源返回正确 Content-Type", () => {
|
||||
const assets = createTestAssets();
|
||||
const response = serveStaticAsset("/assets/index-a1b2c3.css", assets);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("Content-Type")).toBe("text/css; charset=utf-8");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user