Files
testapi/tests/api.test.ts
2026-03-03 14:25:43 +00:00

125 lines
3.8 KiB
TypeScript

import { afterEach, describe, expect, it } from "bun:test";
import { mkdtempSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { reseedDatabase } from "../src/database";
import { createServer } from "../src/index";
let tempDir: string | null = null;
function createTestServer() {
tempDir = mkdtempSync(join(tmpdir(), "mock-task-api-http-"));
const db = reseedDatabase(join(tempDir, "test.sqlite"));
return createServer(db);
}
async function readJson(response: Response) {
return (await response.json()) as Record<string, unknown>;
}
afterEach(() => {
if (tempDir) {
rmSync(tempDir, { recursive: true, force: true });
tempDir = null;
}
});
describe("mock task API", () => {
it("serves a health endpoint", async () => {
const server = createTestServer();
const response = await server.fetch(new Request("http://mock.local/health"));
const body = await readJson(response);
expect(response.status).toBe(200);
expect(body.status).toBe("ok");
});
it("lists organizations", async () => {
const server = createTestServer();
const response = await server.fetch(new Request("http://mock.local/orgs"));
const body = await readJson(response);
expect(response.status).toBe(200);
expect(Array.isArray(body.organizations)).toBe(true);
expect((body.organizations as unknown[]).length).toBe(3);
});
it("filters tasks by org and status", async () => {
const server = createTestServer();
const response = await server.fetch(
new Request("http://mock.local/tasks?orgId=org_acme&status=blocked"),
);
const body = await readJson(response);
const tasks = body.tasks as Array<Record<string, unknown>>;
expect(response.status).toBe(200);
expect(tasks.length).toBe(1);
expect(tasks[0]?.id).toBe("task_1003");
});
it("creates a task through the HTTP contract", async () => {
const server = createTestServer();
const response = await server.fetch(
new Request("http://mock.local/tasks", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
orgId: "org_acme",
projectId: "proj_acme_ops",
title: "Run API smoke test",
priority: "low",
}),
}),
);
const body = await readJson(response);
expect(response.status).toBe(201);
expect((body.task as Record<string, unknown>).title).toBe("Run API smoke test");
});
it("updates a task through the HTTP contract", async () => {
const server = createTestServer();
const response = await server.fetch(
new Request("http://mock.local/tasks/task_1001", {
method: "PATCH",
headers: { "content-type": "application/json" },
body: JSON.stringify({
status: "done",
assigneeUserId: null,
}),
}),
);
const body = await readJson(response);
expect(response.status).toBe(200);
expect((body.task as Record<string, unknown>).status).toBe("done");
expect((body.task as Record<string, unknown>).assigneeUserId).toBeNull();
});
it("returns a valid openapi document at the import path", async () => {
const server = createTestServer();
const response = await server.fetch(new Request("http://mock.local/openapi.json"));
const body = await readJson(response);
const paths = body.paths as Record<string, unknown>;
expect(response.status).toBe(200);
expect(body.openapi).toBe("3.1.0");
expect(paths["/tasks"]).toBeDefined();
expect(paths["/orgs/{orgId}/tasks"]).toBeDefined();
});
it("supports the swagger alias path used by import tools", async () => {
const server = createTestServer();
const response = await server.fetch(new Request("http://mock.local/swagger.json"));
expect(response.status).toBe(200);
});
});