import { beforeEach, describe, expect, it, vi } from 'vitest' import { createEvent, mockSuccessReadBody } from './setup' import fsPromises from 'fs/promises' import { promises as fs } from 'fs' vi.mock('nodemailer', () => { const sendMail = vi.fn().mockResolvedValue(true) const createTransport = vi.fn(() => ({ sendMail })) return { default: { createTransport }, createTransport } }) vi.mock('../server/utils/news.js', () => ({ readNews: vi.fn() })) const nodemailer = await import('nodemailer') const newsUtils = await import('../server/utils/news.js') import contactHandler from '../server/api/contact.post.js' import galerieHandler from '../server/api/galerie.get.js' import newsPublicHandler from '../server/api/news-public.get.js' import termineHandler from '../server/api/termine.get.js' import spielplaeneHandler from '../server/api/spielplaene.get.js' describe('Öffentliche API-Endpunkte', () => { beforeEach(() => { vi.restoreAllMocks() vi.clearAllMocks() }) describe('POST /api/contact', () => { it('validiert Pflichtfelder', async () => { const event = createEvent() mockSuccessReadBody({}) await expect(contactHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('validiert E-Mail-Adresse', async () => { const event = createEvent() mockSuccessReadBody({ name: 'Max', email: 'invalid', subject: 'Hi', message: 'Test' }) await expect(contactHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('sendet E-Mail bei gültigen Daten', async () => { const event = createEvent() mockSuccessReadBody({ name: 'Max', email: 'max@example.com', subject: 'Frage', message: 'Hallo' }) const response = await contactHandler(event) expect(response.success).toBe(true) expect(nodemailer.default.createTransport).toHaveBeenCalled() }) }) describe('GET /api/galerie', () => { it('liefert leeres Array, wenn Verzeichnis fehlt', async () => { vi.spyOn(fs, 'access').mockRejectedValue(new Error('not found')) const result = await galerieHandler(createEvent()) expect(result).toEqual([]) }) it('filtert nur Bilddateien', async () => { vi.spyOn(fs, 'access').mockResolvedValue(undefined) vi.spyOn(fs, 'readdir').mockResolvedValue(['foto-1.jpg', 'readme.md']) const result = await galerieHandler(createEvent()) expect(result).toHaveLength(1) expect(result[0].filename).toBe('foto-1.jpg') }) }) describe('GET /api/news-public', () => { it('filtert nicht öffentliche News', async () => { const now = new Date() newsUtils.readNews.mockResolvedValue([ { id: 1, isPublic: true, isHidden: false, created: now.toISOString(), title: 'ok' }, { id: 2, isPublic: false, isHidden: false, created: now.toISOString() }, { id: 3, isPublic: true, isHidden: true, created: now.toISOString() } ]) const response = await newsPublicHandler(createEvent()) expect(response.success).toBe(true) expect(response.news).toHaveLength(1) expect(response.news[0].id).toBe(1) }) it('begrenzt Ergebnis auf drei Einträge', async () => { const now = Date.now() newsUtils.readNews.mockResolvedValue( Array.from({ length: 5 }).map((_, index) => ({ id: index + 1, isPublic: true, isHidden: false, created: new Date(now - index * 1000).toISOString() })) ) const response = await newsPublicHandler(createEvent()) expect(response.news).toHaveLength(3) expect(response.news[0].id).toBe(1) }) }) describe('GET /api/termine', () => { it('parst CSV-Dateien', async () => { const csv = 'Datum,Uhrzeit,Titel,Beschreibung,Kategorie\n2025-01-01,19:00,Training,Beschreibung,Sport' vi.spyOn(fsPromises, 'readFile').mockResolvedValue(csv) const response = await termineHandler(createEvent()) expect(response.success).toBe(true) expect(response.termine[0]).toMatchObject({ titel: 'Training', kategorie: 'Sport' }) }) it('gibt leeres Array bei Fehlern zurück', async () => { vi.spyOn(fsPromises, 'readFile').mockRejectedValue(new Error('kaputt')) const response = await termineHandler(createEvent()) expect(response.termine).toEqual([]) }) }) describe('GET /api/spielplaene', () => { it('filtert nur erlaubte Dateitypen', async () => { vi.spyOn(fs, 'access').mockResolvedValue(undefined) vi.spyOn(fs, 'readdir').mockResolvedValue(['plan.pdf', 'notizen.txt']) const result = await spielplaeneHandler(createEvent()) expect(result).toEqual(['plan.pdf']) }) it('gibt leeres Array zurück, wenn Verzeichnis fehlt', async () => { vi.spyOn(fs, 'access').mockRejectedValue(new Error('not found')) const result = await spielplaeneHandler(createEvent()) expect(result).toEqual([]) }) }) })