syntaxai/tdd.md · main · src / b32_anchor_extract.test.ts

b32_anchor_extract.test.ts 58 lines · 1866 bytes raw
import { test, expect } from "bun:test";
import { extractAnchors } from "./b32_anchor_extract.ts";

test("extracts h2 with explicit id", () => {
  const html = `<h2 id="getting-started">Getting started</h2>`;
  expect(extractAnchors(html)).toEqual([
    { level: 2, text: "Getting started", id: "getting-started" },
  ]);
});

test("extracts h3 with explicit id", () => {
  const html = `<h3 id="why">Why</h3>`;
  expect(extractAnchors(html)).toEqual([
    { level: 3, text: "Why", id: "why" },
  ]);
});

test("ignores h1 and h4+", () => {
  const html = `<h1 id="t">T</h1><h2 id="a">A</h2><h4 id="b">B</h4>`;
  const anchors = extractAnchors(html);
  expect(anchors.map((a) => a.id)).toEqual(["a"]);
});

test("slugifies when id attribute is missing", () => {
  const html = `<h2>What this number does *not* measure</h2>`;
  const anchors = extractAnchors(html);
  expect(anchors[0]?.id).toBe("what-this-number-does-not-measure");
});

test("strips inline tags from text and id source", () => {
  const html = `<h3><code>red:</code> phase</h3>`;
  const anchors = extractAnchors(html);
  expect(anchors[0]?.text).toBe("red: phase");
  expect(anchors[0]?.id).toBe("red-phase");
});

test("returns multiple anchors in document order", () => {
  const html = `<h2 id="one">One</h2><p>x</p><h3 id="two">Two</h3><h2 id="three">Three</h2>`;
  const anchors = extractAnchors(html);
  expect(anchors.map((a) => `${a.level}:${a.id}`)).toEqual([
    "2:one",
    "3:two",
    "2:three",
  ]);
});

test("skips empty headings", () => {
  const html = `<h2 id="empty"></h2><h2 id="real">Real</h2>`;
  expect(extractAnchors(html).length).toBe(1);
});

test("handles HTML entities in text", () => {
  const html = `<h2>Tom &amp; Jerry</h2>`;
  const anchors = extractAnchors(html);
  expect(anchors[0]?.text).toBe("Tom & Jerry");
  expect(anchors[0]?.id).toBe("tom-jerry");
});