import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { dashboardImageSrc, deleteDashboardImage, fetchDashboardImages, uploadDashboardImage, } from './dashboard-images-api'; /** * dashboard-images-api.test — NEU (quick-260921-pi9). Die vier Aufrufe des * Bilderrahmen-Widgets gegen /dashboard/images: FormData-Feld `image` ohne * eigenen Content-Type, Cookie immer mit, 413 und 400 mit deutschen * Meldungen, Proxy-Pfad fuer . */ const { mockFetch } = vi.hoisted(() => ({ mockFetch: vi.fn() })); beforeEach(() => { mockFetch.mockReset(); vi.stubGlobal('fetch', mockFetch); }); afterEach(() => { vi.unstubAllGlobals(); }); describe('dashboard-images-api (quick-260921-pi9)', () => { it('Test 1: uploadDashboardImage sendet POST mit FormData-Feld image, credentials include, ohne Content-Type von Hand', async () => { mockFetch.mockResolvedValue( new Response(JSON.stringify({ id: 'img-1', originalName: 'a.png', mimeType: 'image/png', size: 3 }), { status: 201, }), ); const file = new File([new Uint8Array([1, 2, 3])], 'a.png', { type: 'image/png' }); const result = await uploadDashboardImage(file); expect(result.id).toBe('img-1'); const [url, init] = mockFetch.mock.calls[0] as [string, RequestInit]; expect(String(url).endsWith('/dashboard/images')).toBe(true); expect(init.method).toBe('POST'); expect(init.credentials).toBe('include'); expect(init.headers).toBeUndefined(); const body = init.body as FormData; expect(body.get('image')).toBeInstanceOf(File); expect((body.get('image') as File).name).toBe('a.png'); }); it('Test 2: Status 413 -> deutsche Meldung "zu gross"', async () => { mockFetch.mockResolvedValue(new Response('{"message":"File too large"}', { status: 413 })); await expect(uploadDashboardImage(new File([1], 'x.png'))).rejects.toThrow( 'Die Datei ist zu groß – erlaubt sind höchstens 5 MB.', ); }); it('Test 3: Status 400 mit { message } -> genau diese Meldung; sonst allgemeine Meldung', async () => { mockFetch.mockResolvedValue( new Response(JSON.stringify({ message: 'Nur Bilder im Format PNG, JPEG, GIF oder WebP sind erlaubt.' }), { status: 400, }), ); await expect(uploadDashboardImage(new File([1], 'x.png'))).rejects.toThrow( 'Nur Bilder im Format PNG, JPEG, GIF oder WebP sind erlaubt.', ); mockFetch.mockResolvedValue(new Response('kaputt', { status: 500 })); await expect(uploadDashboardImage(new File([1], 'x.png'))).rejects.toThrow( 'Das Bild konnte nicht hochgeladen werden.', ); }); it('Test 4: fetchDashboardImages (GET) und deleteDashboardImage (DELETE, Kennung kodiert) mit Cookie', async () => { mockFetch.mockResolvedValue(new Response('[]', { status: 200 })); await expect(fetchDashboardImages()).resolves.toEqual([]); const [listUrl, listInit] = mockFetch.mock.calls[0] as [string, RequestInit]; expect(String(listUrl).endsWith('/dashboard/images')).toBe(true); expect(listInit.credentials).toBe('include'); mockFetch.mockResolvedValue(new Response('{"id":"a b"}', { status: 200 })); await deleteDashboardImage('a b'); const [delUrl, delInit] = mockFetch.mock.calls[1] as [string, RequestInit]; expect(String(delUrl).endsWith('/dashboard/images/a%20b')).toBe(true); expect(delInit.method).toBe('DELETE'); expect(delInit.credentials).toBe('include'); mockFetch.mockResolvedValue(new Response('', { status: 404 })); await expect(deleteDashboardImage('weg')).rejects.toThrow(); }); it('Test 5: dashboardImageSrc kodiert die Kennung im Proxy-Pfad', () => { expect(dashboardImageSrc('a b')).toBe('/api-proxy/dashboard/images/a%20b'); expect(dashboardImageSrc('img-1')).toBe('/api-proxy/dashboard/images/img-1'); }); });