test(sujets): 8 tests route GET /sujets
This commit is contained in:
parent
cc72487013
commit
1a5b79807e
1 changed files with 165 additions and 0 deletions
165
src/routes/__tests__/sujets.test.ts
Normal file
165
src/routes/__tests__/sujets.test.ts
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
// ─── Mocks ───────────────────────────────────────────────────────────────────
|
||||
|
||||
vi.mock('../../lib/supabase', () => ({
|
||||
supabase: {
|
||||
from: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('../../middleware/auth', () => ({
|
||||
authMiddleware: async (c: any, next: any) => {
|
||||
const authHeader = c.req.header('Authorization')
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return c.json({ error: true, code: 'AUTH_REQUIRED' }, 401)
|
||||
}
|
||||
c.set('user', { id: 'test-user-id', email: 'u@test.com' })
|
||||
c.set('profile', {
|
||||
id: 'test-user-id',
|
||||
email: 'u@test.com',
|
||||
plan: 'free',
|
||||
simulations_used: 0,
|
||||
stripe_customer_id: null,
|
||||
stripe_subscription_id: null,
|
||||
plan_expires_at: null,
|
||||
created_at: '2026-01-01',
|
||||
updated_at: '2026-01-01',
|
||||
})
|
||||
await next()
|
||||
},
|
||||
}))
|
||||
|
||||
import { supabase } from '../../lib/supabase'
|
||||
import sujetsRoutes from '../sujets'
|
||||
|
||||
function buildApp() {
|
||||
const app = new Hono()
|
||||
app.route('/sujets', sujetsRoutes)
|
||||
return app
|
||||
}
|
||||
|
||||
/** Mock from('sujets').select().eq('mode').eq('tache').eq('actif').order() */
|
||||
function mockSujetsQuery(rows: unknown[] | null, error: unknown = null) {
|
||||
vi.mocked(supabase.from).mockReturnValueOnce({
|
||||
select: vi.fn(() => ({
|
||||
eq: vi.fn(() => ({
|
||||
eq: vi.fn(() => ({
|
||||
eq: vi.fn(() => ({
|
||||
order: vi.fn(() => ({ data: rows, error })),
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
} as any)
|
||||
}
|
||||
|
||||
const AUTH_HEADERS = { Authorization: 'Bearer valid-token' }
|
||||
|
||||
describe('GET /sujets', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(supabase.from).mockReset()
|
||||
})
|
||||
|
||||
it('retourne 401 sans authentification', async () => {
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EE&tache=1')
|
||||
|
||||
expect(res.status).toBe(401)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('AUTH_REQUIRED')
|
||||
})
|
||||
|
||||
it('retourne 400 VALIDATION_ERROR si mode invalide', async () => {
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=XX&tache=1', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(400)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('VALIDATION_ERROR')
|
||||
})
|
||||
|
||||
it('retourne 400 VALIDATION_ERROR si mode manquant', async () => {
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?tache=1', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(400)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('VALIDATION_ERROR')
|
||||
})
|
||||
|
||||
it('retourne 400 VALIDATION_ERROR si tache invalide', async () => {
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EE&tache=9', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(400)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('VALIDATION_ERROR')
|
||||
})
|
||||
|
||||
it('retourne 400 VALIDATION_ERROR si tache non numérique', async () => {
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EE&tache=abc', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(400)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('VALIDATION_ERROR')
|
||||
})
|
||||
|
||||
it('retourne la liste des sujets actifs pour (mode, tache) valides', async () => {
|
||||
const rows = [
|
||||
{
|
||||
id: 'sujet-1',
|
||||
consigne: 'Écrivez un texte.',
|
||||
role: null,
|
||||
contexte: null,
|
||||
doc1_titre: null,
|
||||
doc1_texte: null,
|
||||
doc2_titre: null,
|
||||
doc2_texte: null,
|
||||
},
|
||||
{
|
||||
id: 'sujet-2',
|
||||
consigne: 'Autre consigne.',
|
||||
role: 'journaliste',
|
||||
contexte: 'magazine',
|
||||
doc1_titre: null,
|
||||
doc1_texte: null,
|
||||
doc2_titre: null,
|
||||
doc2_texte: null,
|
||||
},
|
||||
]
|
||||
mockSujetsQuery(rows)
|
||||
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EE&tache=1', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
const body = await res.json()
|
||||
expect(body).toEqual({ sujets: rows })
|
||||
expect(vi.mocked(supabase.from).mock.calls[0][0]).toBe('sujets')
|
||||
})
|
||||
|
||||
it('retourne un tableau vide si aucun sujet actif', async () => {
|
||||
mockSujetsQuery([])
|
||||
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EO&tache=3', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
const body = await res.json()
|
||||
expect(body).toEqual({ sujets: [] })
|
||||
})
|
||||
|
||||
it('retourne 500 INTERNAL_ERROR si Supabase échoue', async () => {
|
||||
mockSujetsQuery(null, { message: 'connection refused' })
|
||||
|
||||
const app = buildApp()
|
||||
const res = await app.request('/sujets?mode=EE&tache=2', { headers: AUTH_HEADERS })
|
||||
|
||||
expect(res.status).toBe(500)
|
||||
const body = await res.json()
|
||||
expect(body.code).toBe('INTERNAL_ERROR')
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue