# test.content/core/renderers/wiki.renderer.test.ts

> 158 lines of code and 0 definitions.

Tree: Codebase Testing
Language: typescript
Canonical: https://banes-lab.com/anatomy/testing#file-testing-test-content-core-renderers-wiki-renderer-test-ts
Source text: https://banes-lab.com/source/testing/test.content/core/renderers/wiki.renderer.test.ts.txt

Listed in [test.content/core/renderers](https://banes-lab.com/api/source/testing/test.content/core/renderers.md), after [test.content/core/renderers/readme.renderer.test.ts](https://banes-lab.com/source/testing/test.content/core/renderers/readme.renderer.test.ts.md).

## Contained in

- [test.content/core/renderers](https://banes-lab.com/anatomy/testing/folder-testing-test-content-core-renderers.md)

## Source

```typescript
import { ANATOMY_PAGE, FAQ_PAGE, METHODOLOGY_PAGE } from "@banes-lab/web/core/ids/page.ids.ts";
import type { Attribution, ChapterSource, PageSources, ShapeInput } from "@banes-lab/content/types/chapter.types.ts";
import { METHODOLOGY_REPOSITORY, SITE_URL, tabLink } from "@banes-lab/web/core/assets/link.assets.ts";
import { READING_TAB, TREE_TAB } from "@banes-lab/web/core/ids/anatomy.ids.ts";
import { describe, expect, it } from "vitest";
import { isSiteOnly, pageStemOf, renderWiki, wikiResolver } from "@banes-lab/content/core/renderers/wiki.renderer.ts";
import { attributionLine } from "@banes-lab/content/core/renderers/markdown.renderer.ts";

const ATTRIBUTION: Attribution = {
    author: "Author",
    copyright: "© 2025 ",
    coveredBy: "Documentation is covered by ",
    licenseName: "CC BY-SA 4.0",
    licenseUrl: "https://creativecommons.org/licenses/by-sa/4.0/",
    work: " - Work",
};

const INTRODUCTION: ChapterSource = {
    first: true,
    label: "Introduction",
    markdown:
        "# Page\n\nIntro alternate, see [the model](/disciplined-methodology/mental-model#loop), [the faq](/faq) and [a term](/ontology#architecture-x).\n",
    tab: "introduction",
};
const MODEL: ChapterSource = {
    first: false,
    label: "Mental Model",
    markdown: "# Mental model\n\nFirst alternate, back to [home](/disciplined-methodology#top).\n",
    tab: "mental-model",
};
const OBSERVATION: ChapterSource = {
    first: false,
    label: "Observation",
    markdown: "# Observation\n\nSecond alternate.\n",
    tab: "observation",
};
const SOURCES: ChapterSource[] = [INTRODUCTION, MODEL, OBSERVATION];

const FAQ: ChapterSource[] = [{ first: true, label: "FAQ", markdown: "# FAQ\n\nQuestions.\n", tab: FAQ_PAGE }];

const SINGLE: ShapeInput = { pages: [{ label: "Method", page: METHODOLOGY_PAGE, sources: SOURCES }], readme: null };
const MANY: ShapeInput = {
    pages: [
        { label: "Method", page: METHODOLOGY_PAGE, sources: SOURCES },
        { label: "FAQ", page: FAQ_PAGE, sources: FAQ },
    ],
    readme: null,
};

describe("pageStemOf", () => {
    it("numbers a page in reading order and joins the label's words with hyphens, prefixed by its group when the group adds a word", () => {
        expect(pageStemOf(MODEL, 1)).toBe("01-Mental-Model");
        expect(pageStemOf(OBSERVATION, 12)).toBe("12-Observation");
        expect(pageStemOf(OBSERVATION, 3, "Method")).toBe("03-Method.Observation");
        expect(pageStemOf(FAQ[0] ?? MODEL, 4, "FAQ")).toBe("04-FAQ");
    });
});

describe("wikiResolver", () => {
    it("maps a rendered route to its stem, the front page's own route to Home when it holds no numbered page, and the rest to nothing", () => {
        const pages = [
            { group: "Method", hosted: true, href: "01-Mental-Model", page: METHODOLOGY_PAGE, source: MODEL },
        ];
        const resolve = wikiResolver(pages, METHODOLOGY_PAGE);
        expect(resolve(METHODOLOGY_PAGE, "mental-model")).toBe("01-Mental-Model");
        expect(resolve(METHODOLOGY_PAGE, null)).toBe("Home");
        expect(resolve(FAQ_PAGE, null)).toBeNull();
    });
});

describe("renderWiki over one page", () => {
    const pages = renderWiki(SINGLE, ATTRIBUTION);
    const files = pages.map((page) => page.file);

    it("writes Home, one numbered page per tab, the sidebar and the footer", () => {
        expect(files).toStrictEqual([
            "Home.md",
            "01-Mental-Model.md",
            "02-Observation.md",
            "_Sidebar.md",
            "_Footer.md",
        ]);
    });

    it("opens Home with the page alternate and closes it with the reading path", () => {
        const home = pages[0]?.body ?? "";
        expect(home.startsWith("# Page")).toBe(true);
        expect(home).toContain("- [Mental Model](01-Mental-Model)\n- [Observation](02-Observation)");
    });

    it("rewrites a root-relative link to the wiki page that holds it, Home included, or to the site", () => {
        expect(pages[0]?.body).toContain("[the model](01-Mental-Model#loop)");
        expect(pages[0]?.body).toContain("[the faq](https://banes-lab.com/faq)");
        expect(pages[0]?.body).toContain("[a term](https://banes-lab.com/ontology#architecture-x)");
        expect(pages[1]?.body).toContain("[home](Home#top)");
    });

    it("links each page to its neighbors, Home standing in before the first", () => {
        expect(pages[1]?.body).toContain("[Home](Home) · [Observation](02-Observation)");
        expect(pages[2]?.body.trimEnd().endsWith("[Mental Model](01-Mental-Model)")).toBe(true);
    });

    it("lists Home, the reading path and the repository links in the sidebar", () => {
        const sidebar = pages[3]?.body ?? "";
        expect(sidebar).toContain("[Home](Home)");
        expect(sidebar).toContain("- [Mental Model](01-Mental-Model)");
        expect(sidebar).toContain(`[Repository](${METHODOLOGY_REPOSITORY})`);
        expect(sidebar).toContain(`[Discussions](${METHODOLOGY_REPOSITORY}/discussions)`);
    });

    it("carries the attribution line as the footer", () => {
        expect(pages[4]?.body.trimEnd()).toBe(attributionLine(ATTRIBUTION));
    });
});

describe("renderWiki over every teaching page", () => {
    const pages = renderWiki(MANY, ATTRIBUTION);

    it("numbers every tab of every page in order, first tabs included, prefixed by the page, and groups the reading path", () => {
        expect(pages.map((page) => page.file)).toStrictEqual([
            "Home.md",
            "01-Method.Introduction.md",
            "02-Method.Mental-Model.md",
            "03-Method.Observation.md",
            "04-FAQ.md",
            "_Sidebar.md",
            "_Footer.md",
        ]);
        expect(pages[0]?.body).toContain("**Method**\n- [Introduction](01-Method.Introduction)");
        expect(pages[0]?.body).toContain("**FAQ**\n- [FAQ](04-FAQ)");
        expect(pages[0]?.body.startsWith("# Page")).toBe(true);
    });

    it("resolves a link to another teaching page to its numbered wiki page", () => {
        expect(pages[0]?.body).toContain("[the faq](04-FAQ)");
        expect(pages[2]?.body).toContain("[home](01-Method.Introduction#top)");
    });
});

describe("renderWiki over a page with a site-only tab", () => {
    const anatomy: PageSources = {
        label: "Anatomy",
        page: ANATOMY_PAGE,
        sources: [
            {
                first: true,
                label: "Reading",
                markdown: "# Reading\n\nSee [the tree](/anatomy/tree#file-x).\n",
                tab: READING_TAB,
            },
            { first: false, label: "Source tree", markdown: "# Tree\n", tab: TREE_TAB },
        ],
    };
    const pages = renderWiki(
        { pages: [{ label: "Method", page: METHODOLOGY_PAGE, sources: SOURCES }, anatomy], readme: null },
        ATTRIBUTION,
    );

    it("keeps the derived tab off the wiki, lists it as a site link in the reading path and resolves links to it there", () => {
        expect(isSiteOnly(ANATOMY_PAGE, TREE_TAB)).toBe(true);
        expect(isSiteOnly(ANATOMY_PAGE, READING_TAB)).toBe(false);
        expect(pages.map((page) => page.file)).toStrictEqual([
            "Home.md",
            "01-Method.Introduction.md",
            "02-Method.Mental-Model.md",
            "03-Method.Observation.md",
            "04-Anatomy.Reading.md",
            "_Sidebar.md",
            "_Footer.md",
        ]);
        const tree = `${SITE_URL}${tabLink(ANATOMY_PAGE, TREE_TAB)}`;
        expect(pages[0]?.body).toContain(`**Anatomy**\n- [Reading](04-Anatomy.Reading)\n- [Source tree](${tree})`);
        expect(pages[4]?.body).toContain(`[the tree](${tree}#file-x)`);
        expect(pages[4]?.body.trimEnd().endsWith("[Observation](03-Method.Observation)")).toBe(true);
    });
});
```
