import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import ReaderDraftsModule from './ReaderDraftsModule.svelte'; import type { components } from '$lib/generated/api'; type GeschichteSummary = components['schemas']['GeschichteSummary']; afterEach(() => { cleanup(); }); const draft1: GeschichteSummary = { id: 'g1', title: 'Mein erster Entwurf', status: 'DRAFT', type: 'STORY', updatedAt: '2025-01-02T00:00:00Z' }; const draft2: GeschichteSummary = { id: 'g2', title: 'Zweiter Entwurf', status: 'DRAFT', type: 'STORY', createdAt: '2025-02-01T00:00:00Z', updatedAt: '2025-02-01T00:00:00Z' }; describe('ReaderDraftsModule', () => { it('renders a link to /geschichten/{id}/edit for each draft', async () => { render(ReaderDraftsModule, { drafts: [draft1, draft2] }); const link1 = page.getByRole('link', { name: /Mein erster Entwurf/ }); await expect.element(link1).toHaveAttribute('href', '/geschichten/g1/edit'); const link2 = page.getByRole('link', { name: /Zweiter Entwurf/ }); await expect.element(link2).toHaveAttribute('href', '/geschichten/g2/edit'); }); it('shows heading as h3 (not h2)', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const h3 = page.getByRole('heading', { level: 3 }); await expect.element(h3).toBeInTheDocument(); const h2 = page.getByRole('heading', { level: 2 }); await expect.element(h2).not.toBeInTheDocument(); }); it('shows empty state when drafts is empty', async () => { render(ReaderDraftsModule, { drafts: [] }); const emptyText = page.getByText(/Keine Entwürfe/i); await expect.element(emptyText).toBeInTheDocument(); }); it('does not show empty state when drafts are present', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const emptyText = page.getByText(/Keine Entwürfe/i); await expect.element(emptyText).not.toBeInTheDocument(); }); it('card wrapper has mint left-border classes', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const h3 = page.getByRole('heading', { level: 3 }); const card = ((await h3.element()) as HTMLElement).closest('div[class]'); const rootCard = card?.parentElement; const cls = rootCard?.className ?? ''; expect(cls).toMatch(/border-l-\[3px\]/); expect(cls).toMatch(/border-l-brand-mint/); }); it('draft-row link has min-h-[44px] touch target', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const link = page.getByRole('link', { name: /Mein erster Entwurf/ }); const cls = ((await link.element()) as HTMLElement).className; expect(cls).toMatch(/min-h-\[44px\]/); }); it('draft title has text-ink class', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const link = page.getByRole('link', { name: /Mein erster Entwurf/ }); const el = (await link.element()) as HTMLElement; const titleEl = el.querySelector('[class*="text-ink"]'); expect(titleEl).not.toBeNull(); expect(titleEl?.textContent?.trim()).toBe('Mein erster Entwurf'); }); it('draft meta contains "Entwurf" text', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const link = page.getByRole('link', { name: /Mein erster Entwurf/ }); const el = (await link.element()) as HTMLElement; expect(el.textContent).toMatch(/Entwurf/); }); it('chevron SVG is present in each draft row', async () => { render(ReaderDraftsModule, { drafts: [draft1] }); const link = page.getByRole('link', { name: /Mein erster Entwurf/ }); const el = (await link.element()) as HTMLElement; const svg = el.querySelector('svg'); expect(svg).not.toBeNull(); }); });