5bf6013460
Progressive lesson streaming via onSegment callback (fixes SSE for non-English users — locale was shadowed in lesson-reader useEffect). Adds: BullMQ workers, Redis stream buffer, token budget enforcement, Langfuse tracing, golden-eval runner, Playwright e2e scaffolding, lesson depth/locale/preferences schema, mastery map UI, admin panel (blueprints/users/reports/quality/misconceptions), image queries, source citations, view transitions, reading animations, i18n (next-intl), PDF export, surprise endpoint, and 402 passing unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { NextRequest } from 'next/server';
|
|
|
|
vi.mock('@/lib/db/queries', () => ({
|
|
getReviewCheckpoints: vi.fn(),
|
|
getNextReviewAt: vi.fn().mockResolvedValue(null),
|
|
}));
|
|
|
|
import { GET } from '../route';
|
|
import { getReviewCheckpoints } from '@/lib/db/queries';
|
|
|
|
const mockGet = vi.mocked(getReviewCheckpoints);
|
|
|
|
const REVIEW_ITEMS = [
|
|
{
|
|
conceptId: 'c1',
|
|
conceptName: 'Closures',
|
|
score: 0.65,
|
|
checkpointId: 'cp1',
|
|
checkpointPrompt: 'Explain what a closure is.',
|
|
checkpointKind: 'explain' as const,
|
|
},
|
|
];
|
|
|
|
function makeRequest(userId?: string) {
|
|
const url = userId
|
|
? `http://localhost:3000/api/review?userId=${userId}`
|
|
: 'http://localhost:3000/api/review';
|
|
return new NextRequest(url);
|
|
}
|
|
|
|
describe('GET /api/review', () => {
|
|
beforeEach(() => vi.clearAllMocks());
|
|
|
|
it('returns 400 when userId is missing', async () => {
|
|
const res = await GET(makeRequest());
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it('returns 200 with empty list when nothing due', async () => {
|
|
mockGet.mockResolvedValue([]);
|
|
const res = await GET(makeRequest('user-1'));
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.checkpoints).toHaveLength(0);
|
|
});
|
|
|
|
it('returns 200 with due checkpoints', async () => {
|
|
mockGet.mockResolvedValue(REVIEW_ITEMS);
|
|
const res = await GET(makeRequest('user-1'));
|
|
expect(res.status).toBe(200);
|
|
const body = await res.json();
|
|
expect(body.checkpoints).toHaveLength(1);
|
|
expect(body.checkpoints[0].conceptName).toBe('Closures');
|
|
expect(body.checkpoints[0].score).toBe(0.65);
|
|
});
|
|
|
|
it('passes userId to getReviewCheckpoints', async () => {
|
|
mockGet.mockResolvedValue([]);
|
|
await GET(makeRequest('user-abc'));
|
|
expect(mockGet).toHaveBeenCalledWith('user-abc');
|
|
});
|
|
});
|