144 lines
4.1 KiB
TypeScript
144 lines
4.1 KiB
TypeScript
import { describe, test, expect, beforeAll, afterAll, mock } from "bun:test";
|
|
import { db } from "@/db";
|
|
import { annotators } from "@/db/schema";
|
|
import { eq } from "drizzle-orm";
|
|
|
|
// Mock cookie store that captures set/delete calls
|
|
const cookieJar = new Map<string, string>();
|
|
const mockCookieStore = {
|
|
get(name: string) {
|
|
const value = cookieJar.get(name);
|
|
return value ? { value } : undefined;
|
|
},
|
|
set(name: string, value: string, _opts?: unknown) {
|
|
cookieJar.set(name, value);
|
|
},
|
|
delete(name: string) {
|
|
cookieJar.delete(name);
|
|
},
|
|
};
|
|
|
|
// Mock next/headers before importing route handlers
|
|
mock.module("next/headers", () => ({
|
|
cookies: async () => mockCookieStore,
|
|
}));
|
|
|
|
// Import route handlers after mock is set up
|
|
const { GET, POST, DELETE: DELETE_HANDLER } = await import("../route");
|
|
|
|
const TEST_ANNOTATOR = {
|
|
id: "test-auth-user",
|
|
displayName: "Test Auth User",
|
|
password: "testpass",
|
|
};
|
|
|
|
beforeAll(async () => {
|
|
await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
|
|
await db.insert(annotators).values(TEST_ANNOTATOR);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
|
|
});
|
|
|
|
describe("GET /api/auth", () => {
|
|
test("returns annotator list without passwords", async () => {
|
|
const res = await GET();
|
|
const data = await res.json();
|
|
|
|
expect(Array.isArray(data)).toBe(true);
|
|
|
|
const testAnnotator = data.find(
|
|
(a: { id: string }) => a.id === TEST_ANNOTATOR.id,
|
|
);
|
|
expect(testAnnotator).toBeDefined();
|
|
expect(testAnnotator.id).toBe(TEST_ANNOTATOR.id);
|
|
expect(testAnnotator.displayName).toBe(TEST_ANNOTATOR.displayName);
|
|
expect(testAnnotator.password).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("POST /api/auth", () => {
|
|
test("returns 200 and sets session cookie with correct credentials", async () => {
|
|
cookieJar.clear();
|
|
|
|
const req = new Request("http://localhost:3000/api/auth", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
annotatorId: TEST_ANNOTATOR.id,
|
|
password: TEST_ANNOTATOR.password,
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(data.ok).toBe(true);
|
|
expect(data.annotator.id).toBe(TEST_ANNOTATOR.id);
|
|
expect(data.annotator.displayName).toBe(TEST_ANNOTATOR.displayName);
|
|
|
|
// Verify session cookie was set in the mock store
|
|
expect(cookieJar.has("session")).toBe(true);
|
|
const sessionValue = cookieJar.get("session")!;
|
|
expect(sessionValue).toContain(".");
|
|
});
|
|
|
|
test("returns 401 with wrong password", async () => {
|
|
const req = new Request("http://localhost:3000/api/auth", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
annotatorId: TEST_ANNOTATOR.id,
|
|
password: "wrongpassword",
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(401);
|
|
expect(data.error).toBe("Invalid credentials");
|
|
});
|
|
|
|
test("returns 401 with nonexistent annotator", async () => {
|
|
const req = new Request("http://localhost:3000/api/auth", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
annotatorId: "nonexistent-user",
|
|
password: "anything",
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
test("returns 401 with missing fields", async () => {
|
|
const req = new Request("http://localhost:3000/api/auth", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
expect(res.status).toBe(401);
|
|
});
|
|
});
|
|
|
|
describe("DELETE /api/auth", () => {
|
|
test("clears session cookie", async () => {
|
|
// Pre-populate a session cookie
|
|
cookieJar.set("session", "fake-session-value");
|
|
|
|
const res = await DELETE_HANDLER();
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(data.ok).toBe(true);
|
|
expect(cookieJar.has("session")).toBe(false);
|
|
});
|
|
});
|