80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test";
|
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import {
|
|
contentRss,
|
|
contentSitemap,
|
|
createSearchIndex,
|
|
defineCollection,
|
|
localContentLoader,
|
|
paginateContent,
|
|
parseFrontmatter,
|
|
remoteContentLoader,
|
|
searchContent,
|
|
} from "../src/index.ts";
|
|
const roots: string[] = [];
|
|
afterEach(async () =>
|
|
Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))),
|
|
);
|
|
const schema = {
|
|
parse(input: unknown) {
|
|
const value = input as Record<string, unknown>;
|
|
if (typeof value.title !== "string") throw new Error("title required");
|
|
return {
|
|
title: value.title,
|
|
draft: value.draft === true,
|
|
version: String(value.version ?? "v1"),
|
|
};
|
|
},
|
|
};
|
|
describe("typed content collections", () => {
|
|
test("loads, validates, renders, filters drafts and supports preview/versioning", async () => {
|
|
const root = join(tmpdir(), `wrn-content-${crypto.randomUUID()}`);
|
|
roots.push(root);
|
|
await mkdir(root);
|
|
await writeFile(
|
|
join(root, "hello.md"),
|
|
"---\ntitle: Hello\nversion: v1\n---\n# Welcome\nUseful documentation.",
|
|
);
|
|
await writeFile(join(root, "draft.mdx"), "---\ntitle: Draft\ndraft: true\n---\nHidden");
|
|
const collection = defineCollection({
|
|
name: "docs",
|
|
schema,
|
|
loader: localContentLoader(root),
|
|
previewToken: "secret",
|
|
});
|
|
expect(await collection.load()).toHaveLength(1);
|
|
const preview = await collection.load({ previewToken: "secret" });
|
|
expect(preview).toHaveLength(2);
|
|
expect(preview[1]!.html).toContain("<h1");
|
|
expect(await collection.get("hello", { version: "v1" })).not.toBeNull();
|
|
});
|
|
test("builds search, pagination, RSS and sitemap outputs", async () => {
|
|
const collection = defineCollection({
|
|
name: "docs",
|
|
schema,
|
|
loader: remoteContentLoader("https://cms.test/docs", {
|
|
fetch: async () =>
|
|
new Response(
|
|
JSON.stringify([
|
|
{ id: "guide", content: "---\ntitle: Guide\n---\n# Start\nSearch words" },
|
|
]),
|
|
) as any,
|
|
}),
|
|
});
|
|
const entries = await collection.load();
|
|
expect(searchContent(createSearchIndex(entries), "search words")).toHaveLength(1);
|
|
expect(paginateContent(entries, 1, 1)).toMatchObject({ total: 1, totalPages: 1 });
|
|
expect(contentRss(entries, { title: "Docs", baseUrl: "https://example.test/" })).toContain(
|
|
"<rss",
|
|
);
|
|
expect(contentSitemap(entries, "https://example.test/")).toContain(
|
|
"https://example.test/guide",
|
|
);
|
|
});
|
|
test("rejects malformed frontmatter", () => {
|
|
expect(() => parseFrontmatter("---\ntitle nope\n---\nbody")).toThrow("WRN-CONTENT-FRONTMATTER");
|
|
});
|
|
});
|