import { beforeEach, describe, expect, it, vi } from 'vitest' import { createEvent, mockSuccessReadBody } from './setup' vi.mock('../server/utils/auth.js', () => ({ verifyToken: vi.fn(), getUserById: vi.fn(), hasAnyRole: vi.fn((user, ...roles) => { if (!user) return false const userRoles = Array.isArray(user.roles) ? user.roles : (user.role ? [user.role] : []) return roles.some(r => userRoles.includes(r)) }) })) vi.mock('../server/utils/termine.js', () => ({ readTermine: vi.fn(), saveTermin: vi.fn(), deleteTermin: vi.fn() })) const authUtils = await import('../server/utils/auth.js') const termineUtils = await import('../server/utils/termine.js') import termineGetHandler from '../server/api/termine-manage.get.js' import terminePostHandler from '../server/api/termine-manage.post.js' import termineDeleteHandler from '../server/api/termine-manage.delete.js' describe('Termine-Manage API Endpoints', () => { beforeEach(() => { vi.clearAllMocks() }) const adminEvent = () => { const event = createEvent({ cookies: { auth_token: 'token' } }) authUtils.verifyToken.mockReturnValue({ id: '1' }) authUtils.getUserById.mockResolvedValue({ id: '1', roles: ['admin'] }) authUtils.hasAnyRole.mockReturnValue(true) return event } describe('GET /api/termine-manage', () => { it('verlangt Authentifizierung', async () => { const event = createEvent() await expect(termineGetHandler(event)).rejects.toMatchObject({ statusCode: 401 }) }) it('lehnt ungültiges Token ab', async () => { const event = createEvent({ cookies: { auth_token: 'bad' } }) authUtils.verifyToken.mockReturnValue(null) await expect(termineGetHandler(event)).rejects.toMatchObject({ statusCode: 401 }) }) it('verlangt Admin- oder Vorstand-Rolle', async () => { const event = createEvent({ cookies: { auth_token: 'token' } }) authUtils.verifyToken.mockReturnValue({ id: '1' }) authUtils.getUserById.mockResolvedValue({ id: '1', roles: ['mitglied'] }) authUtils.hasAnyRole.mockReturnValue(false) await expect(termineGetHandler(event)).rejects.toMatchObject({ statusCode: 403 }) }) it('liefert Terminliste', async () => { const event = adminEvent() termineUtils.readTermine.mockResolvedValue([ { datum: '2025-06-01', titel: 'Hauptversammlung', kategorie: 'Verein' } ]) const result = await termineGetHandler(event) expect(result.success).toBe(true) expect(result.termine).toHaveLength(1) expect(result.termine[0].titel).toBe('Hauptversammlung') }) }) describe('POST /api/termine-manage', () => { it('verlangt Authentifizierung', async () => { const event = createEvent() mockSuccessReadBody({}) await expect(terminePostHandler(event)).rejects.toMatchObject({ statusCode: 401 }) }) it('verlangt Admin- oder Vorstand-Rolle', async () => { const event = createEvent({ cookies: { auth_token: 'token' } }) authUtils.verifyToken.mockReturnValue({ id: '1' }) authUtils.getUserById.mockResolvedValue({ id: '1', roles: ['mitglied'] }) authUtils.hasAnyRole.mockReturnValue(false) mockSuccessReadBody({ datum: '2025-06-01', titel: 'Test' }) await expect(terminePostHandler(event)).rejects.toMatchObject({ statusCode: 403 }) }) it('validiert Pflichtfelder – kein Titel', async () => { const event = adminEvent() mockSuccessReadBody({ datum: '2025-06-01' }) await expect(terminePostHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('validiert Pflichtfelder – kein Datum', async () => { const event = adminEvent() mockSuccessReadBody({ titel: 'Training' }) await expect(terminePostHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('speichert Termin erfolgreich', async () => { const event = adminEvent() termineUtils.saveTermin.mockResolvedValue(undefined) mockSuccessReadBody({ datum: '2025-06-01', titel: 'Hauptversammlung', kategorie: 'Verein', uhrzeit: '19:00' }) const result = await terminePostHandler(event) expect(result.success).toBe(true) expect(termineUtils.saveTermin).toHaveBeenCalledWith( expect.objectContaining({ datum: '2025-06-01', titel: 'Hauptversammlung' }) ) }) }) describe('DELETE /api/termine-manage', () => { it('verlangt Authentifizierung', async () => { const event = createEvent() await expect(termineDeleteHandler(event)).rejects.toMatchObject({ statusCode: 401 }) }) it('verlangt Admin- oder Vorstand-Rolle', async () => { const event = createEvent({ cookies: { auth_token: 'token' } }) authUtils.verifyToken.mockReturnValue({ id: '1' }) authUtils.getUserById.mockResolvedValue({ id: '1', roles: ['mitglied'] }) authUtils.hasAnyRole.mockReturnValue(false) await expect(termineDeleteHandler(event)).rejects.toMatchObject({ statusCode: 403 }) }) it('validiert Pflichtfelder – datum und titel fehlen', async () => { const event = adminEvent() // __query ist leer → keine datum/titel await expect(termineDeleteHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('löscht Termin erfolgreich', async () => { const event = adminEvent() event.__query = { datum: '2025-06-01', titel: 'Hauptversammlung', kategorie: 'Verein' } termineUtils.deleteTermin.mockResolvedValue(undefined) const result = await termineDeleteHandler(event) expect(result.success).toBe(true) expect(termineUtils.deleteTermin).toHaveBeenCalledWith( expect.objectContaining({ datum: '2025-06-01', titel: 'Hauptversammlung' }) ) }) }) })