From 5dea8c67117d05530ba6366537017d5d3fe97501 Mon Sep 17 00:00:00 2001 From: tmdeveloper007 Date: Fri, 26 Jun 2026 06:58:07 +0000 Subject: [PATCH] test: export digest-email helpers and add unit tests --- src/lib/digest-email.ts | 9 ++-- test/digest-email.test.ts | 110 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 test/digest-email.test.ts diff --git a/src/lib/digest-email.ts b/src/lib/digest-email.ts index 717fceee2..dbd9111d9 100644 --- a/src/lib/digest-email.ts +++ b/src/lib/digest-email.ts @@ -19,15 +19,16 @@ import type { DigestMetrics } from "@/lib/weekly-digest"; // ─── Helpers ────────────────────────────────────────────────────────────────── -function esc(s: string): string { - return s +export function esc(s: string): string { + const str = String(s); + return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } -function pluralise(n: number, singular: string, plural = `${singular}s`): string { +export function pluralise(n: number, singular: string, plural = `${singular}s`): string { return `${n} ${n === 1 ? singular : plural}`; } @@ -55,7 +56,7 @@ const LANG_COLOURS: Record = { Svelte: "#ff3e00", }; -function langColour(name: string): string { +export function langColour(name: string): string { return LANG_COLOURS[name] ?? "#64748b"; } diff --git a/test/digest-email.test.ts b/test/digest-email.test.ts new file mode 100644 index 000000000..282ab19d9 --- /dev/null +++ b/test/digest-email.test.ts @@ -0,0 +1,110 @@ +import { describe, it, expect } from "vitest"; +import { esc, pluralise, langColour } from "@/lib/digest-email"; + +describe("esc", () => { + it("escapes ampersand", () => { + expect(esc("a & b")).toBe("a & b"); + }); + + it("escapes less-than sign", () => { + expect(esc("
")).toBe("<div>"); + }); + + it("escapes greater-than sign", () => { + expect(esc("a > b")).toBe("a > b"); + }); + + it("escapes double-quote", () => { + expect(esc('say "hello"')).toBe("say "hello""); + }); + + it("escapes multiple special characters together", () => { + expect(esc('')).toBe( + "<script>alert("xss")</script>" + ); + }); + + it("returns plain string unchanged", () => { + expect(esc("hello world")).toBe("hello world"); + }); + + it("returns empty string for empty input", () => { + expect(esc("")).toBe(""); + }); + + it("returns numbers coerced to string", () => { + expect(esc(42 as unknown as string)).toBe("42"); + }); +}); + +describe("pluralise", () => { + it("uses singular form when n equals 1", () => { + expect(pluralise(1, "commit")).toBe("1 commit"); + }); + + it("uses plural form when n is 0", () => { + expect(pluralise(0, "commit")).toBe("0 commits"); + }); + + it("uses plural form when n is greater than 1", () => { + expect(pluralise(5, "commit")).toBe("5 commits"); + }); + + it("uses default plural (singular + 's')", () => { + expect(pluralise(2, "star")).toBe("2 stars"); + }); + + it("uses custom plural string when provided", () => { + expect(pluralise(2, "leaf", "leaves")).toBe("2 leaves"); + }); + + it("uses singular form with custom plural when n equals 1", () => { + expect(pluralise(1, "leaf", "leaves")).toBe("1 leaf"); + }); + + it("handles large numbers", () => { + expect(pluralise(1000, "commit")).toBe("1000 commits"); + }); +}); + +describe("langColour", () => { + it("returns TypeScript colour", () => { + expect(langColour("TypeScript")).toBe("#3178c6"); + }); + + it("returns JavaScript colour", () => { + expect(langColour("JavaScript")).toBe("#f7df1e"); + }); + + it("returns Python colour", () => { + expect(langColour("Python")).toBe("#3776ab"); + }); + + it("returns Go colour", () => { + expect(langColour("Go")).toBe("#00add8"); + }); + + it("returns Rust colour", () => { + expect(langColour("Rust")).toBe("#ce412b"); + }); + + it("returns CSS colour", () => { + expect(langColour("CSS")).toBe("#563d7c"); + }); + + it("returns HTML colour", () => { + expect(langColour("HTML")).toBe("#e34c26"); + }); + + it("returns default colour for unknown language", () => { + expect(langColour("MyCoolLanguage")).toBe("#64748b"); + }); + + it("returns default colour for empty string", () => { + expect(langColour("")).toBe("#64748b"); + }); + + it("is case-sensitive", () => { + expect(langColour("typescript")).toBe("#64748b"); + }); +});