import { describe, expect, it, vi } from 'vitest' import { renderToStaticMarkup } from 'react-dom/server' import type { ImageLoaderProps } from 'next/image' import type { Media } from '~/data/schema' vi.mock('next-intl', () => ({ useTranslations: () => (key: string) => key, })) vi.mock('next/image', () => ({ default: ({ loader, src, alt, sizes }: { loader?: (args: ImageLoaderProps) => string src: string alt: string sizes?: string }) => {alt}, })) const { blockRegistry } = await import('~/components/blocks/registry') const base: Media = { id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00001', projectId: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00009', kind: 'image', originalFilename: 'schema.png', path: 'projekt/bild/original.png', mime: 'image/png', width: 2000, height: 1125, byteSize: 12345, variants: [ { width: 480, format: 'webp', path: 'projekt/bild/w480.webp' }, { width: 960, format: 'webp', path: 'projekt/bild/w960.webp' }, ], variantError: null, alt: 'Ein Schema', caption: 'Bildunterschrift', uploadedBy: null, createdAt: new Date('2026-07-30T07:00:00Z'), } function media(...items: Media[]): Map { return new Map(items.map(item => [item.id, item])) } function render(type: string, data: Record, items: Map): string { const Component = blockRegistry[type] if (!Component) { throw new Error(`kein Block für ${type}`) } return renderToStaticMarkup() } describe('Blöcke ohne Medium', () => { it('bleibt bei jedem Typ ohne Daten leer statt kaputt', () => { for (const type of Object.keys(blockRegistry)) { expect(render(type, {}, new Map()), type).toBe('') } }) it('verliert kein Bild, wenn die Kennung ins Leere zeigt', () => { const missing = { mediaId: base.id, mediaIds: [base.id], beforeMediaId: base.id, afterMediaId: base.id } for (const type of ['image', 'gallery', 'before_after', 'video']) { expect(render(type, missing, new Map()), type).toBe('') } }) it('zeigt den Videoverweis auch ohne Medium', () => { const markup = render('video', { url: 'https://example.test/film' }, new Map()) expect(markup).toContain('https://example.test/film') }) }) describe('Blöcke mit Medium', () => { it('holt die passende Fassung über den Medienweg', () => { const markup = render('image', { mediaId: base.id }, media(base)) expect(markup).toContain('/api/v1/media/file/projekt/bild/w960.webp') expect(markup).toContain('Ein Schema') }) it('nimmt das Original, wenn keine Fassung erzeugt wurde', () => { const original: Media = { ...base, variants: [] } const markup = render('image', { mediaId: original.id }, media(original)) expect(markup).toContain('/api/v1/media/file/projekt/bild/original.png') }) it('stellt die Galerie mit Vorschaubildern auf', () => { const second: Media = { ...base, id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00002', caption: null } const markup = render('gallery', { mediaIds: [base.id, second.id] }, media(base, second)) expect(markup.match(/ { const after: Media = { ...base, id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00003' } const markup = render( 'before_after', { beforeMediaId: base.id, afterMediaId: after.id }, media(base, after), ) expect(markup).toContain('type="range"') expect(markup).toContain('clip-path') }) it('zeigt nur eine Seite, wenn das Gegenstück fehlt', () => { const markup = render('before_after', { beforeMediaId: base.id }, media(base)) expect(markup).not.toContain('type="range"') expect(markup).toContain('before') }) it('spielt ein Video als Video aus', () => { const film: Media = { ...base, kind: 'video', mime: 'video/mp4', variants: [] } const markup = render('video', { mediaId: film.id }, media(film)) expect(markup).toContain('