Files
tessera-ctl/apps/web/src/components/dashboard/widgets/clock-widget.test.tsx
T
schalli 2d8efe1a97 feat(quick-260916-bwo): Widget-Inhalt skaliert per Container-Queries (Uhr, Stoppuhr, Rechner), Punktgroesse der Uhrzeit einstellbar
- widget-wrapper.tsx: Rumpf ist Groessen-Container (@container-size) fuer cqw/cqh
- clock-font-size.ts (neu): Grenzen 8..200, resolveClockTimeFontSizePt nur fuer endliche Zahlen (T-BWO-01)
- clock-widget.tsx: Container-Query-Klassen mit clamp(), data-font-mode auto/fixed, Inline-pt nur bei Zahl, keine vw-Formel mehr, p-1
- stopwatch-widget.tsx: Anzeige per Container-Query, p-1.5; calculator-widget.tsx: Anzeige und Tasten skalieren, Tasten h-full min-h-7, p-1
- widget-settings-panel.tsx: Zahlenfeld Schriftgroesse der Uhrzeit (Blur/Enter, leer = automatisch, Fehlermeldung ausserhalb 8..200)
- de.json/en.json: widgets.clock.fontSizeLabel/fontSizeAuto/fontSizeHint/fontSizeInvalid (Sie-Form, Waechter gruen)
- Tests: Uhr +4, Stoppuhr +1, Rechner +1, widget-settings-panel.test.tsx neu (4)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
2026-09-16 09:12:02 +02:00

157 lines
5.5 KiB
TypeScript

import { cleanup, render, screen } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
CLOCK_FONT_SIZE_MAX_PT,
CLOCK_FONT_SIZE_MIN_PT,
resolveClockTimeFontSizePt,
} from './clock-font-size';
// Mock next-intl
vi.mock('next-intl', () => ({
useTranslations: (ns: string) => (key: string) => {
const map: Record<string, Record<string, string>> = {
widgets: {
'clock.name': 'Clock',
'clock.description': 'Shows the current time',
'clock.dateHint': 'Show date',
},
};
return map[ns]?.[key] ?? key;
},
}));
afterEach(() => {
cleanup();
vi.useRealTimers();
});
describe('ClockWidget', () => {
it('renders a time string with timezone config', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-06-24T12:30:00Z'));
const { ClockWidget } = await import('./clock-widget');
render(
<ClockWidget
instanceId="clock-1"
config={{ timezone: 'Europe/Berlin', showDate: true }}
isEditMode={false}
/>,
);
// Should render a time element
const timeEl = screen.getByRole('time');
expect(timeEl).toBeInTheDocument();
// Time text should be non-empty
expect(timeEl.textContent).toBeTruthy();
// Should render a date element when showDate is true
const dateEl = screen.getByTestId('clock-date');
expect(dateEl).toBeInTheDocument();
expect(dateEl.textContent).toBeTruthy();
vi.useRealTimers();
});
it('does not render date element when showDate is false', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-06-24T12:30:00Z'));
const { ClockWidget } = await import('./clock-widget');
render(
<ClockWidget
instanceId="clock-2"
config={{ timezone: 'Europe/Berlin', showDate: false }}
isEditMode={false}
/>,
);
expect(screen.queryByTestId('clock-date')).not.toBeInTheDocument();
vi.useRealTimers();
});
// --- quick-260916-bwo: Skalierung per Container-Query, feste Punktgroesse ---
// jsdom verwirft clamp()/min() in style.fontSize (gemessen) — deshalb liegt die
// automatische Groesse in einer Tailwind-KLASSE und nur die feste Punktgroesse
// im Inline-Style. Die Tests lesen fuer 'auto' die Klasse, fuer 'fixed' style.
it('Test 3 (quick-260916-bwo): resolveClockTimeFontSizePt laesst nur endliche Zahlen 8..200 durch (T-BWO-01)', () => {
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 36 })).toBe(36);
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 8 })).toBe(8);
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 200 })).toBe(200);
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 36.5 })).toBe(36.5);
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 7 })).toBeNull();
expect(resolveClockTimeFontSizePt({ timeFontSizePt: 201 })).toBeNull();
expect(resolveClockTimeFontSizePt({ timeFontSizePt: '36' })).toBeNull();
expect(resolveClockTimeFontSizePt({ timeFontSizePt: Number.NaN })).toBeNull();
expect(resolveClockTimeFontSizePt({ timeFontSizePt: Number.POSITIVE_INFINITY })).toBeNull();
expect(resolveClockTimeFontSizePt({ timeFontSizePt: null })).toBeNull();
expect(resolveClockTimeFontSizePt({})).toBeNull();
expect(CLOCK_FONT_SIZE_MIN_PT).toBe(8);
expect(CLOCK_FONT_SIZE_MAX_PT).toBe(200);
});
it('Test 4 (quick-260916-bwo): feste Punktgroesse -> Inline-Style 36pt, Datum 14.4pt, data-font-mode fixed', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-06-24T12:30:00Z'));
const { ClockWidget } = await import('./clock-widget');
render(
<ClockWidget
instanceId="clock-3"
config={{ timezone: 'Europe/Berlin', showDate: true, timeFontSizePt: 36 }}
isEditMode={false}
/>,
);
const timeEl = screen.getByRole('time');
expect(timeEl.style.fontSize).toBe('36pt');
expect(timeEl.getAttribute('data-font-mode')).toBe('fixed');
expect(screen.getByTestId('clock-date').style.fontSize).toBe('14.4pt');
});
it('Test 5 (quick-260916-bwo): ohne Punktgroesse -> kein Inline-Style, data-font-mode auto, Container-Query-Klassen', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-06-24T12:30:00Z'));
const { ClockWidget } = await import('./clock-widget');
render(
<ClockWidget
instanceId="clock-4"
config={{ timezone: 'Europe/Berlin', showDate: true }}
isEditMode={false}
/>,
);
const timeEl = screen.getByRole('time');
expect(timeEl.style.fontSize).toBe('');
expect(timeEl.getAttribute('data-font-mode')).toBe('auto');
expect(timeEl.className).toMatch(/cqw/);
expect(timeEl.className).toMatch(/cqh/);
const dateEl = screen.getByTestId('clock-date');
expect(dateEl.className).toMatch(/cq[wh]/);
expect(dateEl.style.fontSize).toBe('');
});
it('Test 6 (quick-260916-bwo): Zeichenketten-Wert wird ignoriert — auto, kein Inline-Style (T-BWO-01)', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-06-24T12:30:00Z'));
const { ClockWidget } = await import('./clock-widget');
render(
<ClockWidget
instanceId="clock-5"
config={{ timezone: 'Europe/Berlin', showDate: true, timeFontSizePt: '36' }}
isEditMode={false}
/>,
);
const timeEl = screen.getByRole('time');
expect(timeEl.style.fontSize).toBe('');
expect(timeEl.getAttribute('data-font-mode')).toBe('auto');
expect(timeEl.className).toMatch(/cqw/);
expect(screen.getByTestId('clock-date').style.fontSize).toBe('');
});
});