169 lines
6.0 KiB
TypeScript
169 lines
6.0 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { createEvent, mockSuccessReadBody } from './setup'
|
|
|
|
vi.mock('../server/utils/auth.js', () => {
|
|
return {
|
|
readUsers: vi.fn(),
|
|
writeUsers: vi.fn(),
|
|
verifyPassword: vi.fn(),
|
|
generateToken: vi.fn(),
|
|
createSession: vi.fn(),
|
|
hashPassword: vi.fn(),
|
|
verifyToken: vi.fn(),
|
|
deleteSession: vi.fn(),
|
|
getUserFromToken: vi.fn(),
|
|
readSessions: vi.fn(),
|
|
writeSessions: vi.fn()
|
|
}
|
|
})
|
|
|
|
vi.mock('nodemailer', () => {
|
|
const sendMail = vi.fn().mockResolvedValue(true)
|
|
const createTransport = vi.fn(() => ({ sendMail }))
|
|
return {
|
|
default: { createTransport },
|
|
createTransport
|
|
}
|
|
})
|
|
|
|
const authUtils = await import('../server/utils/auth.js')
|
|
const nodemailer = await import('nodemailer')
|
|
|
|
import loginHandler from '../server/api/auth/login.post.js'
|
|
import logoutHandler from '../server/api/auth/logout.post.js'
|
|
import registerHandler from '../server/api/auth/register.post.js'
|
|
import resetPasswordHandler from '../server/api/auth/reset-password.post.js'
|
|
import statusHandler from '../server/api/auth/status.get.js'
|
|
|
|
describe('Auth API Endpoints', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('POST /api/auth/login', () => {
|
|
it('wirft 400 bei fehlenden Feldern', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({})
|
|
|
|
await expect(loginHandler(event)).rejects.toMatchObject({ statusCode: 400 })
|
|
})
|
|
|
|
it('wirft 401 bei unbekanntem Benutzer', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({ email: 'test@example.com', password: 'password' })
|
|
authUtils.readUsers.mockResolvedValue([])
|
|
|
|
await expect(loginHandler(event)).rejects.toMatchObject({ statusCode: 401 })
|
|
})
|
|
|
|
it('gibt Token und Cookie bei Erfolg zurück', async () => {
|
|
const event = createEvent()
|
|
const user = { id: '1', email: 'test@example.com', password: 'hash', role: 'mitglied', active: true, lastLogin: null }
|
|
mockSuccessReadBody({ email: user.email, password: 'plain' })
|
|
authUtils.readUsers.mockResolvedValue([user])
|
|
authUtils.verifyPassword.mockResolvedValue(true)
|
|
authUtils.generateToken.mockReturnValue('jwt-token')
|
|
authUtils.createSession.mockResolvedValue({})
|
|
authUtils.writeUsers.mockResolvedValue(true)
|
|
|
|
const response = await loginHandler(event)
|
|
|
|
expect(response.success).toBe(true)
|
|
expect(response.token).toBe('jwt-token')
|
|
expect(response.user).toMatchObject({ id: '1', email: user.email })
|
|
expect(authUtils.createSession).toHaveBeenCalledWith('1', 'jwt-token')
|
|
expect(authUtils.writeUsers).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('POST /api/auth/logout', () => {
|
|
it('löscht Session und Cookie, wenn Token vorhanden ist', async () => {
|
|
const event = createEvent({ cookies: { auth_token: 'token' } })
|
|
authUtils.deleteSession.mockResolvedValue()
|
|
|
|
const response = await logoutHandler(event)
|
|
|
|
expect(response.success).toBe(true)
|
|
expect(authUtils.deleteSession).toHaveBeenCalledWith('token')
|
|
})
|
|
|
|
it('wirft 500 bei Fehlern', async () => {
|
|
const event = createEvent({ cookies: { auth_token: 'token' } })
|
|
authUtils.deleteSession.mockRejectedValue(new Error('boom'))
|
|
|
|
await expect(logoutHandler(event)).rejects.toMatchObject({ statusCode: 500 })
|
|
})
|
|
})
|
|
|
|
describe('POST /api/auth/register', () => {
|
|
it('prüft Pflichtfelder', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({})
|
|
|
|
await expect(registerHandler(event)).rejects.toMatchObject({ statusCode: 400 })
|
|
})
|
|
|
|
it('verhindert doppelte Benutzer', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({ name: 'Max', email: 'max@example.com', password: '12345678' })
|
|
authUtils.readUsers.mockResolvedValue([{ email: 'max@example.com' }])
|
|
|
|
await expect(registerHandler(event)).rejects.toMatchObject({ statusCode: 409 })
|
|
})
|
|
|
|
it('legt Benutzer an und versendet E-Mails', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({ name: 'Max', email: 'max@example.com', password: '12345678', phone: '123' })
|
|
authUtils.readUsers.mockResolvedValue([])
|
|
authUtils.hashPassword.mockResolvedValue('hashed')
|
|
authUtils.writeUsers.mockResolvedValue(true)
|
|
|
|
const response = await registerHandler(event)
|
|
|
|
expect(response.success).toBe(true)
|
|
expect(authUtils.writeUsers).toHaveBeenCalled()
|
|
expect(nodemailer.default.createTransport).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('POST /api/auth/reset-password', () => {
|
|
it('prüft Pflichtfelder', async () => {
|
|
const event = createEvent()
|
|
mockSuccessReadBody({})
|
|
|
|
const response = await resetPasswordHandler(event)
|
|
expect(response.success).toBe(true)
|
|
})
|
|
|
|
it('aktualisiert Passwort bei vorhandenem Benutzer', async () => {
|
|
const event = createEvent()
|
|
const user = { id: '1', email: 'user@example.com', name: 'User', password: 'hash' }
|
|
mockSuccessReadBody({ email: user.email })
|
|
authUtils.readUsers.mockResolvedValue([user])
|
|
authUtils.hashPassword.mockResolvedValue('new-hash')
|
|
authUtils.writeUsers.mockResolvedValue(true)
|
|
|
|
const response = await resetPasswordHandler(event)
|
|
expect(response.success).toBe(true)
|
|
expect(authUtils.writeUsers).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('GET /api/auth/status', () => {
|
|
it('liefert loggedOut, wenn kein Cookie gesetzt ist', async () => {
|
|
const event = createEvent()
|
|
const response = await statusHandler(event)
|
|
expect(response.isLoggedIn).toBe(false)
|
|
})
|
|
|
|
it('liefert Benutzerinformationen bei gültigem Token', async () => {
|
|
const event = createEvent({ cookies: { auth_token: 'token' } })
|
|
authUtils.getUserFromToken.mockResolvedValue({ id: '1', email: 'user@example.com', name: 'User', role: 'mitglied' })
|
|
|
|
const response = await statusHandler(event)
|
|
expect(response.isLoggedIn).toBe(true)
|
|
expect(response.user).toMatchObject({ id: '1' })
|
|
})
|
|
})
|
|
})
|