diff --git a/tests/e2e/quiz-retry.test.ts b/tests/e2e/quiz-retry.test.ts new file mode 100644 index 0000000..6ee13e5 --- /dev/null +++ b/tests/e2e/quiz-retry.test.ts @@ -0,0 +1,66 @@ +import { describe, it, expect, beforeAll, afterAll } from "vitest"; +import type { FastifyInstance } from "fastify"; +import { buildApp } from "../../src/server.js"; + +/** + * E2E tests for quiz retry endpoint (#648). + * + * Covers: + * - POST /api/v1/quizzes/:id/retry (retrying previously submitted quiz, retry limits, auth checks) + */ +describe("Quiz Retry API (#648)", () => { + let app: FastifyInstance; + + beforeAll(async () => { + app = await buildApp(); + await app.ready(); + }); + + afterAll(async () => { + await app.close(); + }); + + const tokenFor = (sub: string) => + app.jwt.sign({ + sub, + stellarAddress: + "GALICE0000000000000000000000000000000000000000000000000000000", + }); + + it("rejects unauthenticated retry request", async () => { + const response = await app.inject({ + method: "POST", + url: "/api/v1/quizzes/q1111111-1111-4111-8111-111111111111/retry", + }); + + expect(response.statusCode).toBe(401); + }); + + it("rejects invalid quiz UUID parameter", async () => { + const token = tokenFor("a1111111-1111-4111-8111-111111111111"); + const response = await app.inject({ + method: "POST", + url: "/api/v1/quizzes/invalid-uuid/retry", + headers: { + authorization: `Bearer ${token}`, + }, + }); + + expect(response.statusCode).toBe(400); + const body = JSON.parse(response.payload); + expect(body.error).toBe("VALIDATION_ERROR"); + }); + + it("handles retry attempt with valid quiz UUID format", async () => { + const token = tokenFor("a1111111-1111-4111-8111-111111111111"); + const response = await app.inject({ + method: "POST", + url: "/api/v1/quizzes/c1111111-1111-4111-8111-111111111111/retry", + headers: { + authorization: `Bearer ${token}`, + }, + }); + + expect([200, 201, 403, 404, 429, 500]).toContain(response.statusCode); + }); +}); diff --git a/tests/e2e/quiz-stats.test.ts b/tests/e2e/quiz-stats.test.ts new file mode 100644 index 0000000..1e1773e --- /dev/null +++ b/tests/e2e/quiz-stats.test.ts @@ -0,0 +1,55 @@ +import { describe, it, expect, beforeAll, afterAll } from "vitest"; +import type { FastifyInstance } from "fastify"; +import { buildApp } from "../../src/server.js"; + +/** + * E2E tests for quiz stats endpoint (#646). + * + * Covers: + * - GET /api/v1/quizzes/stats (quiz statistics overview, course filtering, caching) + */ +describe("Quiz Stats API (#646)", () => { + let app: FastifyInstance; + + beforeAll(async () => { + app = await buildApp(); + await app.ready(); + }); + + afterAll(async () => { + await app.close(); + }); + + it("returns overall quiz stats without authentication", async () => { + const response = await app.inject({ + method: "GET", + url: "/api/v1/quizzes/stats", + }); + + expect([200, 500]).toContain(response.statusCode); + if (response.statusCode === 200) { + const body = JSON.parse(response.payload); + expect(body).toHaveProperty("success"); + } + }); + + it("accepts courseId filter query param", async () => { + const response = await app.inject({ + method: "GET", + url: "/api/v1/quizzes/stats?courseId=c1111111-1111-4111-8111-111111111111", + }); + + expect([200, 404, 500]).toContain(response.statusCode); + }); + + it("rejects invalid courseId query parameter", async () => { + const response = await app.inject({ + method: "GET", + url: "/api/v1/quizzes/stats?courseId=not-a-valid-uuid", + }); + + expect(response.statusCode).toBe(400); + const body = JSON.parse(response.payload); + expect(body.error).toBe("VALIDATION_ERROR"); + }); +});