102 lines
3.1 KiB
TypeScript
102 lines
3.1 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test";
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { createDrawingStore, type DrawingStore } from "./db";
|
|
import { createServer } from "./http-server";
|
|
|
|
const cleanup: string[] = [];
|
|
const stores: DrawingStore[] = [];
|
|
|
|
afterEach(() => {
|
|
while (stores.length > 0) {
|
|
stores.pop()?.close();
|
|
}
|
|
|
|
while (cleanup.length > 0) {
|
|
const dir = cleanup.pop();
|
|
if (dir) {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
}
|
|
});
|
|
|
|
function createServerFixture() {
|
|
const dir = mkdtempSync(join(tmpdir(), "excali-server-"));
|
|
cleanup.push(dir);
|
|
|
|
const store = createDrawingStore(join(dir, "test.sqlite"));
|
|
stores.push(store);
|
|
|
|
return {
|
|
store,
|
|
server: createServer({ drawingStore: store }),
|
|
};
|
|
}
|
|
|
|
describe("createServer", () => {
|
|
test("redirects / to the latest drawing", () => {
|
|
const { server, store } = createServerFixture();
|
|
|
|
const response = server.routes["/"]?.(new Request("http://local/")) as Response;
|
|
const created = store.listDrawings();
|
|
|
|
expect(created).toHaveLength(1);
|
|
expect(response.status).toBe(302);
|
|
expect(response.headers.get("location")).toBe(`http://local/d/${created[0]?.id}`);
|
|
});
|
|
|
|
test("keeps Bun responsible for API routes", async () => {
|
|
const { server } = createServerFixture();
|
|
const response = await server.routes["/api/health"]?.GET?.();
|
|
|
|
expect(response?.status).toBe(200);
|
|
expect(await response?.json()).toEqual({ ok: true });
|
|
});
|
|
|
|
test("does not expose a Bun static route for drawings in production", () => {
|
|
const { server } = createServerFixture();
|
|
|
|
expect(Object.hasOwn(server.routes, "/d/:id")).toBe(false);
|
|
expect(Object.hasOwn(server.routes, "/p/:slug")).toBe(false);
|
|
});
|
|
|
|
test("serves public drawing data through the public api", async () => {
|
|
const { server, store } = createServerFixture();
|
|
const drawing = store.createDrawing("Published");
|
|
store.publishDrawing(drawing.id, { slug: "published-note" });
|
|
|
|
const response = await server.routes["/api/public/drawings/:slug"]?.GET?.(
|
|
Object.assign(new Request("http://local/api/public/drawings/published-note"), {
|
|
params: { slug: "published-note" },
|
|
}),
|
|
);
|
|
|
|
expect(response?.status).toBe(200);
|
|
expect(await response?.json()).toEqual({
|
|
title: "Published",
|
|
elements: [],
|
|
appState: { theme: "dark" },
|
|
files: {},
|
|
});
|
|
});
|
|
|
|
test("returns 404 for unknown or unpublished public slugs", async () => {
|
|
const { server } = createServerFixture();
|
|
|
|
const response = await server.routes["/api/public/drawings/:slug"]?.GET?.(
|
|
Object.assign(new Request("http://local/api/public/drawings/missing"), { params: { slug: "missing" } }),
|
|
);
|
|
|
|
expect(response?.status).toBe(404);
|
|
});
|
|
|
|
test("returns JSON 404 for unmatched requests", async () => {
|
|
const { server } = createServerFixture();
|
|
const response = await server.fetch(new Request("http://local/index-abc123.js"));
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(await response.json()).toEqual({ ok: false, error: "Not found" });
|
|
});
|
|
});
|