- Unit tests for createGameSession and evaluateAnswer (14 tests) - Endpoint tests for POST /game/start and /game/answer via supertest (8 tests) - Mock @glossa/db — no real database dependency
139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import request from "supertest";
|
|
|
|
vi.mock("@glossa/db", () => ({
|
|
getGameTerms: vi.fn(),
|
|
getDistractors: vi.fn(),
|
|
}));
|
|
|
|
import { getGameTerms, getDistractors } from "@glossa/db";
|
|
import { createApp } from "../app.js";
|
|
|
|
const app = createApp();
|
|
const mockGetGameTerms = vi.mocked(getGameTerms);
|
|
const mockGetDistractors = vi.mocked(getDistractors);
|
|
|
|
const validBody = {
|
|
source_language: "en",
|
|
target_language: "it",
|
|
pos: "noun",
|
|
difficulty: "easy",
|
|
rounds: "3",
|
|
};
|
|
|
|
const fakeTerms = [
|
|
{ termId: "t1", sourceText: "dog", targetText: "cane", sourceGloss: null },
|
|
{ termId: "t2", sourceText: "cat", targetText: "gatto", sourceGloss: null },
|
|
{ termId: "t3", sourceText: "house", targetText: "casa", sourceGloss: null },
|
|
];
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mockGetGameTerms.mockResolvedValue(fakeTerms);
|
|
mockGetDistractors.mockResolvedValue(["wrong1", "wrong2", "wrong3"]);
|
|
});
|
|
|
|
describe("POST /api/v1/game/start", () => {
|
|
it("returns 200 with a valid game session", async () => {
|
|
const res = await request(app).post("/api/v1/game/start").send(validBody);
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.success).toBe(true);
|
|
expect(res.body.data.sessionId).toBeDefined();
|
|
expect(res.body.data.questions).toHaveLength(3);
|
|
});
|
|
|
|
it("returns 400 when the body is empty", async () => {
|
|
const res = await request(app).post("/api/v1/game/start").send({});
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(res.body.success).toBe(false);
|
|
expect(res.body.error).toBeDefined();
|
|
});
|
|
|
|
it("returns 400 when required fields are missing", async () => {
|
|
const res = await request(app)
|
|
.post("/api/v1/game/start")
|
|
.send({ source_language: "en" });
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(res.body.success).toBe(false);
|
|
});
|
|
|
|
it("returns 400 when a field has an invalid value", async () => {
|
|
const res = await request(app)
|
|
.post("/api/v1/game/start")
|
|
.send({ ...validBody, difficulty: "impossible" });
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(res.body.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("POST /api/v1/game/answer", () => {
|
|
it("returns 200 with an answer result for a valid submission", async () => {
|
|
// Start a game first
|
|
const startRes = await request(app)
|
|
.post("/api/v1/game/start")
|
|
.send(validBody);
|
|
|
|
const { sessionId, questions } = startRes.body.data;
|
|
const question = questions[0];
|
|
|
|
const res = await request(app)
|
|
.post("/api/v1/game/answer")
|
|
.send({
|
|
sessionId,
|
|
questionId: question.questionId,
|
|
selectedOptionId: 0,
|
|
});
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.success).toBe(true);
|
|
expect(res.body.data.questionId).toBe(question.questionId);
|
|
expect(typeof res.body.data.isCorrect).toBe("boolean");
|
|
expect(typeof res.body.data.correctOptionId).toBe("number");
|
|
expect(res.body.data.selectedOptionId).toBe(0);
|
|
});
|
|
|
|
it("returns 400 when the body is empty", async () => {
|
|
const res = await request(app).post("/api/v1/game/answer").send({});
|
|
|
|
expect(res.status).toBe(400);
|
|
expect(res.body.success).toBe(false);
|
|
});
|
|
|
|
it("returns 404 when the session does not exist", async () => {
|
|
const res = await request(app)
|
|
.post("/api/v1/game/answer")
|
|
.send({
|
|
sessionId: "00000000-0000-0000-0000-000000000000",
|
|
questionId: "00000000-0000-0000-0000-000000000000",
|
|
selectedOptionId: 0,
|
|
});
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(res.body.success).toBe(false);
|
|
expect(res.body.error).toContain("Game session not found");
|
|
});
|
|
|
|
it("returns 404 when the question does not exist in the session", async () => {
|
|
const startRes = await request(app)
|
|
.post("/api/v1/game/start")
|
|
.send(validBody);
|
|
|
|
const { sessionId } = startRes.body.data;
|
|
|
|
const res = await request(app)
|
|
.post("/api/v1/game/answer")
|
|
.send({
|
|
sessionId,
|
|
questionId: "00000000-0000-0000-0000-000000000000",
|
|
selectedOptionId: 0,
|
|
});
|
|
|
|
expect(res.status).toBe(404);
|
|
expect(res.body.success).toBe(false);
|
|
expect(res.body.error).toContain("Question not found");
|
|
});
|
|
});
|