2d8efe1a97
- 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
157 lines
5.5 KiB
TypeScript
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('');
|
|
});
|
|
});
|