muddle/tests/markdown.test.ts
2026-10-23 08:53:07 -04:00

104 lines
3.1 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { ContentRegistry } from "../core/content.ts";
import { resolveConfig } from "../core/config.ts";
import { markdownLoader, parseFrontmatter, renderMarkdown } from "../views/markdown.ts";
/**
* Tests of the markdown loader and of the content collections.
*/
describe("markdown", () => {
test("parses the frontmatter", () => {
const { frontmatter, body } = parseFrontmatter(
"---\ntitle: Hello\ndraft: false\ncount: 3\ntags:\n - a\n - b\n---\n\nBody",
);
expect(frontmatter.title).toBe("Hello");
expect(frontmatter.draft).toBe(false);
expect(frontmatter.count).toBe(3);
expect(frontmatter.tags).toEqual(["a", "b"]);
expect(body.trim()).toBe("Body");
});
test("renders the inline markup", () => {
expect(renderMarkdown("**bold** and *italic*")).toContain("<strong>bold</strong>");
expect(renderMarkdown("`code`")).toContain("<code>code</code>");
expect(renderMarkdown("[link](/x)")).toContain('<a href="/x">link</a>');
});
test("renders the blocks", () => {
const html = renderMarkdown(
"# Title\n\nA paragraph.\n\n- one\n- two\n\n> quoted\n\n```js\nconst a = 1;\n```",
);
expect(html).toContain("<h1>Title</h1>");
expect(html).toContain("<p>A paragraph.</p>");
expect(html).toContain("<li>one</li>");
expect(html).toContain("<blockquote>");
expect(html).toContain("<pre><code class=\"language-js\">");
});
});
describe("content collections", () => {
test("loads the entries of a collection", async () => {
const dir = await mkdtemp(join(tmpdir(), "muddle-content-"));
await writeFile(
join(dir, "first.md"),
"---\ntitle: First\n---\n\nHello **world**",
"utf8",
);
await writeFile(
join(dir, "second.md"),
"---\ntitle: Second\n---\n\nSecond note",
"utf8",
);
const registry = new ContentRegistry(
resolveConfig({
root: dir,
collections: [
{
name: "notes",
dir: ".",
loader: markdownLoader(),
schema: { required: ["title"] },
},
],
}),
);
await registry.load();
const entries = registry.entries("notes");
expect(entries).toHaveLength(2);
expect(entries[0]?.id).toBe("first");
expect(entries[0]?.frontmatter.title).toBe("First");
expect(entries[0]?.body).toContain("<strong>world</strong>");
expect(registry.get("notes", "second")?.frontmatter.title).toBe("Second");
await rm(dir, { recursive: true, force: true });
});
test("rejects an invalid frontmatter", async () => {
const dir = await mkdtemp(join(tmpdir(), "muddle-content-"));
await writeFile(join(dir, "broken.md"), "---\ndraft: true\n---\n\nBody", "utf8");
const registry = new ContentRegistry(
resolveConfig({
root: dir,
collections: [
{
name: "notes",
dir: ".",
loader: markdownLoader(),
schema: { required: ["title"] },
},
],
}),
);
await expect(registry.load()).rejects.toThrow("title is required");
await rm(dir, { recursive: true, force: true });
});
});