import { cleanup, render, screen, waitFor } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; /** * AppVersionBadge.test — die Versionszeile unten in der Seitenleiste * (quick-260914-ku1). Vorlage: sidebar.test.tsx (next-intl-Mock, cleanup, * dynamischer Import nach dem Setzen der Mocks). Seit quick-260916-dcz ist die * Zeile ein Link zur Seite "Was ist neu" — deshalb der `next/link`-Mock, der * href, className, title, aria-label und data-testid durchreicht (Tests 5/6). */ vi.mock('next/link', () => ({ default: ({ children, href, className, title, 'aria-label': ariaLabel, 'data-testid': testId, }: { children: React.ReactNode; href: string; className?: string; title?: string; 'aria-label'?: string; 'data-testid'?: string; }) => ( {children} ), })); vi.mock('next-intl', () => ({ useTranslations: (ns: string) => (key: string) => { const map: Record> = { sidebar: { 'channel.beta': 'Beta', 'channel.live': 'Live', 'channel.dev': 'Entwicklung', whatsNew: 'Was ist neu', }, }; return map[ns]?.[key] ?? key; }, })); let mockAppVersion = { version: 'v1.2.3', channel: 'beta' as 'beta' | 'live' | 'dev', commit: 'abc1234' }; const mockLoad = vi.fn(); vi.mock('@/lib/app-version', () => ({ get appVersion() { return mockAppVersion; }, loadApiVersion: () => mockLoad(), })); afterEach(() => { cleanup(); vi.restoreAllMocks(); mockLoad.mockReset(); mockAppVersion = { version: 'v1.2.3', channel: 'beta', commit: 'abc1234' }; }); async function importBadge() { const mod = await import('./app-version-badge'); return mod.AppVersionBadge; } describe('AppVersionBadge (quick-260914-ku1)', () => { it('Test 1 (Zeile): zeigt Version und uebersetzten Kanal', async () => { mockLoad.mockResolvedValue(null); const AppVersionBadge = await importBadge(); render(); expect(screen.getByTestId('app-version')).toHaveTextContent('v1.2.3 · Beta'); }); it('Test 2 (Tooltip mit API): title nennt Commit und API-Version samt Kanal', async () => { mockLoad.mockResolvedValue({ name: 'tessera', version: 'v1.2.3', channel: 'beta', commit: 'abc1234', buildTime: '', }); const AppVersionBadge = await importBadge(); render(); await waitFor(() => { const title = screen.getByTestId('app-version').getAttribute('title') ?? ''; expect(title).toContain('Commit abc1234'); expect(title).toContain('API v1.2.3 (beta)'); }); }); it('Test 3 (Tooltip ohne API): title nennt den Commit, aber keinen API-Teil', async () => { mockLoad.mockResolvedValue(null); const AppVersionBadge = await importBadge(); render(); await waitFor(() => { expect(mockLoad).toHaveBeenCalled(); }); const title = screen.getByTestId('app-version').getAttribute('title') ?? ''; expect(title).toContain('Commit abc1234'); expect(title).not.toContain('API'); }); it('Test 4 (Kanal dev, kein Commit): zeigt dev · Entwicklung und hat kein title-Attribut', async () => { mockAppVersion = { version: 'dev', channel: 'dev', commit: '' }; mockLoad.mockResolvedValue(null); const AppVersionBadge = await importBadge(); render(); await waitFor(() => { expect(mockLoad).toHaveBeenCalled(); }); const el = screen.getByTestId('app-version'); expect(el).toHaveTextContent('dev · Entwicklung'); expect(el.hasAttribute('title')).toBe(false); }); it('Test 5 (Link): die Versionszeile ist ein Link auf /changelog', async () => { mockLoad.mockResolvedValue(null); const AppVersionBadge = await importBadge(); render(); const el = screen.getByTestId('app-version'); expect(el.tagName).toBe('A'); expect(el).toHaveAttribute('href', '/changelog'); }); it('Test 6 (aria-label): der Link traegt den Namen "Was ist neu"', async () => { mockLoad.mockResolvedValue(null); const AppVersionBadge = await importBadge(); render(); expect(screen.getByTestId('app-version')).toHaveAttribute('aria-label', 'Was ist neu'); }); });