72 lines
3.0 KiB
TypeScript
72 lines
3.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
citationDomainLabel,
|
|
closeUnterminatedFence,
|
|
isExternalMarkdownUrl,
|
|
parseCitationBadgeLabel,
|
|
parseHexColorToken,
|
|
sanitizeMarkdownUrl,
|
|
} from "./markdown";
|
|
|
|
describe("sanitizeMarkdownUrl", () => {
|
|
it("allows normal external links and optionally allows local links", () => {
|
|
expect(sanitizeMarkdownUrl("https://example.com/docs")).toBe("https://example.com/docs");
|
|
expect(sanitizeMarkdownUrl("mailto:hello@example.com")).toBe("mailto:hello@example.com");
|
|
expect(sanitizeMarkdownUrl("/docs", true)).toBe("/docs");
|
|
expect(sanitizeMarkdownUrl("#section", true)).toBe("#section");
|
|
});
|
|
|
|
it("rejects executable and embedded-data URLs", () => {
|
|
expect(sanitizeMarkdownUrl("javascript:alert(1)", true)).toBeUndefined();
|
|
expect(sanitizeMarkdownUrl("data:text/html,<script>alert(1)</script>", true)).toBeUndefined();
|
|
expect(sanitizeMarkdownUrl("/docs")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("isExternalMarkdownUrl", () => {
|
|
it("identifies outbound links while excluding local paths and fragments", () => {
|
|
expect(isExternalMarkdownUrl("https://example.com/docs")).toBe(true);
|
|
expect(isExternalMarkdownUrl("http://85.215.232.220:8080/gudrun-review/")).toBe(true);
|
|
expect(isExternalMarkdownUrl("mailto:hello@example.com")).toBe(true);
|
|
expect(isExternalMarkdownUrl("/docs")).toBe(false);
|
|
expect(isExternalMarkdownUrl("#section")).toBe(false);
|
|
expect(isExternalMarkdownUrl(undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("parseHexColorToken", () => {
|
|
it("parses valid 3, 6, and 8 digit hex color tokens and rejects other strings", () => {
|
|
expect(parseHexColorToken("#6B4226")).toBe("#6B4226");
|
|
expect(parseHexColorToken(" #e8722a ")).toBe("#e8722a");
|
|
expect(parseHexColorToken("#fff")).toBe("#fff");
|
|
expect(parseHexColorToken("#FAF6F0FF")).toBe("#FAF6F0FF");
|
|
expect(parseHexColorToken("#12345")).toBeUndefined();
|
|
expect(parseHexColorToken("npm run dev")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("closeUnterminatedFence", () => {
|
|
it("temporarily closes a partial streaming code fence", () => {
|
|
expect(closeUnterminatedFence("Before\n```ts\nconst value = 1;")).toBe(
|
|
"Before\n```ts\nconst value = 1;\n```",
|
|
);
|
|
});
|
|
|
|
it("leaves complete markdown unchanged", () => {
|
|
const markdown = "```ts\nconst value = 1;\n```\n\nDone";
|
|
expect(closeUnterminatedFence(markdown)).toBe(markdown);
|
|
});
|
|
});
|
|
|
|
describe("parseCitationBadgeLabel and citationDomainLabel", () => {
|
|
it("recognizes numeric inline citation links and extracts domain labels", () => {
|
|
expect(parseCitationBadgeLabel("1", "https://arxiv.org/abs/2401.00001")).toBe("1");
|
|
expect(parseCitationBadgeLabel("[12]", "https://www.example.com/article")).toBe("12");
|
|
expect(parseCitationBadgeLabel("Read more", "https://example.com/article")).toBeUndefined();
|
|
expect(parseCitationBadgeLabel("1", "/relative/path")).toBeUndefined();
|
|
|
|
expect(citationDomainLabel("https://www.arxiv.org/abs/2401.00001")).toBe("arxiv.org");
|
|
expect(citationDomainLabel("invalid-url")).toBeUndefined();
|
|
});
|
|
});
|