Files
scriptc/docs/test/routes.test.mjs
Chris Tate 5aa450c6b2 docs: migrate to Geistdocs (#611)
* docs: migrate to Geistdocs

* Restore compiler files to main
2026-10-02 00:58:25 -05:00

184 lines
8.9 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { test } from "node:test";
import { description, siteUrl } from "../src/lib/site.ts";
const base = process.env.DOCS_TEST_URL;
assert.ok(base, "Set DOCS_TEST_URL to a running production build.");
const pages = JSON.parse(await readFile(new URL("./fixtures/migration-baseline.json", import.meta.url), "utf8"));
const get = (path, headers = {}) => fetch(new URL(path, base), {
redirect: "manual",
signal: AbortSignal.timeout(30_000),
headers: { "user-agent": "Mozilla/5.0", accept: "text/html", ...headers },
});
const decode = (text) => text.replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#x27;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
const meta = (html, key) => decode(html.match(new RegExp(`<meta (?:name|property)="${key}" content="([^"]*)"`))?.[1] ?? "");
for (const { href, title, headings } of pages) {
test(`${href} preserves its title, social card and published heading anchors`, async () => {
const response = await get(href);
assert.equal(response.status, 200);
const html = await response.text();
assert.equal(decode(html.match(/<title>([^<]*)<\/title>/)?.[1] ?? ""), `${title} | scriptc`);
assert.equal(meta(html, "description"), description);
assert.equal(meta(html, "og:title"), `${title} | scriptc`);
assert.ok(html.includes(`<link rel="canonical" href="${siteUrl}${href}"`));
assert.equal((html.match(/<h1\b/g) ?? []).length, 1);
assert.ok(html.includes('data-geistdocs-article="title"'));
assert.ok(html.includes('data-geistdocs-article="body"'));
for (const heading of headings) assert.ok(html.includes(`id="${heading.id}"`), `missing anchor ${heading.id}`);
});
}
test("previous docs URLs redirect permanently and preserve query parameters", async () => {
for (const { legacy, href } of pages) {
const response = await get(`${legacy}?mode=static`);
assert.equal(response.status, 308, legacy);
const destination = new URL(response.headers.get("location"), base);
assert.equal(destination.pathname, href);
assert.equal(destination.search, "?mode=static");
}
assert.equal((await get("/docs/introduction")).headers.get("location"), "/docs");
});
test("Markdown twins preserve examples and declare the HTML canonical URL", async () => {
for (const { href } of pages) {
const response = await get(`${href}.md`);
assert.equal(response.status, 200, href);
assert.match(response.headers.get("content-type"), /^text\/markdown/);
assert.ok(response.headers.get("link")?.includes(`<${siteUrl}${href}>; rel="canonical"`));
const markdown = await response.text();
const file = href === "/docs" ? "index" : href.slice("/docs/".length);
const source = await readFile(new URL(`../content/docs/${file}.mdx`, import.meta.url), "utf8");
for (const fence of source.matchAll(/^```[^\n]*\n([\s\S]*?)^```/gm)) {
assert.ok(markdown.includes(fence[1].trimEnd()), `${file} lost a code example`);
}
assert.doesNotMatch(markdown, /className=/);
}
const mdx = await get("/docs/quickstart.mdx");
assert.equal(mdx.status, 200);
assert.match(mdx.headers.get("content-type"), /^text\/markdown/);
});
test("literal HTML tables and definition lists remain readable", async () => {
const intro = await (await get("/docs")).text();
assert.match(intro, /<table[ >]/);
const cli = await (await get("/docs/cli")).text();
assert.match(cli, /<dl[ >]/);
assert.match(cli, /<dt[ >]/);
const markdown = await (await get("/docs/cli.md")).text();
assert.ok(markdown.includes("--dynamic"));
assert.ok(markdown.includes("--external-types"));
});
test("docs negotiate Markdown and keep browser HTML and prefetch payloads", async () => {
for (const headers of [{ accept: "text/markdown" }, { "user-agent": "ClaudeBot/1.0", accept: "*/*" }]) {
const response = await get("/docs/quickstart", headers);
assert.equal(response.status, 200);
assert.match(response.headers.get("content-type"), /^text\/markdown/);
await response.body?.cancel();
}
const html = await get("/docs/quickstart");
assert.match(html.headers.get("content-type"), /^text\/html/);
await html.body?.cancel();
// Next.js can add its _rsc hash with a redirect before returning the payload.
const prefetch = await fetch(new URL("/docs/quickstart", base), {
signal: AbortSignal.timeout(30_000),
headers: { rsc: "1", "next-router-prefetch": "1", accept: "*/*", "user-agent": "ClaudeBot/1.0" },
});
assert.equal(prefetch.status, 200);
assert.doesNotMatch(prefetch.headers.get("content-type"), /markdown/);
await prefetch.body?.cancel();
});
test("unknown pages return 404 in HTML and Markdown", async () => {
for (const path of ["/docs/missing-page", "/docs/missing-page.md", "/missing-page"]) {
const response = await get(path);
assert.equal(response.status, 404, path);
await response.body?.cancel();
}
});
test("agent and search indexes include every documentation page", async () => {
const llms = await (await get("/llms.txt")).text();
const sitemapMarkdown = await (await get("/sitemap.md")).text();
const sitemap = await (await get("/sitemap.xml")).text();
for (const { href } of pages) {
assert.ok(llms.includes(`${siteUrl}${href}`), `llms.txt lacks ${href}`);
assert.ok(sitemapMarkdown.includes(href), `sitemap.md lacks ${href}`);
assert.ok(sitemap.includes(`<loc>${siteUrl}${href}</loc>`), `sitemap.xml lacks ${href}`);
}
const agents = await (await get("/agents.md")).text();
assert.ok(agents.includes("scriptc"));
assert.ok(agents.includes("/compatibility"));
const search = await get("/api/search?query=runtime%20type%20checks");
assert.equal(search.status, 200);
assert.ok((await search.json()).some((result) => result.url === "/docs/limitations#runtime-type-checks"));
});
test("internal documentation links and their fragments resolve", async () => {
const anchors = new Map();
for (const { href } of pages) anchors.set(href, await (await get(href)).text());
for (const { href } of pages) {
const file = href === "/docs" ? "index" : href.slice("/docs/".length);
const source = await readFile(new URL(`../content/docs/${file}.mdx`, import.meta.url), "utf8");
for (const [, path, fragment] of source.matchAll(/\]\((\/docs(?:\/[\w-]+)?)(?:#([\w-]+))?\)/g)) {
assert.ok(anchors.has(path), `${href} links to missing page ${path}`);
if (fragment) assert.ok(anchors.get(path).includes(`id="${fragment}"`), `${href} links to missing fragment ${path}#${fragment}`);
}
}
});
test("compatibility page and data endpoints keep their existing contracts", async () => {
const page = await get("/compatibility");
assert.equal(page.status, 200);
const html = await page.text();
assert.ok(html.includes("Node.js 24 Compatibility"));
assert.ok(html.includes(`<link rel="canonical" href="${siteUrl}/compatibility"`));
const response = await get("/compatibility/data");
assert.equal(response.status, 200);
const dataset = await response.json();
const metadata = JSON.parse(await readFile(new URL("../src/generated/node-v24-compatibility-meta.json", import.meta.url), "utf8"));
assert.equal(dataset.rows.length, metadata.rowCount);
assert.equal((await get("/node-compatibility")).status, 308);
assert.equal((await get("/node-compatibility/data")).status, 308);
});
test("WebMCP serves its bridge and discovery manifest", async () => {
const response = await get("/api/mcp?webmcp-script");
assert.equal(response.status, 200);
assert.match(response.headers.get("content-type"), /javascript/);
assert.match(await response.text(), /registerTool/);
const manifest = await get("/.well-known/mcp.json");
assert.equal(manifest.status, 200);
assert.ok((await manifest.json()).servers.some((server) => server.url.endsWith("/api/mcp")));
});
test("homepage negotiates the agent profile and preserves explicit HTML requests", async () => {
for (const headers of [{ accept: "text/markdown" }, { "user-agent": "ClaudeBot/1.0", accept: "*/*" }]) {
const response = await get("/", headers);
assert.equal(response.status, 200);
assert.match(response.headers.get("content-type"), /^text\/markdown/);
assert.ok((await response.text()).includes("/compatibility"));
}
const html = await get("/", { "user-agent": "ClaudeBot/1.0", accept: "text/html" });
assert.equal(html.status, 200);
assert.match(html.headers.get("content-type"), /^text\/html/);
await html.body?.cancel();
});
test("homepage and existing social images still render", async () => {
const home = await get("/");
assert.equal(home.status, 200);
const html = await home.text();
assert.ok(html.includes('href="/docs/quickstart"'));
assert.ok(html.includes("832040"));
assert.doesNotMatch(html, /~320KB|~620KB|about 4ms|~35ms/);
for (const path of ["/og", "/og/limitations"]) {
const image = await get(path);
assert.equal(image.status, 200, path);
assert.match(image.headers.get("content-type"), /^image\/png/);
await image.body?.cancel();
}
});