ba06db98c5
- CHANGELOG.md (Wurzel): Unveroeffentlicht (bwo + dyv + diese Seite, 8 Punkte) und 1.0.0 – 2026-09-15 (11 Punkte aus den Handbuechern), Alltagssprache, echte Umlaute - next.config.ts liest CHANGELOG.md zur Bauzeit nach env.TESSERA_CHANGELOG_MD; .dockerignore-Ausnahme !CHANGELOG.md und COPY-Zeile im Web-Dockerfile - lib/changelog.ts: filterChangelogForChannel (live ohne Unveroeffentlicht, beta/dev mit "Noch nicht freigegeben (Beta)", leerer Abschnitt ausgeblendet), 10 Tests - Server-Seite /changelog (MDEditor.Markdown + rehype-sanitize, Hinweis auf Beta, Leer-Text), 3 Tests; Versionszeile ist Link mit aria-label, 2 Tests - de/en: sidebar.whatsNew und Namensraum changelog; Web-Suite 49/309, tsc 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
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;
|
|
}) => (
|
|
<a href={href} className={className} title={title} aria-label={ariaLabel} data-testid={testId}>
|
|
{children}
|
|
</a>
|
|
),
|
|
}));
|
|
|
|
vi.mock('next-intl', () => ({
|
|
useTranslations: (ns: string) => (key: string) => {
|
|
const map: Record<string, Record<string, string>> = {
|
|
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(<AppVersionBadge />);
|
|
|
|
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(<AppVersionBadge />);
|
|
|
|
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(<AppVersionBadge />);
|
|
|
|
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(<AppVersionBadge />);
|
|
|
|
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(<AppVersionBadge />);
|
|
|
|
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(<AppVersionBadge />);
|
|
|
|
expect(screen.getByTestId('app-version')).toHaveAttribute('aria-label', 'Was ist neu');
|
|
});
|
|
});
|