Description
The API currently has E2E tests for only 2 of 6 modules:
tests/e2e/auth.test.ts — 4 tests
tests/e2e/rewards.test.ts — 4 tests
The remaining 4 modules have zero test coverage:
users — profile CRUD, progress aggregation
courses — listing, filtering, enrollment, detail
quizzes — generation, submission, scoring
credentials — listing, minting
Test pattern to follow
Use the existing structure from tests/e2e/auth.test.ts:
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import type { FastifyInstance } from "fastify";
import { buildApp } from "../../src/server.js";
describe("ModuleName API", () => {
let app: FastifyInstance;
beforeAll(async () => {
app = await buildApp();
await app.ready();
});
afterAll(async () => {
await app.close();
});
// Use app.inject() for HTTP requests
// Use app.jwt.sign() to create test tokens
});
Files to create
tests/e2e/users.test.ts
Tests for GET /api/users/me, PUT /api/users/me, GET /api/users/me/progress:
describe("Users API")
describe("GET /api/users/me")
- should reject unauthenticated requests (401)
- should return user profile when authenticated (200)
- should return correct stellarAddress in profile
describe("PUT /api/users/me")
- should reject unauthenticated requests (401)
- should update displayName
- should update background and learningGoal
- should reject invalid background values (400)
describe("GET /api/users/me/progress")
- should reject unauthenticated requests (401)
- should return progress aggregate for enrolled user
Auth pattern for authenticated requests:
const token = app.jwt.sign({
sub: "00000000-0000-0000-0000-000000000001",
stellarAddress: "GALICE0000000000000000000000000000000000000000000000000000000",
});
const response = await app.inject({
method: "GET",
url: "/api/users/me",
headers: { authorization: `Bearer ${token}` },
});
tests/e2e/courses.test.ts
Tests for GET /api/courses, GET /api/courses/:id, POST /api/courses/:id/enroll:
describe("Courses API")
describe("GET /api/courses")
- should return paginated course list (200)
- should filter by difficulty query param
- should return enrolledCount for each course
- should include isEnrolled when authenticated
describe("GET /api/courses/:id")
- should return course detail with modules (200)
- should return 404 for non-existent course
- should include enrollment status when authenticated
describe("POST /api/courses/:id/enroll")
- should reject unauthenticated requests (401)
- should enroll user in course (201)
- should reject duplicate enrollment (409)
- should return 404 for non-existent course
tests/e2e/quizzes.test.ts
Tests for POST /api/quizzes/generate, POST /api/quizzes/:id/submit:
describe("Quizzes API")
describe("POST /api/quizzes/generate")
- should reject unauthenticated requests (401)
- should reject if not enrolled in course (403)
- should return generated quiz questions (200)
- should return same quiz on repeat generation (idempotent)
describe("POST /api/quizzes/:id/submit")
- should reject unauthenticated requests (401)
- should submit answers and return score (200)
- should include feedback in response
- should set rewardAvailable when score >= 70%
- should reject duplicate submission (409)
tests/e2e/credentials.test.ts
Tests for GET /api/credentials, POST /api/credentials/mint:
describe("Credentials API")
describe("GET /api/credentials")
- should reject unauthenticated requests (401)
- should return user's credentials list (200)
describe("POST /api/credentials/mint")
- should reject unauthenticated requests (401)
- should mint credential for completed course (201)
- should reject if course not completed
- should reject duplicate credential (409)
Important notes
- Some tests may fail without a running PostgreSQL + Redis. Use
beforeAll/afterAll for cleanup, or consider mocking the database layer.
- The
app.inject() method does NOT require a running server — it uses Fastify's test injection.
- Use realistic UUIDs for user IDs and Stellar addresses that match the DB schema constraints.
Description
The API currently has E2E tests for only 2 of 6 modules:
tests/e2e/auth.test.ts— 4 teststests/e2e/rewards.test.ts— 4 testsThe remaining 4 modules have zero test coverage:
users— profile CRUD, progress aggregationcourses— listing, filtering, enrollment, detailquizzes— generation, submission, scoringcredentials— listing, mintingTest pattern to follow
Use the existing structure from
tests/e2e/auth.test.ts:Files to create
tests/e2e/users.test.tsTests for
GET /api/users/me,PUT /api/users/me,GET /api/users/me/progress:Auth pattern for authenticated requests:
tests/e2e/courses.test.tsTests for
GET /api/courses,GET /api/courses/:id,POST /api/courses/:id/enroll:tests/e2e/quizzes.test.tsTests for
POST /api/quizzes/generate,POST /api/quizzes/:id/submit:tests/e2e/credentials.test.tsTests for
GET /api/credentials,POST /api/credentials/mint:Important notes
beforeAll/afterAllfor cleanup, or consider mocking the database layer.app.inject()method does NOT require a running server — it uses Fastify's test injection.