114 lines
3.1 KiB
TypeScript
114 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 });
|
|
});
|
|
});
|