新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
140 lines
4.9 KiB
TypeScript
140 lines
4.9 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { afterEach, describe, it } from "node:test";
|
||
import {
|
||
absoluteCanonical,
|
||
canonicalPage,
|
||
canonicalPath,
|
||
homeCanonicalQuery,
|
||
isTrackingParam,
|
||
isWideShellPath,
|
||
parseSiteOrigin,
|
||
resolveSiteOrigin,
|
||
} from "./siteUrl.ts";
|
||
|
||
const prev = {
|
||
SITE_URL: process.env.SITE_URL,
|
||
NODE_ENV: process.env.NODE_ENV,
|
||
};
|
||
|
||
afterEach(() => {
|
||
if (prev.SITE_URL === undefined) delete process.env.SITE_URL;
|
||
else process.env.SITE_URL = prev.SITE_URL;
|
||
process.env.NODE_ENV = prev.NODE_ENV;
|
||
});
|
||
|
||
describe("parseSiteOrigin", () => {
|
||
it("去掉尾斜杠并保留端口", () => {
|
||
assert.equal(parseSiteOrigin("https://bbs.example.com/"), "https://bbs.example.com");
|
||
assert.equal(parseSiteOrigin("http://localhost:3000/"), "http://localhost:3000");
|
||
});
|
||
it("拒绝 API / 容器名 / 带路径 / 非 http", () => {
|
||
assert.equal(parseSiteOrigin("http://api:3001"), null);
|
||
assert.equal(parseSiteOrigin("https://bbs.example.com/forum"), null);
|
||
assert.equal(parseSiteOrigin("ftp://bbs.example.com"), null);
|
||
assert.equal(parseSiteOrigin("not-a-url"), null);
|
||
assert.equal(parseSiteOrigin(""), null);
|
||
});
|
||
it("生产态把容器 API 地址视为非法", () => {
|
||
process.env.SITE_URL = "http://api:3001";
|
||
process.env.NODE_ENV = "production";
|
||
assert.equal(resolveSiteOrigin(), null);
|
||
});
|
||
});
|
||
|
||
describe("resolveSiteOrigin", () => {
|
||
it("开发态无配置回退 localhost:3000", () => {
|
||
delete process.env.SITE_URL;
|
||
process.env.NODE_ENV = "development";
|
||
assert.equal(resolveSiteOrigin(), "http://localhost:3000");
|
||
});
|
||
it("生产态缺失不回退 localhost", () => {
|
||
delete process.env.SITE_URL;
|
||
process.env.NODE_ENV = "production";
|
||
assert.equal(resolveSiteOrigin(), null);
|
||
});
|
||
it("生产态使用 SITE_URL", () => {
|
||
process.env.SITE_URL = "https://bbs.example.com/";
|
||
process.env.NODE_ENV = "production";
|
||
assert.equal(resolveSiteOrigin(), "https://bbs.example.com");
|
||
});
|
||
});
|
||
|
||
describe("canonicalPath", () => {
|
||
it("首页无尾斜杠参数", () => {
|
||
assert.equal(canonicalPath("/"), "/");
|
||
assert.equal(canonicalPath("/post/12/"), "/post/12");
|
||
});
|
||
it("省略空值并丢掉追踪参数", () => {
|
||
assert.equal(
|
||
canonicalPath("/post/12", { utm_source: "x", fbclid: "1", page: 2, q: "" }),
|
||
"/post/12?page=2"
|
||
);
|
||
});
|
||
it("保留内容参数", () => {
|
||
assert.equal(canonicalPath("/", { board: 3, sort: "new", page: 2 }), "/?board=3&page=2&sort=new");
|
||
});
|
||
});
|
||
|
||
describe("canonicalPage", () => {
|
||
it("第一页与非法页码省略", () => {
|
||
assert.equal(canonicalPage(undefined), undefined);
|
||
assert.equal(canonicalPage("1"), undefined);
|
||
assert.equal(canonicalPage("0"), undefined);
|
||
assert.equal(canonicalPage("foo"), undefined);
|
||
assert.equal(canonicalPage("2"), 2);
|
||
});
|
||
});
|
||
|
||
describe("isTrackingParam", () => {
|
||
it("识别 utm 与常见点击 id", () => {
|
||
assert.equal(isTrackingParam("utm_source"), true);
|
||
assert.equal(isTrackingParam("gclid"), true);
|
||
assert.equal(isTrackingParam("page"), false);
|
||
});
|
||
});
|
||
|
||
describe("absoluteCanonical", () => {
|
||
it("拼出绝对地址", () => {
|
||
process.env.SITE_URL = "https://bbs.example.com";
|
||
process.env.NODE_ENV = "production";
|
||
assert.equal(absoluteCanonical("/post/9", { page: 2 }), "https://bbs.example.com/post/9?page=2");
|
||
});
|
||
});
|
||
|
||
describe("homeCanonicalQuery", () => {
|
||
it("默认排序与第一页省略;搜索丢掉 board", () => {
|
||
assert.deepEqual(homeCanonicalQuery({}, true), {});
|
||
assert.deepEqual(homeCanonicalQuery({ sort: "latest", page: "1" }, true), {});
|
||
assert.deepEqual(homeCanonicalQuery({ sort: "new" }, false), {});
|
||
assert.deepEqual(
|
||
homeCanonicalQuery({ q: " go ", board: "3", page: "2" }, true),
|
||
{ q: "go", page: 2 }
|
||
);
|
||
assert.deepEqual(
|
||
homeCanonicalQuery({ board: "3", sort: "new", page: "2" }, true),
|
||
{ board: 3, page: 2, sort: "new" }
|
||
);
|
||
});
|
||
});
|
||
|
||
describe("isWideShellPath(书库页放宽档位)", () => {
|
||
it("覆盖三种伪静态风格的书库路径", () => {
|
||
assert.equal(isWideShellPath("/library"), true);
|
||
assert.equal(isWideShellPath("/library/abc"), true);
|
||
assert.equal(isWideShellPath("/library/abc/read"), true);
|
||
assert.equal(isWideShellPath("/library.html"), true);
|
||
assert.equal(isWideShellPath("/library-abc.html"), true);
|
||
assert.equal(isWideShellPath("/library-abc.html?sec=2"), true);
|
||
assert.equal(isWideShellPath("/library-abc-read-2.html"), true);
|
||
});
|
||
it("非书库路径不放宽", () => {
|
||
assert.equal(isWideShellPath("/"), false);
|
||
assert.equal(isWideShellPath("/post-1.html"), false);
|
||
assert.equal(isWideShellPath("/p-about.html"), false);
|
||
assert.equal(isWideShellPath("/u/5"), false);
|
||
assert.equal(isWideShellPath("/admin/library"), false);
|
||
assert.equal(isWideShellPath("/my-library.html"), false);
|
||
assert.equal(isWideShellPath(null), false);
|
||
});
|
||
});
|