Files
Curio/src/app/api/user/account/__tests__/route.test.ts
T
arnaudne 4e38b5a791 feat: initial commit — Curio mastery tutor
Full Next.js App Router application with:
- AI-graded lesson checkpoints (BKT/Elo mastery tracking)
- Auth.js v5: credentials, Google, GitHub, generic OIDC
- Anonymous-session-first with migrate-on-signin
- Admin panel: users, blueprints, reports, site settings
- Password reset + email verification (nodemailer/SMTP)
- Site config: require_auth + signups_enabled flags
- server-only guards on all DB/generation/verification modules
- PostgreSQL 16 + pgvector, Redis cache, Drizzle ORM
- 271 unit tests (Vitest), golden-eval harness, Playwright e2e stubs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 22:25:43 +02:00

68 lines
2.0 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { NextRequest } from 'next/server';
import { requireAuth } from '@/lib/auth-helpers';
const mockTx = {
delete: vi.fn().mockReturnValue({ where: vi.fn().mockResolvedValue([]) }),
};
const mockDb = {
transaction: vi.fn().mockImplementation(async (fn: (tx: typeof mockTx) => Promise<void>) => fn(mockTx)),
};
vi.mock('@/lib/db', () => ({ db: mockDb }));
vi.mock('@/lib/db/schema', () => ({
users: {},
responses: {},
mastery: {},
journeyInstances: {},
}));
vi.mock('drizzle-orm', () => ({
eq: vi.fn((col, val) => ({ col, val })),
}));
function makeRequest(): NextRequest {
return new NextRequest('http://localhost/api/user/account', { method: 'DELETE' });
}
describe('DELETE /api/user/account', () => {
beforeEach(() => {
vi.clearAllMocks();
mockTx.delete.mockReturnValue({ where: vi.fn().mockResolvedValue([]) });
mockDb.transaction.mockImplementation(async (fn: (tx: typeof mockTx) => Promise<void>) => fn(mockTx));
});
it('returns 200 {ok:true} on happy path', async () => {
const { DELETE } = await import('../route');
const res = await DELETE();
const body = await res.json();
expect(res.status).toBe(200);
expect(body).toEqual({ ok: true });
});
it('runs transaction and deletes all four tables', async () => {
const { DELETE } = await import('../route');
await DELETE();
expect(mockDb.transaction).toHaveBeenCalledOnce();
expect(mockTx.delete).toHaveBeenCalledTimes(4);
});
it('returns 401 when requireAuth throws', async () => {
vi.mocked(requireAuth).mockRejectedValueOnce(new Error('redirect'));
const { DELETE } = await import('../route');
await expect(DELETE()).rejects.toThrow('redirect');
});
it('propagates transaction errors', async () => {
mockDb.transaction.mockRejectedValueOnce(new Error('db error'));
const { DELETE } = await import('../route');
await expect(DELETE()).rejects.toThrow('db error');
});
});