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});