From 99570f1a3d18bd6c0774d8e9ca753c02c50ee062 Mon Sep 17 00:00:00 2001 From: Koji Wakayama Date: Tue, 11 Aug 2026 21:57:06 +0200 Subject: [PATCH] test(chat): check the renderer warning's anchor against the guide it links to The missing-Markdown-renderer warning deep-links to a section of the chat-ui guide. The test that guards that link asserted the whole URL against a second copy of the same string, so it could only catch someone editing the constant -- never someone renaming the heading the fragment names. A fragment that names no heading does not 404; the reader silently lands at the top of the article, so nothing else catches it either. Resolve the published URL back to the repository file it is published from and assert the fragment against that file's headings. Renaming the section now fails here, and the failure lists the headings that do exist. Resolve the doc path from import.meta.url rather than the process cwd: test files share one process under --parallel and src/testing/cwd.ts chdirs it. --- .../chat/missing-renderer-warning.test.ts | 90 ++++++++++++++++--- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/src/react/components/chat/missing-renderer-warning.test.ts b/src/react/components/chat/missing-renderer-warning.test.ts index bf8c0dc831..9078881e48 100644 --- a/src/react/components/chat/missing-renderer-warning.test.ts +++ b/src/react/components/chat/missing-renderer-warning.test.ts @@ -1,21 +1,87 @@ -import { assertEquals } from "#veryfront/testing/assert"; +import { assert, assertEquals } from "#veryfront/testing/assert"; import { describe, it } from "#veryfront/testing/bdd"; +import { fromFileUrl } from "@std/path"; import { MISSING_MARKDOWN_RENDERER_WARNING } from "./missing-renderer-warning.ts"; /** - * The warning's only escape hatch is the documentation link, so the link has to - * resolve. The published guide lives under `/docs/code/guides/chat-ui` - * (`/docs/guides/chat-ui` is a 404), and the fragment has to track the heading - * in this repo's `docs/guides/chat-ui.md`, which is the source the published - * site is generated from: "## Render Markdown in chat" slugs to - * `#render-markdown-in-chat`. + * The warning's only escape hatch is the documentation link, so the whole link + * has to resolve: the page and the fragment. + * + * The page is published from this repository's `docs/` tree under + * `/docs/code/`, so the URL also names the file that has to carry the anchor. + * Asserting the fragment against that file's headings -- rather than against a + * second copy of the string -- means renaming the section fails here instead of + * shipping a link that lands readers at the top of the article. */ + +/** Prefix under which veryfront-code's docs/ tree is published. */ +const PUBLISHED_DOCS_PREFIX = "https://veryfront.com/docs/code/"; + +/** Repository root, resolved from this module so the process cwd cannot move it. */ +const REPO_ROOT = fromFileUrl(new URL("../../../../", import.meta.url)); + +/** + * Resolve a published docs URL back to the repository file behind it. + * Deriving the path keeps the two in step: moving the guide without moving the + * link fails this test. + */ +function localFileForDocsUrl(url: URL): string { + const withoutFragment = `${url.origin}${url.pathname}`; + assert( + withoutFragment.startsWith(PUBLISHED_DOCS_PREFIX), + `the warning must link into the published veryfront-code docs tree ` + + `(${PUBLISHED_DOCS_PREFIX}...), got: ${withoutFragment}`, + ); + return `${REPO_ROOT}docs/${withoutFragment.slice(PUBLISHED_DOCS_PREFIX.length)}.md`; +} + +/** + * Anchor ids the published page exposes. Headings are slugified to lowercase + * hyphenated text. + */ +function anchorsIn(markdown: string): Set { + const anchors = new Set(); + for (const line of markdown.split("\n")) { + const heading = /^#{2,6}\s+(.+?)\s*$/.exec(line)?.[1]; + if (heading) anchors.add(heading.toLowerCase().replace(/\s+/g, "-")); + } + return anchors; +} + +/** The single link the warning ships. */ +function warningLink(): URL { + const links = MISSING_MARKDOWN_RENDERER_WARNING.match(/https:\/\/\S+/g) ?? []; + assertEquals( + links.length, + 1, + `the warning must carry exactly one link, got: ${links.join(", ")}`, + ); + return new URL(links[0] as string); +} + describe("missing Markdown renderer warning — documentation link", () => { - it("carries exactly one link, and it is the published chat-ui guide", () => { - const links = MISSING_MARKDOWN_RENDERER_WARNING.match(/https:\/\/\S+/g) ?? []; + it("points at the published chat-ui guide", () => { + const link = warningLink(); + + assertEquals( + `${link.origin}${link.pathname}`, + "https://veryfront.com/docs/code/guides/chat-ui", + "`/docs/guides/chat-ui` is a 404; the guide is published under `/docs/code/`", + ); + }); + + it("names a section that exists in the guide it links to", async () => { + const link = warningLink(); + const docFile = localFileForDocsUrl(link); + const anchors = anchorsIn(await Deno.readTextFile(docFile)); + const fragment = decodeURIComponent(link.hash.replace(/^#/, "")); - assertEquals(links, [ - "https://veryfront.com/docs/code/guides/chat-ui#render-markdown-in-chat", - ]); + assert(fragment !== "", "the warning must deep-link to the renderer section, not the page top"); + assert( + anchors.has(fragment), + `no "#${fragment}" heading in ${docFile}. A reader following the warning lands at the ` + + `top of the article instead of the section. Headings present: ` + + `${[...anchors].join(", ")}`, + ); }); });