feat(web): CalendarConfig im Einstellungsfeld, Changelog- und Handbuch-Eintrag
- Kalender-Zweig im Einstellungsfeld ersetzt den englischen Fliesstext durch CalendarConfig (Monatsansicht ein/aus, Anzahl Termine 0..10, Zeitraum 7/14/30/60/90) nach Muster ClockConfig; Speichern per partiellem updateWidgetConfig
- Paneltest um drei Kalender-Tests erweitert (7/7 gruen), next-intl-Mock interpoliert jetzt {platzhalter}
- CHANGELOG.md: zweiter Eintrag unter Unveroeffentlicht/Geaendert; Anwenderhandbuch: Widget-Tabellenzeile und Dashboard-Widgets-Absatz ergaenzt
- Gesamtlauf: 51 Testdateien / 332 Tests gruen, Type-Check Exit 0 (quick-260916-htc)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,12 @@ vi.mock('next-intl', async () => {
|
||||
| string
|
||||
| undefined;
|
||||
return {
|
||||
useTranslations: (ns?: string) => (key: string) => lookup(ns ? `${ns}.${key}` : key) ?? key,
|
||||
useTranslations:
|
||||
(ns?: string) =>
|
||||
(key: string, values?: Record<string, unknown>) => {
|
||||
const raw = lookup(ns ? `${ns}.${key}` : key) ?? key;
|
||||
return values ? raw.replace(/\{(\w+)\}/g, (_: string, n: string) => String(values[n] ?? '')) : raw;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -36,6 +41,7 @@ vi.mock('@/components/settings/search-provider-form', () => ({
|
||||
}));
|
||||
|
||||
const clockTexts = (de as { widgets: { clock: Record<string, string> } }).widgets.clock;
|
||||
const cal = (de as { widgets: { calendar: Record<string, string> } }).widgets.calendar;
|
||||
|
||||
const WIDGET = { id: 'c1', widgetType: 'clock', config: { timezone: 'Europe/Berlin', timeFontSizePt: 24 } };
|
||||
|
||||
@@ -105,3 +111,74 @@ describe('WidgetSettingsPanel — Schriftgroesse der Uhrzeit (quick-260916-bwo)'
|
||||
expect(screen.getByRole('alert')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('WidgetSettingsPanel — Kalender-Einstellungen (quick-260916-htc)', () => {
|
||||
function renderCalendarExpanded(config: Record<string, unknown> = {}) {
|
||||
const onWidgetUpdate = vi.fn();
|
||||
const widget = { id: 'k1', widgetType: 'calendar', config };
|
||||
render(<WidgetSettingsPanel widgets={[widget]} onWidgetUpdate={onWidgetUpdate} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /Kalender #1/ }));
|
||||
return { onWidgetUpdate };
|
||||
}
|
||||
|
||||
it('Test 5: Vorbelegung aus der Konfiguration, Optionslisten und uebersetzte Link-Zeile', () => {
|
||||
renderCalendarExpanded();
|
||||
|
||||
const showMonth = screen.getByLabelText(cal.configShowMonth) as HTMLInputElement;
|
||||
expect(showMonth.checked).toBe(true);
|
||||
|
||||
const maxEventsSelect = screen.getByLabelText(cal.configMaxEvents) as HTMLSelectElement;
|
||||
expect(maxEventsSelect.value).toBe('3');
|
||||
const maxEventsOptionTexts = Array.from(maxEventsSelect.options).map((o) => o.textContent);
|
||||
expect(maxEventsOptionTexts).toEqual([
|
||||
cal.configMaxEventsNone,
|
||||
cal.configMaxEventsOne,
|
||||
...Array.from({ length: 9 }, (_, i) => cal.configMaxEventsMany.replace('{count}', String(i + 2))),
|
||||
]);
|
||||
|
||||
const lookaheadSelect = screen.getByLabelText(cal.configLookahead) as HTMLSelectElement;
|
||||
expect(lookaheadSelect.value).toBe('30');
|
||||
const lookaheadOptionTexts = Array.from(lookaheadSelect.options).map((o) => o.textContent);
|
||||
expect(lookaheadOptionTexts).toEqual(
|
||||
[7, 14, 30, 60, 90].map((days) => cal.configLookaheadOption.replace('{days}', String(days))),
|
||||
);
|
||||
|
||||
expect(screen.getByText(cal.configSourcesHint)).toBeInTheDocument();
|
||||
const link = screen.getByRole('link', { name: cal.configSourcesLink });
|
||||
expect(link).toHaveAttribute('href', '/settings/dashboard/calendar');
|
||||
|
||||
expect(screen.queryByText(/managed under/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Test 6: jede Aenderung ruft updateWidgetConfig/onWidgetUpdate nur mit dem geaenderten Feld auf', async () => {
|
||||
const { onWidgetUpdate } = renderCalendarExpanded();
|
||||
|
||||
fireEvent.change(screen.getByLabelText(cal.configMaxEvents), { target: { value: '5' } });
|
||||
await vi.waitFor(() => expect(onWidgetUpdate).toHaveBeenCalledWith('k1', { maxEvents: 5 }));
|
||||
expect(updateWidgetConfig).toHaveBeenCalledWith('k1', { maxEvents: 5 });
|
||||
|
||||
fireEvent.change(screen.getByLabelText(cal.configLookahead), { target: { value: '14' } });
|
||||
await vi.waitFor(() => expect(onWidgetUpdate).toHaveBeenCalledWith('k1', { lookaheadDays: 14 }));
|
||||
expect(updateWidgetConfig).toHaveBeenCalledWith('k1', { lookaheadDays: 14 });
|
||||
|
||||
fireEvent.click(screen.getByLabelText(cal.configShowMonth));
|
||||
await vi.waitFor(() => expect(onWidgetUpdate).toHaveBeenCalledWith('k1', { showMonth: false }));
|
||||
expect(updateWidgetConfig).toHaveBeenCalledWith('k1', { showMonth: false });
|
||||
|
||||
expect(updateWidgetConfig).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('Test 7: bestehende Werte werden angezeigt, ungueltige Werte geklemmt', () => {
|
||||
renderCalendarExpanded({ showMonth: false, maxEvents: 7, lookaheadDays: 60 });
|
||||
|
||||
expect((screen.getByLabelText(cal.configShowMonth) as HTMLInputElement).checked).toBe(false);
|
||||
expect((screen.getByLabelText(cal.configMaxEvents) as HTMLSelectElement).value).toBe('7');
|
||||
expect((screen.getByLabelText(cal.configLookahead) as HTMLSelectElement).value).toBe('60');
|
||||
|
||||
cleanup();
|
||||
|
||||
renderCalendarExpanded({ maxEvents: 42, lookaheadDays: 45 });
|
||||
expect((screen.getByLabelText(cal.configMaxEvents) as HTMLSelectElement).value).toBe('10');
|
||||
expect((screen.getByLabelText(cal.configLookahead) as HTMLSelectElement).value).toBe('30');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user