179 lines
5.0 KiB
TypeScript
179 lines
5.0 KiB
TypeScript
import { describe, test, expect, beforeAll, afterAll, mock } from "bun:test";
|
|
import { db } from "@/db";
|
|
import { annotators, quizSessions } from "@/db/schema";
|
|
import { eq } from "drizzle-orm";
|
|
|
|
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.module("next/headers", () => ({
|
|
cookies: async () => mockCookieStore,
|
|
}));
|
|
|
|
const { createSession } = await import("@/lib/auth");
|
|
const { GET, POST } = await import("../route");
|
|
|
|
const TEST_ANNOTATOR = {
|
|
id: "test-warmup-user",
|
|
displayName: "Test Warmup User",
|
|
password: "testpass",
|
|
};
|
|
|
|
const QUIZ_SESSION_ID = "test-warmup-quiz-session";
|
|
|
|
beforeAll(async () => {
|
|
// Clean up any leftover data
|
|
await db
|
|
.delete(quizSessions)
|
|
.where(eq(quizSessions.annotatorId, TEST_ANNOTATOR.id));
|
|
await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
|
|
|
|
// Create test annotator
|
|
await db.insert(annotators).values(TEST_ANNOTATOR);
|
|
|
|
// Create a passed quiz session
|
|
await db.insert(quizSessions).values({
|
|
id: QUIZ_SESSION_ID,
|
|
annotatorId: TEST_ANNOTATOR.id,
|
|
totalQuestions: 8,
|
|
score: 8,
|
|
passed: true,
|
|
completedAt: new Date(),
|
|
answers: "[]",
|
|
});
|
|
|
|
// Set up session cookie
|
|
cookieJar.clear();
|
|
await createSession(TEST_ANNOTATOR.id);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await db
|
|
.delete(quizSessions)
|
|
.where(eq(quizSessions.annotatorId, TEST_ANNOTATOR.id));
|
|
await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
|
|
});
|
|
|
|
describe("GET /api/warmup", () => {
|
|
test("returns first warmup paragraph", async () => {
|
|
const res = await GET();
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(data.done).toBe(false);
|
|
expect(data.warmupCompleted).toBe(0);
|
|
expect(data.paragraph).toBeDefined();
|
|
expect(data.paragraph.id).toBe("warmup-1");
|
|
expect(data.paragraph.text).toBeTruthy();
|
|
expect(data.paragraph.index).toBe(0);
|
|
expect(data.paragraph.total).toBe(5);
|
|
});
|
|
});
|
|
|
|
describe("POST /api/warmup", () => {
|
|
test("returns gold answer and explanation for correct answer", async () => {
|
|
const req = new Request("http://localhost:3000/api/warmup", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
category: "Board Governance",
|
|
specificity: 3,
|
|
warmupIndex: 0,
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(data.categoryCorrect).toBe(true);
|
|
expect(data.specificityCorrect).toBe(true);
|
|
expect(data.goldCategory).toBe("Board Governance");
|
|
expect(data.goldSpecificity).toBe(3);
|
|
expect(data.explanation).toBeTruthy();
|
|
expect(data.warmupCompleted).toBe(1);
|
|
expect(data.done).toBe(false);
|
|
});
|
|
|
|
test("returns feedback for incorrect answer", async () => {
|
|
const req = new Request("http://localhost:3000/api/warmup", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
category: "Management Role",
|
|
specificity: 1,
|
|
warmupIndex: 1,
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
const data = await res.json();
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(data.categoryCorrect).toBe(false);
|
|
expect(data.specificityCorrect).toBe(false);
|
|
expect(data.goldCategory).toBe("Incident Disclosure");
|
|
expect(data.goldSpecificity).toBe(4);
|
|
expect(data.warmupCompleted).toBe(2);
|
|
});
|
|
|
|
test("rejects mismatched warmup index", async () => {
|
|
const req = new Request("http://localhost:3000/api/warmup", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
category: "Risk Management Process",
|
|
specificity: 1,
|
|
warmupIndex: 0, // should be 2 at this point
|
|
}),
|
|
});
|
|
|
|
const res = await POST(req);
|
|
expect(res.status).toBe(400);
|
|
const data = await res.json();
|
|
expect(data.error).toBe("Warmup index mismatch");
|
|
});
|
|
|
|
test("completes remaining warmups and returns done", async () => {
|
|
// Complete warmups 2, 3, 4
|
|
for (let i = 2; i < 5; i++) {
|
|
const req = new Request("http://localhost:3000/api/warmup", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
category: "None/Other",
|
|
specificity: 1,
|
|
warmupIndex: i,
|
|
}),
|
|
});
|
|
const res = await POST(req);
|
|
expect(res.status).toBe(200);
|
|
}
|
|
|
|
// GET should now return done
|
|
const res = await GET();
|
|
const data = await res.json();
|
|
expect(data.done).toBe(true);
|
|
expect(data.warmupCompleted).toBe(5);
|
|
});
|
|
});
|
|
|
|
describe("GET /api/warmup - unauthorized", () => {
|
|
test("returns 401 without session", async () => {
|
|
cookieJar.clear();
|
|
const res = await GET();
|
|
expect(res.status).toBe(401);
|
|
});
|
|
});
|