Update dependencies in package.json and package-lock.json; add testing scripts for Vitest, and include new packages such as supertest and vitest. Refactor Navigation component to improve event handling and cleanup, ensuring better performance and user experience. Enhance error handling in various API endpoints for PDF uploads and CSV saves, ensuring robust error propagation. Update nodemailer transport configuration for consistency across API handlers.
This commit is contained in:
158
tests/members-endpoints.spec.ts
Normal file
158
tests/members-endpoints.spec.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
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(),
|
||||
readUsers: vi.fn(),
|
||||
readMembers: vi.fn(),
|
||||
writeUsers: vi.fn(),
|
||||
readSessions: vi.fn(),
|
||||
writeSessions: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('../server/utils/members.js', () => ({
|
||||
readMembers: vi.fn(),
|
||||
writeMembers: vi.fn(),
|
||||
saveMember: vi.fn(),
|
||||
deleteMember: vi.fn(),
|
||||
normalizeDate: vi.fn((value) => value)
|
||||
}))
|
||||
|
||||
const authUtils = await import('../server/utils/auth.js')
|
||||
const memberUtils = await import('../server/utils/members.js')
|
||||
|
||||
import membersGetHandler from '../server/api/members.get.js'
|
||||
import membersPostHandler from '../server/api/members.post.js'
|
||||
import membersDeleteHandler from '../server/api/members.delete.js'
|
||||
import membersBulkHandler from '../server/api/members/bulk.post.js'
|
||||
|
||||
describe('Members API Endpoints', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('GET /api/members', () => {
|
||||
it('verlangt Authentifizierung', async () => {
|
||||
const event = createEvent()
|
||||
await expect(membersGetHandler(event)).rejects.toMatchObject({ statusCode: 401 })
|
||||
})
|
||||
|
||||
it('gibt zusammengeführte Mitglieder zurück', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
memberUtils.readMembers.mockResolvedValue([
|
||||
{ id: 'm1', firstName: 'Anna', lastName: 'Muster', email: 'anna@club.de' }
|
||||
])
|
||||
authUtils.readUsers.mockResolvedValue([
|
||||
{ id: 'u1', name: 'Ben Nutzer', email: 'ben@club.de', role: 'mitglied', active: true }
|
||||
])
|
||||
|
||||
const response = await membersGetHandler(event)
|
||||
|
||||
expect(response.success).toBe(true)
|
||||
expect(response.members).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /api/members', () => {
|
||||
const baseBody = {
|
||||
firstName: 'Lisa',
|
||||
lastName: 'Beispiel',
|
||||
geburtsdatum: '2000-01-01',
|
||||
email: 'lisa@example.com'
|
||||
}
|
||||
|
||||
it('verweigert Zugriff ohne Token', async () => {
|
||||
const event = createEvent()
|
||||
mockSuccessReadBody(baseBody)
|
||||
await expect(membersPostHandler(event)).rejects.toMatchObject({ statusCode: 401 })
|
||||
})
|
||||
|
||||
it('verlangt Admin- oder Vorstand-Rolle', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody(baseBody)
|
||||
authUtils.verifyToken.mockReturnValue({ id: '2' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '2', role: 'mitglied' })
|
||||
|
||||
await expect(membersPostHandler(event)).rejects.toMatchObject({ statusCode: 403 })
|
||||
})
|
||||
|
||||
it('gibt 409 bei Duplikaten zurück', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody(baseBody)
|
||||
authUtils.verifyToken.mockReturnValue({ id: '2' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '2', role: 'admin' })
|
||||
memberUtils.saveMember.mockRejectedValue(new Error('existiert bereits'))
|
||||
|
||||
await expect(membersPostHandler(event)).rejects.toMatchObject({ statusCode: 409 })
|
||||
})
|
||||
|
||||
it('speichert Mitglied erfolgreich', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody(baseBody)
|
||||
authUtils.verifyToken.mockReturnValue({ id: '2' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '2', role: 'admin' })
|
||||
memberUtils.saveMember.mockResolvedValue(true)
|
||||
|
||||
const response = await membersPostHandler(event)
|
||||
expect(response.success).toBe(true)
|
||||
expect(memberUtils.saveMember).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('DELETE /api/members', () => {
|
||||
it('validiert die ID', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody({})
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '1', role: 'admin' })
|
||||
|
||||
await expect(membersDeleteHandler(event)).rejects.toMatchObject({ statusCode: 400 })
|
||||
})
|
||||
|
||||
it('löscht Mitglied erfolgreich', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody({ id: 'm1' })
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '1', role: 'vorstand' })
|
||||
memberUtils.deleteMember.mockResolvedValue(true)
|
||||
|
||||
const response = await membersDeleteHandler(event)
|
||||
expect(response.success).toBe(true)
|
||||
expect(memberUtils.deleteMember).toHaveBeenCalledWith('m1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /api/members/bulk', () => {
|
||||
const importBody = {
|
||||
members: [
|
||||
{ firstName: 'Paul', lastName: 'Team', geburtsdatum: '2001-02-03' }
|
||||
]
|
||||
}
|
||||
|
||||
it('validiert members-Array', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody({ members: [] })
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '1', role: 'admin' })
|
||||
|
||||
await expect(membersBulkHandler(event)).rejects.toMatchObject({ statusCode: 400 })
|
||||
})
|
||||
|
||||
it('importiert Mitglieder und schreibt Datei', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
mockSuccessReadBody(importBody)
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserById.mockResolvedValue({ id: '1', role: 'admin' })
|
||||
memberUtils.readMembers.mockResolvedValue([])
|
||||
memberUtils.writeMembers.mockResolvedValue(true)
|
||||
|
||||
const response = await membersBulkHandler(event)
|
||||
|
||||
expect(response.success).toBe(true)
|
||||
expect(response.summary.imported).toBe(1)
|
||||
expect(memberUtils.writeMembers).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user