links.test.ts

4.5 kB · typescript · 120 lines

1import { expect, test } from "bun:test";2import { index, resolve, stamp } from "./links.ts";3import type { Input, Route, Site } from "./build.ts";45/* SITE */67const home = "/repo";8const net = `${home}/site`;910const input = (name: string, path: string): Input => ({ name, path, files: [], missing: false });1112const routes: Route[] = [13  { route: "/research/", kind: "research", source: `${home}/research/README.md` },14  { route: "/research/bases/", kind: "note", source: `${home}/research/bases.md` },15  { route: "/blog/hello/", kind: "post", source: `${net}/blog/hello.md` },16  { route: "/about/", kind: "page", source: `${net}/pages/about.md` },17  { route: "/contact/", kind: "page", source: `${net}/pages/contact.md` },18  {19    route: "/demos/",20    kind: "demos",21    source: `${net}/demos`,22    urls: [{ route: "/demos/spin/", source: `${net}/demos/spin` }],23  },24];2526const code: Route[] = [27  { route: "/git/", kind: "gitdir" },28  { route: "/git/crates/mrly/", kind: "gitdir" },29  { route: "/git/crates/mrly/README.md", kind: "gitfile" },30  { route: "/git/research/lab/walk.rs", kind: "gitfile" },31  { route: "/git/files/figures/carpet.png", kind: "gitfile" },32];3334function site(git: boolean): Site {35  const one = {36    root: net,37    config: { git: git ? { root: "..", slug: "mrlyprod/mrlyprod", branch: "main" } : { root: ".", slug: "acme/site" } },38    inputs: {39      research: input("research", `${home}/research`),40      blog: input("blog", `${net}/blog`),41      pages: input("pages", `${net}/pages`),42      demos: input("demos", `${net}/demos`),43    },44    routes: git ? [...routes, ...code] : routes,45  } as unknown as Site;46  one.index = index(one);47  return one;48}4950const mrly = site(true);5152/* ROUTES */5354test("a note link to a sibling note lands on that note's route", () => {55  expect(resolve(mrly, "research/core.md", "bases.md")).toBe("/research/bases/");56  expect(resolve(mrly, "research/core.md", "README.md")).toBe("/research/");57});5859test("a note link to a demo lands on the demo route", () => {60  expect(resolve(mrly, "research/core.md", "../demos/spin/")).toBe("/demos/spin/");61});6263test("a page link to a page lands on that page's route", () => {64  expect(resolve(mrly, "site/pages/about.md", "contact.md")).toBe("/contact/");65});6667test("a post link to a note lands on the research route", () => {68  expect(resolve(mrly, "site/blog/hello.md", "../../research/bases.md")).toBe("/research/bases/");69});7071test("a fragment and a query ride along", () => {72  expect(resolve(mrly, "research/core.md", "bases.md#lemma")).toBe("/research/bases/#lemma");73  expect(resolve(mrly, "research/core.md", "../demos/spin/?code=7")).toBe("/demos/spin/?code=7");74});7576/* STAMP */7778test("the stamp moves when a route a page could link to disappears", () => {79  const gone = { ...mrly, routes: mrly.routes.filter((one) => one.route !== "/research/bases/") } as Site;80  expect(stamp(index(gone))).not.toBe(stamp(mrly.index!));81});8283test("a source outside the repo never lands in the stamp", () => {84  const away = "/shelf/carpet/README.md";85  const wide = { ...mrly, routes: [...mrly.routes, { route: "/shelf/carpet/", kind: "note", source: away }] } as Site;86  expect(stamp(index(wide))).not.toContain(away);87});8889/* FALLBACK */9091test("a repo file with no route lands on its /git/ page", () => {92  expect(resolve(mrly, "research/core.md", "lab/walk.rs")).toBe("/git/research/lab/walk.rs");93  expect(resolve(mrly, "research/core.md", "../crates/mrly/README.md")).toBe("/git/crates/mrly/README.md");94});9596test("an image with no route lands on its raw bytes", () => {97  expect(resolve(mrly, "research/core.md", "../files/figures/carpet.png")).toBe("/raw/files/figures/carpet.png");98});99100test("an extensionless directory lands on its listing", () => {101  expect(resolve(mrly, "research/core.md", "../crates/mrly")).toBe("/git/crates/mrly/");102});103104test("a path the repo does not carry stays as written", () => {105  expect(resolve(mrly, "research/core.md", "lab/gone.rs")).toBe("lab/gone.rs");106});107108test("a site with no git routes falls to the github blob", () => {109  expect(resolve(site(false), "pages/about.md", "../lib/tree.js")).toBe("https://github.com/acme/site/blob/main/lib/tree.js");110});111112test("an outside link and a rooted link pass through", () => {113  for (const url of ["https://mrly.net", "http://mrly.net", "mailto:help@mrly.net", "tel:+1", "#top", "/demos/"]) {114    expect(resolve(mrly, "research/core.md", url)).toBe(url);115  }116});117118test("a target outside the repo stays as written", () => {119  expect(resolve(mrly, "../shelf/carpet/README.md", "paper.pdf")).toBe("paper.pdf");120});