返回 CodeWhale
truncate.test.ts
根目录 / web / lib / truncate.test.ts
1 import { readFileSync } from "node:fs";
2 import { describe, expect, it } from "vitest";
3 import { truncateChars } from "./truncate";
4
5 const webRoot = new URL("../", import.meta.url);
6 const ticker = readFileSync(new URL("components/ticker.tsx", webRoot), "utf8");
7 const roadmap = readFileSync(new URL("lib/roadmap-feed.ts", webRoot), "utf8");
8
9 describe("truncateChars", () => {
10 it("leaves text at or under the limit untouched", () => {
11 expect(truncateChars("short", 70)).toBe("short");
12 expect(truncateChars("x".repeat(70), 70)).toBe("x".repeat(70));
13 });
14
15 it("never splits an astral character in half", () => {
16 // `"…🐋".slice(0, 70)` cuts between the surrogates and emits a lone
17 // U+D83D, which renders as U+FFFD next to the ellipsis.
18 const title = `${"x".repeat(69)}🐋 whale support`;
19 const cut = truncateChars(title, 70);
20 expect(cut).toBe(`${"x".repeat(69)}🐋…`);
21 // No surrogate survives that is not half of a well-formed pair.
22 const unpaired = cut.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "");
23 expect(/[\uD800-\uDFFF]/.test(unpaired), "lone surrogate in output").toBe(false);
24 expect(title.slice(0, 70).charCodeAt(69)).toBe(0xd83d);
25 });
26
27 it("counts code points, not UTF-16 code units", () => {
28 // Forty whales are forty characters and eighty code units. The old
29 // `title.length > 70` test called this an 80-character title and cut it.
30 const whales = "🐋".repeat(40);
31 expect(whales.length).toBe(80);
32 expect(truncateChars(whales, 70)).toBe(whales);
33 });
34
35 it("supports a keep budget below the limit", () => {
36 expect(truncateChars("y".repeat(139), 140, 137)).toBe("y".repeat(139));
37 expect(truncateChars("y".repeat(141), 140, 137)).toBe(`${"y".repeat(137)}…`);
38 });
39
40 it("is the one truncation rule the GitHub-fed surfaces use", () => {
41 expect(ticker).toContain("truncateChars(title, 70)");
42 expect(ticker).not.toContain("title.slice(");
43 expect(roadmap).toContain("truncateChars(stripped, 140, 137)");
44 expect(roadmap).not.toContain("stripped.slice(");
45 });
46 });
47
47 lines TYPESCRIPT