Add sharp image processing library and update dependencies in package.json and package-lock.json; enhance Navigation component with new 'Galerie' link for improved user navigation.
This commit is contained in:
163
tests/galerie-endpoints.spec.ts
Normal file
163
tests/galerie-endpoints.spec.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEvent, mockSuccessReadBody } from './setup'
|
||||
import fs from 'fs/promises'
|
||||
import sharp from 'sharp'
|
||||
|
||||
vi.mock('../server/utils/auth.js', () => ({
|
||||
getUserFromToken: vi.fn(),
|
||||
verifyToken: vi.fn(),
|
||||
readUsers: vi.fn(),
|
||||
writeUsers: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('sharp', () => ({
|
||||
default: vi.fn(() => ({
|
||||
resize: vi.fn().mockReturnThis(),
|
||||
toFile: vi.fn().mockResolvedValue({})
|
||||
}))
|
||||
}))
|
||||
|
||||
vi.mock('multer', () => {
|
||||
const single = vi.fn((field) => (req, _res, cb) => {
|
||||
if (req.__mockMulterError) {
|
||||
cb(req.__mockMulterError)
|
||||
return
|
||||
}
|
||||
req.file = req.__mockFile || null
|
||||
req.body = req.body || {}
|
||||
cb(null)
|
||||
})
|
||||
|
||||
const multerFn = vi.fn(() => ({ single }))
|
||||
const diskStorage = vi.fn(() => ({}))
|
||||
multerFn.diskStorage = diskStorage
|
||||
|
||||
return {
|
||||
default: multerFn,
|
||||
diskStorage
|
||||
}
|
||||
})
|
||||
|
||||
const authUtils = await import('../server/utils/auth.js')
|
||||
|
||||
import uploadHandler from '../server/api/galerie/upload.post.js'
|
||||
import listHandler from '../server/api/galerie/list.get.js'
|
||||
import imageHandler from '../server/api/galerie/[id].get.js'
|
||||
|
||||
describe('Galerie API Endpoints', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.spyOn(fs, 'readFile').mockResolvedValue('[]')
|
||||
vi.spyOn(fs, 'writeFile').mockResolvedValue(undefined)
|
||||
vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined)
|
||||
vi.spyOn(fs, 'access').mockResolvedValue(undefined)
|
||||
})
|
||||
|
||||
describe('POST /api/galerie/upload', () => {
|
||||
it('erfordert Authentifizierung', async () => {
|
||||
const event = createEvent({ method: 'POST' })
|
||||
event.node.req.__mockFile = { filename: 'test.jpg', path: 'tmp/test.jpg', originalname: 'test.jpg', mimetype: 'image/jpeg' }
|
||||
event.node.req.body = { title: 'Test', isPublic: 'true' }
|
||||
|
||||
await expect(uploadHandler(event)).rejects.toMatchObject({ statusCode: 401 })
|
||||
})
|
||||
|
||||
it('erfordert Admin- oder Vorstand-Rolle', async () => {
|
||||
const event = createEvent({ method: 'POST', cookies: { auth_token: 'token' } })
|
||||
event.node.req.__mockFile = { filename: 'test.jpg', path: 'tmp/test.jpg', originalname: 'test.jpg', mimetype: 'image/jpeg' }
|
||||
event.node.req.body = { title: 'Test', isPublic: 'true' }
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserFromToken.mockResolvedValue({ id: '1', role: 'mitglied', active: true })
|
||||
|
||||
await expect(uploadHandler(event)).rejects.toMatchObject({ statusCode: 403 })
|
||||
})
|
||||
|
||||
it('lädt Bild hoch und erstellt Thumbnail', async () => {
|
||||
const event = createEvent({ method: 'POST', cookies: { auth_token: 'token' } })
|
||||
event.node.req.__mockFile = { filename: 'test.jpg', path: 'tmp/test.jpg', originalname: 'test.jpg', mimetype: 'image/jpeg' }
|
||||
event.node.req.body = { title: 'Test Bild', description: 'Beschreibung', isPublic: 'true' }
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserFromToken.mockResolvedValue({ id: '1', role: 'admin', active: true })
|
||||
|
||||
const response = await uploadHandler(event)
|
||||
|
||||
expect(response.success).toBe(true)
|
||||
expect(sharp).toHaveBeenCalled()
|
||||
expect(fs.writeFile).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/galerie/list', () => {
|
||||
it('zeigt öffentliche Bilder für alle', async () => {
|
||||
const event = createEvent()
|
||||
vi.spyOn(fs, 'readFile').mockResolvedValue(JSON.stringify([
|
||||
{ id: '1', title: 'Öffentlich', isPublic: true, previewFilename: 'preview_1.jpg', uploadedAt: '2025-01-01' },
|
||||
{ id: '2', title: 'Privat', isPublic: false, previewFilename: 'preview_2.jpg', uploadedAt: '2025-01-02' }
|
||||
]))
|
||||
|
||||
const response = await listHandler(event)
|
||||
|
||||
expect(response.success).toBe(true)
|
||||
expect(response.images).toHaveLength(1)
|
||||
expect(response.images[0].id).toBe('1')
|
||||
})
|
||||
|
||||
it('zeigt alle Bilder für eingeloggte Mitglieder', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
vi.spyOn(fs, 'readFile').mockResolvedValue(JSON.stringify([
|
||||
{ id: '1', title: 'Öffentlich', isPublic: true, previewFilename: 'preview_1.jpg', uploadedAt: '2025-01-01' },
|
||||
{ id: '2', title: 'Privat', isPublic: false, previewFilename: 'preview_2.jpg', uploadedAt: '2025-01-02' }
|
||||
]))
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserFromToken.mockResolvedValue({ id: '1', active: true })
|
||||
|
||||
const response = await listHandler(event)
|
||||
|
||||
expect(response.images).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/galerie/[id]', () => {
|
||||
it('verweigert Zugriff auf private Bilder für nicht eingeloggte Benutzer', async () => {
|
||||
const event = createEvent()
|
||||
event.context.params = { id: '1' }
|
||||
vi.spyOn(fs, 'readFile')
|
||||
.mockResolvedValueOnce(JSON.stringify([
|
||||
{ id: '1', filename: 'test.jpg', previewFilename: 'preview_test.jpg', isPublic: false }
|
||||
]))
|
||||
|
||||
await expect(imageHandler(event)).rejects.toMatchObject({ statusCode: 403 })
|
||||
})
|
||||
|
||||
it('liefert Bild für eingeloggte Mitglieder', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
event.context.params = { id: '1' }
|
||||
vi.spyOn(fs, 'readFile')
|
||||
.mockResolvedValueOnce(JSON.stringify([
|
||||
{ id: '1', filename: 'test.jpg', previewFilename: 'preview_test.jpg', isPublic: false }
|
||||
]))
|
||||
.mockResolvedValueOnce(Buffer.from('image data'))
|
||||
authUtils.verifyToken.mockReturnValue({ id: '1' })
|
||||
authUtils.getUserFromToken.mockResolvedValue({ id: '1', active: true })
|
||||
|
||||
const response = await imageHandler(event)
|
||||
|
||||
expect(response).toBeInstanceOf(Buffer)
|
||||
})
|
||||
|
||||
it('liefert Preview-Bild bei preview=true', async () => {
|
||||
const event = createEvent({ query: { preview: 'true' } })
|
||||
event.context.params = { id: '1' }
|
||||
vi.spyOn(fs, 'readFile')
|
||||
.mockResolvedValueOnce(JSON.stringify([
|
||||
{ id: '1', filename: 'test.jpg', previewFilename: 'preview_test.jpg', isPublic: true }
|
||||
]))
|
||||
.mockResolvedValueOnce(Buffer.from('preview data'))
|
||||
|
||||
const response = await imageHandler(event)
|
||||
|
||||
expect(response).toBeInstanceOf(Buffer)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user