From fc76fac9818b9aa8146dde46412a308325a14474 Mon Sep 17 00:00:00 2001 From: Hermann_Kitio Date: Tue, 21 Apr 2026 03:07:13 +0300 Subject: [PATCH] test(sujets): 5 tests POST /sujets/idees Co-Authored-By: Claude Opus 4.7 (1M context) --- src/routes/__tests__/sujets.test.ts | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/routes/__tests__/sujets.test.ts b/src/routes/__tests__/sujets.test.ts index badb147..d61094a 100644 --- a/src/routes/__tests__/sujets.test.ts +++ b/src/routes/__tests__/sujets.test.ts @@ -9,6 +9,10 @@ vi.mock('../../lib/supabase', () => ({ }, })) +vi.mock('../../lib/deepseek', () => ({ + generateIdees: vi.fn(), +})) + vi.mock('../../middleware/auth', () => ({ authMiddleware: async (c: any, next: any) => { const authHeader = c.req.header('Authorization') @@ -32,6 +36,7 @@ vi.mock('../../middleware/auth', () => ({ })) import { supabase } from '../../lib/supabase' +import { generateIdees } from '../../lib/deepseek' import sujetsRoutes from '../sujets' function buildApp() { @@ -163,3 +168,93 @@ describe('GET /sujets', () => { expect(body.code).toBe('INTERNAL_ERROR') }) }) + +describe('POST /sujets/idees', () => { + beforeEach(() => { + vi.mocked(generateIdees).mockReset() + }) + + const VALID_CONTENU = Array.from({ length: 35 }, (_, i) => `mot${i}`).join(' ') + + it('retourne 401 sans authentification', async () => { + const app = buildApp() + const res = await app.request('/sujets/idees', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ sujet_consigne: 'x', contenu_partiel: VALID_CONTENU }), + }) + + expect(res.status).toBe(401) + const body = await res.json() + expect(body.code).toBe('AUTH_REQUIRED') + }) + + it('retourne 400 VALIDATION_ERROR si sujet_consigne manquant', async () => { + const app = buildApp() + const res = await app.request('/sujets/idees', { + method: 'POST', + headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' }, + body: JSON.stringify({ contenu_partiel: VALID_CONTENU }), + }) + + expect(res.status).toBe(400) + const body = await res.json() + expect(body.code).toBe('VALIDATION_ERROR') + expect(vi.mocked(generateIdees)).not.toHaveBeenCalled() + }) + + it('retourne 400 VALIDATION_ERROR si contenu_partiel contient moins de 30 mots', async () => { + const app = buildApp() + const res = await app.request('/sujets/idees', { + method: 'POST', + headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + sujet_consigne: 'Rédigez une lettre.', + contenu_partiel: 'Trop court.', + }), + }) + + expect(res.status).toBe(400) + const body = await res.json() + expect(body.code).toBe('VALIDATION_ERROR') + expect(vi.mocked(generateIdees)).not.toHaveBeenCalled() + }) + + it('retourne 200 avec idees[] en cas de succès', async () => { + const idees = ['Idée 1', 'Idée 2', 'Idée 3', 'Idée 4', 'Idée 5'] + vi.mocked(generateIdees).mockResolvedValueOnce(idees) + + const app = buildApp() + const res = await app.request('/sujets/idees', { + method: 'POST', + headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + sujet_consigne: 'Rédigez une lettre.', + contenu_partiel: VALID_CONTENU, + }), + }) + + expect(res.status).toBe(200) + const body = await res.json() + expect(body).toEqual({ idees }) + expect(vi.mocked(generateIdees)).toHaveBeenCalledWith('Rédigez une lettre.', VALID_CONTENU) + }) + + it('retourne 500 INTERNAL_ERROR si DeepSeek throw', async () => { + vi.mocked(generateIdees).mockRejectedValueOnce(new Error('DeepSeek down')) + + const app = buildApp() + const res = await app.request('/sujets/idees', { + method: 'POST', + headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + sujet_consigne: 'Rédigez une lettre.', + contenu_partiel: VALID_CONTENU, + }), + }) + + expect(res.status).toBe(500) + const body = await res.json() + expect(body.code).toBe('INTERNAL_ERROR') + }) +})