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');
});
});