test: expand endpoint coverage and harden deploy gate
Some checks failed
Code Analysis and Production Deploy / analyze (push) Failing after 15s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Has been skipped

This commit is contained in:
Torsten Schulz (local)
2026-05-21 08:03:59 +02:00
parent 5fce08ab75
commit 19d7aeefb0
10 changed files with 1013 additions and 14 deletions

View File

@@ -0,0 +1,149 @@
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' })
)
})
})
})