|
| 1 | +import { client, expect, scenario } from "probitas"; |
| 2 | +import { getPackageList } from "../data/api-pages.ts"; |
| 3 | +import { docPages } from "../data/docs.ts"; |
| 4 | + |
| 5 | +const BASE_URL = Deno.env.get("DOCS_BASE_URL") ?? "http://localhost:8000"; |
| 6 | + |
| 7 | +async function loadDocHeadings(): Promise<Record<string, string>> { |
| 8 | + const headings: Record<string, string> = {}; |
| 9 | + for (const doc of docPages) { |
| 10 | + try { |
| 11 | + const content = await Deno.readTextFile( |
| 12 | + new URL(doc.file, import.meta.url), |
| 13 | + ); |
| 14 | + const match = content.match(/^# .+/m); |
| 15 | + if (match) { |
| 16 | + headings[doc.path] = match[0]; |
| 17 | + } |
| 18 | + } catch { |
| 19 | + // Ignore missing local files; remote check will still validate status/ctype |
| 20 | + } |
| 21 | + } |
| 22 | + return headings; |
| 23 | +} |
| 24 | + |
| 25 | +const docHeadings = await loadDocHeadings(); |
| 26 | + |
| 27 | +export default scenario("Probitas docs site health", { |
| 28 | + tags: ["smoke", "docs"], |
| 29 | +}) |
| 30 | + .resource("http", () => |
| 31 | + client.http.createHttpClient({ |
| 32 | + url: BASE_URL, |
| 33 | + })) |
| 34 | + .step("serves LLM-friendly markdown at /", async ({ resources }) => { |
| 35 | + const res = await resources.http.get("/", { |
| 36 | + headers: { accept: "text/markdown" }, |
| 37 | + }); |
| 38 | + |
| 39 | + expect(res) |
| 40 | + .ok() |
| 41 | + .status(200) |
| 42 | + .contentType(/text\/markdown/) |
| 43 | + .textContains("This is a Markdown page for LLMs.") |
| 44 | + .textContains("# Probitas"); |
| 45 | + }) |
| 46 | + .step("serves human homepage HTML", async ({ resources }) => { |
| 47 | + const res = await resources.http.get("/", { |
| 48 | + query: { human: "1" }, |
| 49 | + headers: { accept: "text/html" }, |
| 50 | + }); |
| 51 | + |
| 52 | + expect(res) |
| 53 | + .ok() |
| 54 | + .status(200) |
| 55 | + .contentType(/text\/html/) |
| 56 | + .textContains("Probitas - Scenario-based Testing Framework") |
| 57 | + .textContains( |
| 58 | + "Scenario-based testing framework designed for API, database, and message queue testing", |
| 59 | + ) |
| 60 | + .textContains("AI-Friendly Documentation"); |
| 61 | + }) |
| 62 | + .step("exposes raw markdown for docs pages", async ({ resources }) => { |
| 63 | + for (const doc of docPages) { |
| 64 | + const res = await resources.http.get(`${doc.path}.md`); |
| 65 | + const heading = docHeadings[doc.path] ?? "# "; |
| 66 | + expect(res) |
| 67 | + .ok() |
| 68 | + .status(200) |
| 69 | + .contentType(/text\/markdown/) |
| 70 | + .textContains(heading); |
| 71 | + } |
| 72 | + }) |
| 73 | + .step("renders docs HTML pages", async ({ resources }) => { |
| 74 | + for (const doc of docPages) { |
| 75 | + const res = await resources.http.get(doc.path, { |
| 76 | + headers: { accept: "text/html" }, |
| 77 | + }); |
| 78 | + expect(res) |
| 79 | + .ok() |
| 80 | + .status(200) |
| 81 | + .contentType(/text\/html/) |
| 82 | + .textContains(doc.label); |
| 83 | + } |
| 84 | + }) |
| 85 | + .step("provides LLM endpoints", async ({ resources }) => { |
| 86 | + const indexRes = await resources.http.get("/llms.txt"); |
| 87 | + expect(indexRes) |
| 88 | + .ok() |
| 89 | + .status(200) |
| 90 | + .contentType(/text\/markdown/) |
| 91 | + .textContains("## Documentation") |
| 92 | + .textContains("## API Reference"); |
| 93 | + |
| 94 | + const fullRes = await resources.http.get("/llms-full.txt"); |
| 95 | + expect(fullRes) |
| 96 | + .ok() |
| 97 | + .status(200) |
| 98 | + .contentType(/text\/markdown/) |
| 99 | + .textContains("# Probitas - Complete Documentation") |
| 100 | + .textContains("## Additional Resources"); |
| 101 | + }) |
| 102 | + .step("renders API index and package JSON", async ({ resources }) => { |
| 103 | + const indexRes = await resources.http.get("/api", { |
| 104 | + headers: { accept: "text/html" }, |
| 105 | + }); |
| 106 | + expect(indexRes).ok().status(200).textContains("API Reference"); |
| 107 | + |
| 108 | + const packages = await getPackageList(); |
| 109 | + for (const pkg of packages) { |
| 110 | + const res = await resources.http.get(`/api/${pkg.name}.json`); |
| 111 | + expect(res) |
| 112 | + .ok() |
| 113 | + .status(200) |
| 114 | + .contentType(/application\/json/) |
| 115 | + .dataContains({ name: pkg.name, specifier: pkg.specifier }); |
| 116 | + } |
| 117 | + }) |
| 118 | + .step("renders API markdown endpoints", async ({ resources }) => { |
| 119 | + const packages = await getPackageList(); |
| 120 | + for (const pkg of packages) { |
| 121 | + const res = await resources.http.get(`/api/${pkg.name}.md`); |
| 122 | + expect(res) |
| 123 | + .ok() |
| 124 | + .status(200) |
| 125 | + .contentType(/text\/markdown/) |
| 126 | + .textContains(pkg.specifier); |
| 127 | + } |
| 128 | + }) |
| 129 | + .step("serves static assets", async ({ resources }) => { |
| 130 | + const res = await resources.http.get("/static/style.css"); |
| 131 | + expect(res).ok().status(200).contentType(/text\/css/); |
| 132 | + }) |
| 133 | + .build(); |
0 commit comments