import { describe, it, expect } from 'vitest'; import { Hono } from 'hono'; import { toolsRouter } from '../src/routes/tools.ts'; import type { CardsDb } from '../src/db/connection.ts'; function buildApp() { const stub = { select: () => ({ from: () => ({ where: () => ({ limit: () => [] }), innerJoin: () => ({ where: () => ({ orderBy: () => ({ limit: () => [] }) }), }), }), }), }; const app = new Hono(); app.route('/api/v1/tools', toolsRouter({ db: stub as unknown as CardsDb })); return { app }; } describe('toolsRouter — Auth-Gate', () => { it('POST /:name ohne X-User-Id ist 401', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.create', { method: 'POST', body: '{}', }); expect(res.status).toBe(401); }); }); describe('toolsRouter — Tool-Dispatch', () => { it('Unbekanntes Tool ist 404', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.unknown', { method: 'POST', headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, body: '{}', }); expect(res.status).toBe(404); const body = (await res.json()) as { error: string }; expect(body.error).toBe('unknown_tool'); }); it('cards.create mit invalid input ist 422', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.create', { method: 'POST', headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, body: '{}', }); expect(res.status).toBe(422); }); it('cards.create mit gültigem Input erreicht Deck-Lookup (404 bei stub)', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.create', { method: 'POST', headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ deck_id: 'd-1', type: 'basic', fields: { front: 'Q', back: 'A' }, }), }); expect(res.status).toBe(404); const body = (await res.json()) as { error: string }; expect(body.error).toBe('deck_not_found'); }); it('cards.search ohne query ist 422', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.search', { method: 'POST', headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, body: '{}', }); expect(res.status).toBe(422); }); it('cards.search mit gültigem query → 200 mit envelope-Shape', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/tools/cards.search', { method: 'POST', headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ query: 'Konfuzius' }), }); expect(res.status).toBe(200); const body = (await res.json()) as { query: string; results: unknown[]; app: string }; expect(body.query).toBe('Konfuzius'); expect(Array.isArray(body.results)).toBe(true); expect(body.app).toBe('cards'); }); });