import { cleanup, render, screen } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { BRAND_OLIVE, BRAND_OLIVE_FILL, BRAND_YELLOW } from './brand'; import { TesseraLogo } from './tessera-logo'; import de from '@/messages/de.json'; import en from '@/messages/en.json'; vi.mock('next-intl', () => ({ useTranslations: (ns: string) => (key: string) => { const map: Record> = { common: { appName: 'Tessera', 'brand.logoAlt': 'Tessera Logo', }, }; return map[ns]?.[key] ?? key; }, })); afterEach(() => { cleanup(); }); function flattenKeys(obj: unknown, prefix = ''): string[] { if (obj === null || typeof obj !== 'object') { return [prefix]; } return Object.entries(obj as Record).flatMap(([key, value]) => flattenKeys(value, prefix ? `${prefix}.${key}` : key), ); } describe('TesseraLogo', () => { it('variant "mark" renders an img-role element with the translated accessible name and no visible wordmark', () => { render(); const mark = screen.getByRole('img', { name: 'Tessera Logo' }); expect(mark).toBeInTheDocument(); expect(screen.queryByText('Tessera')).not.toBeInTheDocument(); }); it('variant "horizontal" renders the img-role mark and the visible wordmark text', () => { render(); expect(screen.getByRole('img', { name: 'Tessera Logo' })).toBeInTheDocument(); expect(screen.getByText('Tessera')).toBeInTheDocument(); }); it('renders no tagline unless one is passed', () => { render(); // Hand-geschriebener Erwartungstext, bewusst NICHT aus derselben Quelle // gebildet, aus der die Komponente ihn zoege. expect( screen.queryByText('Modulare Workflow-Plattform fuer Ihr Unternehmen'), ).not.toBeInTheDocument(); }); it('places mark, wordmark and tagline in that document order when a tagline is passed', () => { render( , ); const mark = screen.getByRole('img', { name: 'Tessera Logo' }); const wordmark = screen.getByText('Tessera'); const tagline = screen.getByText( 'Modulare Workflow-Plattform fuer Ihr Unternehmen', ); expect(mark).toBeInTheDocument(); // Node.compareDocumentPosition: DOCUMENT_POSITION_FOLLOWING === 4. // Prueft die tatsaechliche Reihenfolge im Baum — Bildmarke vor Schriftzug, // Schriftzug vor Untertitel — statt nur deren Vorhandensein. expect(mark.compareDocumentPosition(wordmark) & 4).toBe(4); expect(wordmark.compareDocumentPosition(tagline) & 4).toBe(4); }); it('enables the dark-mode plate outline class by default', () => { render(); const mark = screen.getByRole('img', { name: 'Tessera Logo' }); const plate = mark.querySelector('rect'); expect(plate?.getAttribute('class')).toContain('dark:stroke-white/25'); }); it('omits the dark-mode plate outline class when plateOutline is false', () => { render(); const mark = screen.getByRole('img', { name: 'Tessera Logo' }); const plate = mark.querySelector('rect'); expect(plate?.getAttribute('class')).not.toContain('dark:stroke-white/25'); }); it('renders exactly five tiles; the rotated one takes the accent token, the other four the derived olive tone with the fixed olive as fallback', () => { render(); const mark = screen.getByRole('img', { name: 'Tessera Logo' }); const tiles = Array.from(mark.querySelectorAll('g rect')) as SVGRectElement[]; expect(tiles).toHaveLength(5); const accentTiles = tiles.filter((tile) => tile.style.fill === `var(--primary, ${BRAND_YELLOW})`); expect(accentTiles).toHaveLength(1); expect(accentTiles[0].hasAttribute('transform')).toBe(true); const rotatedTiles = tiles.filter((tile) => tile.hasAttribute('transform')); expect(rotatedTiles).toHaveLength(1); const presentationYellowTiles = tiles.filter((tile) => tile.getAttribute('fill') === BRAND_YELLOW); expect(presentationYellowTiles).toHaveLength(0); // BRAND_OLIVE_FILL haengt selbst am --primary-Token — Zusicherung, dass // die vier Kacheln wirklich daran haengen und nicht an einer festen Farbe. expect(BRAND_OLIVE_FILL).toContain('var(--primary'); const derivedOliveTiles = tiles.filter((tile) => tile.style.fill === BRAND_OLIVE_FILL); expect(derivedOliveTiles).toHaveLength(4); for (const tile of derivedOliveTiles) { expect(tile.getAttribute('fill')).toBe(BRAND_OLIVE); expect(tile.hasAttribute('transform')).toBe(false); } }); }); describe('common.brand i18n namespace — de/en key parity', () => { it('both locales define common.brand.logoAlt', () => { expect(de.common).toHaveProperty('brand.logoAlt'); expect(en.common).toHaveProperty('brand.logoAlt'); }); it('has an identical (recursively-flattened) key set under common.brand in de and en', () => { const deKeys = flattenKeys((de.common as { brand: unknown }).brand).sort(); const enKeys = flattenKeys((en.common as { brand: unknown }).brand).sort(); expect(deKeys).toEqual(enKeys); }); });