TheBird

serve.test.ts

3.3 kB · typescript · 86 lines

1import { expect, test } from "bun:test";2import type { Output, Route, Site, Spec } from "./ssg/build.ts";3import { find, serve } from "./serve.ts";45/* SITE */67const routes: Route[] = [8  { route: "/", name: "Home" },9  { route: "/about/", kind: "page", name: "About" },10  { route: "/papers/one/", kind: "paper", name: "One" },11  { route: "/blog/hello/@files", kind: "files", hidden: true, urls: [{ route: "/blog/hello/hero.png" }] },12  { route: "/404.html", kind: "missing", hidden: true },13];1415const drawn: Record<string, Output[]> = {16  "/": [{ path: "index.html", bytes: "<h1>home</h1>" }],17  "/about/": [18    { path: "about/index.html", bytes: "<h1>about</h1>" },19    { path: "about/data.json", bytes: '{"ok":true}', type: "application/json" },20  ],21  "/papers/one/": [22    { path: "papers/one/index.html", bytes: "<h1>one</h1>" },23    { path: "papers/one/paper.tex", bytes: "\\documentclass{article}" },24  ],25  "/blog/hello/@files": [{ path: "blog/hello/hero.png", bytes: new Uint8Array([137, 80, 78, 71]), type: "image/png" }],26  "/404.html": [{ path: "404.html", bytes: "<h1>lost</h1>" }],27};2829const spec = { render: (_: Site, route: Route) => drawn[route.route] ?? [] } as unknown as Spec;3031const site = {32  config: { root: "https://demo.test" },33  routes,34  copies: [{ path: "ui/base-abcd1234.css", bytes: "body{margin:0}" }],35} as unknown as Site;3637/* TESTS */3839test("a path answers the route's output with the type it carries", async () => {40  const hit = await serve(spec, site, "/about/data.json");41  expect(hit.status).toBe(200);42  expect(hit.headers.get("content-type")).toBe("application/json");43  expect(await hit.text()).toBe('{"ok":true}');44});4546test("a slash route answers its index.html as html", async () => {47  const hit = await serve(spec, site, "/");48  expect(hit.headers.get("content-type")).toBe("text/html; charset=utf-8");49  expect(await hit.text()).toBe("<h1>home</h1>");50});5152test("a route that lists what it publishes answers a listed path", async () => {53  const hit = await serve(spec, site, "/blog/hello/hero.png");54  expect(hit.status).toBe(200);55  expect(hit.headers.get("content-type")).toBe("image/png");56});5758test("a slash route holds the files it writes beside its page", async () => {59  const hit = await serve(spec, site, "/papers/one/paper.tex");60  expect(hit.headers.get("content-type")).toBe("text/plain; charset=utf-8");61  expect(await hit.text()).toContain("documentclass");62});6364test("a placed copy answers from the globals", async () => {65  const hit = await serve(spec, site, "/ui/base-abcd1234.css");66  expect(hit.headers.get("content-type")).toBe("text/css; charset=utf-8");67});6869test("a route without its slash redirects to it", async () => {70  const hit = await serve(spec, site, "/about");71  expect(hit.status).toBe(302);72  expect(hit.headers.get("location")).toBe("/about/");73});7475test("an unknown path is the 404 page", async () => {76  const hit = await serve(spec, site, "/nowhere/");77  expect(hit.status).toBe(404);78  expect(await hit.text()).toBe("<h1>lost</h1>");79});8081test("a traversal path is a miss and a 404", async () => {82  expect(await find(spec, site, "/ui/../../site.json")).toBeNull();83  expect(await find(spec, site, "/../site.json")).toBeNull();84  expect(await find(spec, site, "/about/./index.html")).toBeNull();85  expect((await serve(spec, site, "/../site.json")).status).toBe(404);86});