diff options
| author | Joe Mou <dev@mou.fo> | 2026-09-03 00:08:06 -0400 |
|---|---|---|
| committer | Joe Mou <dev@mou.fo> | 2026-09-03 01:09:10 -0400 |
| commit | 4c66a07a995c0d551cd284d6e72826b4f7748bab (patch) | |
| tree | 35c53f0713a0903ed4c44d53ed17a4f47deaf4af /cgithub/src/scraper.test.ts | |
| parent | 1b9d13fce99b9d798dd604f402699bb47cb1627e (diff) | |
Render repository wikis
Wikis are one of the last parts of GitHub still served as plain Rails
HTML, with no embedded JSON to read, so this scrapes the markup: a page
and any older revision of it, the _Sidebar and _Footer a wiki can
define, and the page index. Every page is already in the sidebar of
every page, since the "Show N more pages" button only unhides the rest,
so linking the whole wiki costs no second request.
Routes mirror GitHub's and resolve in its order, so an underscore name
reserved for its own actions (_pages, _history, _new, _edit) can never
be mistaken for a page; the ones we don't serve fall through to the
usual redirect. A slug reaches us decoded and has to be encoded again
rather than interpolated the way a ref is, or a page named C# would
truncate at the fragment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013rQG1io1i4GJQW5RFcXNGd
Diffstat (limited to 'cgithub/src/scraper.test.ts')
| -rw-r--r-- | cgithub/src/scraper.test.ts | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/cgithub/src/scraper.test.ts b/cgithub/src/scraper.test.ts index 88e9271..372772b 100644 --- a/cgithub/src/scraper.test.ts +++ b/cgithub/src/scraper.test.ts @@ -14,6 +14,8 @@ import { getGitHubRepo, getGitHubOwner, getGitHubTree, + getGitHubWiki, + getGitHubWikiPages, GitHubHTTPError, RedirectError, } from "./scraper.ts"; @@ -384,6 +386,84 @@ describe("GitHub scraper", () => { }); }); + describe("wikis", () => { + it("should fetch the home page a wiki serves off /wiki itself", async () => { + const data = await getGitHubWiki("microsoft", "vscode"); + + assert.strictEqual(data.repo.owner, "microsoft"); + assert.strictEqual(data.repo.name, "vscode"); + assert.strictEqual(data.title, "Home"); + assert.strictEqual(data.updatedBy, "Greg Van Liew"); + assert.strictEqual(data.updatedAt, "2019-11-22T03:08:32Z"); + + assert.match(data.bodyHtml, /Welcome to the Visual Studio Code Wiki/); + // The _Sidebar and _Footer pages this wiki defines. + assert.match(data.sidebarHtml ?? "", /href="\/microsoft\/vscode\/wiki\/Roadmap"/); + assert.match(data.footerHtml ?? "", /Want to contribute to this Wiki\?/); + }); + + it("should fetch a page by its slug", async () => { + const data = await getGitHubWiki("microsoft", "vscode", "Commit-Signing"); + + assert.strictEqual(data.title, "Commit Signing"); + assert.match(data.bodyHtml, /GPG/); + }); + + // The slug arrives from our route already decoded, so it has to be encoded + // again rather than interpolated into the URL as-is. + it("should fetch a page whose slug is not path-safe", async () => { + const data = await getGitHubWiki( + "microsoft", + "vscode", + "[DEV]-Perf-Tools-for-VS-Code-Development", + ); + + assert.strictEqual(data.title, "[DEV] Perf Tools for VS Code Development"); + assert.ok(data.bodyHtml.length > 0); + }); + + it("should fetch an older revision of a page", async () => { + const oid = "f1c60035ba38b68ba383f58e482c312218daf86c"; + const data = await getGitHubWiki("microsoft", "vscode", "Commit-Signing", oid); + + assert.strictEqual(data.title, "Commit Signing"); + assert.strictEqual(data.updatedBy, "Joaqu\u00edn Ruales"); + assert.strictEqual(data.updatedAt, "2025-10-17T15:07:14Z"); + }); + + // The sidebar list is complete; its "Show N more pages…" button only + // unhides the rest, so no second request is needed to link every page. + it("should collect every page from the sidebar of any page", async () => { + const data = await getGitHubWiki("microsoft", "vscode"); + + assert.ok(data.pages.length > 15); + assert.deepStrictEqual(data.pages[0], { name: "Home", href: "/microsoft/vscode/wiki" }); + assert.ok(data.pages.some((page) => page.href === "/microsoft/vscode/wiki/Commit-Signing")); + }); + + // An archived repository, so neither its wiki nor these dates can move. + it("should fetch the page index with its last-updated dates", async () => { + const data = await getGitHubWikiPages("ariya", "phantomjs"); + + assert.strictEqual(data.repo.owner, "ariya"); + assert.ok(data.pages.length > 1); + assert.ok(data.pages.every((page) => page.updatedAt)); + + const home = data.pages.find((page) => page.name === "Home"); + assert.ok(home); + assert.strictEqual(home.href, "/ariya/phantomjs/wiki"); + assert.strictEqual(home.updatedAt, "2018-02-08T18:57:56Z"); + }); + + it("should redirect to the repository when it has no wiki", async () => { + await assert.rejects(getGitHubWiki("git", "git"), (err) => { + assert(err instanceof RedirectError, "error should be a RedirectError"); + assert.strictEqual(err.location, "/git/git"); + return true; + }); + }); + }); + describe("owner pages", () => { it("should fetch user profile", async () => { const data = await getGitHubOwner("torvalds"); |
