test(260928-ujj): rote Tests fuer Dashboard-Hintergrund in der Datenbank
- PATCH me/dashboard-background: Allowlist, UUID-Bildkennung, Mandantenbindung - getMe liefert dashboardBackground normalisiert - Web: Uebernahme der alten localStorage-Wahl, Hook liest aus dem Auth-Store Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { act, renderHook, waitFor } from '@testing-library/react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { type AuthUser, useAuthStore } from '@/lib/stores/auth-store';
|
||||
|
||||
// quick-260928-ujj: der Dashboard-Hintergrund steht pro Benutzer in der
|
||||
// Datenbank. Der Hook liest ihn aus dem Auth-Store (Sitzungsantwort) und
|
||||
// speichert ueber die Server-Aktion; eine alte localStorage-Wahl wird
|
||||
// einmalig uebernommen.
|
||||
|
||||
const updateDashboardBackgroundAction = vi.fn();
|
||||
|
||||
vi.mock('@/lib/auth-actions', () => ({
|
||||
updateDashboardBackgroundAction: (...args: unknown[]) => updateDashboardBackgroundAction(...args),
|
||||
}));
|
||||
|
||||
const LEGACY_KEY = 'tessera.dashboardBackground.u1';
|
||||
|
||||
function makeUser(overrides: Partial<AuthUser> = {}): AuthUser {
|
||||
return {
|
||||
id: 'u1',
|
||||
username: 'schalli',
|
||||
displayName: 'Schalli',
|
||||
role: 'USER',
|
||||
tenantId: 't1',
|
||||
accentColor: null,
|
||||
dashboardBackground: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
async function renderBackgroundHook() {
|
||||
const { useDashboardBackground } = await import('./dashboard-background');
|
||||
return renderHook(() => useDashboardBackground());
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
updateDashboardBackgroundAction.mockReset();
|
||||
updateDashboardBackgroundAction.mockResolvedValue({ success: true });
|
||||
useAuthStore.setState({ user: null });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
describe('useDashboardBackground (quick-260928-ujj)', () => {
|
||||
it('ohne angemeldeten Benutzer: kein Hintergrund, kein Speichern', async () => {
|
||||
const { result } = await renderBackgroundHook();
|
||||
|
||||
expect(result.current.background).toEqual({ kind: 'none' });
|
||||
expect(updateDashboardBackgroundAction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('liest die Wahl aus dem Auth-Store; null ergibt „kein Hintergrund“', async () => {
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: { kind: 'preset', id: 'dunes' } }) });
|
||||
const { result } = await renderBackgroundHook();
|
||||
expect(result.current.background).toEqual({ kind: 'preset', id: 'dunes' });
|
||||
|
||||
act(() => useAuthStore.setState({ user: makeUser({ dashboardBackground: null }) }));
|
||||
expect(result.current.background).toEqual({ kind: 'none' });
|
||||
});
|
||||
|
||||
it('choose() setzt den Store sofort und speichert ueber die Server-Aktion', async () => {
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: { kind: 'none' } }) });
|
||||
const { result } = await renderBackgroundHook();
|
||||
|
||||
act(() => {
|
||||
result.current.choose({ kind: 'preset', id: 'mosaic' });
|
||||
});
|
||||
|
||||
expect(useAuthStore.getState().user?.dashboardBackground).toEqual({ kind: 'preset', id: 'mosaic' });
|
||||
expect(result.current.background).toEqual({ kind: 'preset', id: 'mosaic' });
|
||||
expect(updateDashboardBackgroundAction).toHaveBeenCalledWith({ kind: 'preset', id: 'mosaic' });
|
||||
});
|
||||
|
||||
it.each([
|
||||
['Fehlerantwort', () => updateDashboardBackgroundAction.mockResolvedValue({ success: false, error: 'saveError' })],
|
||||
['Ausnahme', () => updateDashboardBackgroundAction.mockRejectedValue(new Error('offline'))],
|
||||
])('Speichern schlaegt fehl (%s): der vorige Wert wird zurueckgesetzt', async (_label, arrange) => {
|
||||
arrange();
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: { kind: 'preset', id: 'dunes' } }) });
|
||||
const { result } = await renderBackgroundHook();
|
||||
|
||||
act(() => {
|
||||
result.current.choose({ kind: 'preset', id: 'mist' });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.background).toEqual({ kind: 'preset', id: 'dunes' }));
|
||||
expect(useAuthStore.getState().user?.dashboardBackground).toEqual({ kind: 'preset', id: 'dunes' });
|
||||
});
|
||||
|
||||
it('Server-Wert null und alte localStorage-Wahl: wird genau einmal gespeichert, Schluessel entfernt', async () => {
|
||||
window.localStorage.setItem(LEGACY_KEY, JSON.stringify({ kind: 'preset', id: 'pebble' }));
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: null }) });
|
||||
|
||||
const { result, rerender } = await renderBackgroundHook();
|
||||
|
||||
await waitFor(() => expect(updateDashboardBackgroundAction).toHaveBeenCalledTimes(1));
|
||||
expect(updateDashboardBackgroundAction).toHaveBeenCalledWith({ kind: 'preset', id: 'pebble' });
|
||||
expect(result.current.background).toEqual({ kind: 'preset', id: 'pebble' });
|
||||
expect(window.localStorage.getItem(LEGACY_KEY)).toBeNull();
|
||||
|
||||
// erneutes Rendern und ein neues Benutzerobjekt desselben Benutzers loesen nichts mehr aus
|
||||
rerender();
|
||||
act(() => useAuthStore.setState({ user: makeUser({ dashboardBackground: null }) }));
|
||||
rerender();
|
||||
expect(updateDashboardBackgroundAction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Server-Wert gesetzt: keine Uebernahme, der alte Schluessel wird nur aufgeraeumt', async () => {
|
||||
window.localStorage.setItem(LEGACY_KEY, JSON.stringify({ kind: 'preset', id: 'pebble' }));
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: { kind: 'none' } }) });
|
||||
|
||||
const { result } = await renderBackgroundHook();
|
||||
|
||||
await waitFor(() => expect(window.localStorage.getItem(LEGACY_KEY)).toBeNull());
|
||||
expect(updateDashboardBackgroundAction).not.toHaveBeenCalled();
|
||||
expect(result.current.background).toEqual({ kind: 'none' });
|
||||
});
|
||||
|
||||
it('Server-Wert null ohne alte Wahl: nichts wird gespeichert', async () => {
|
||||
useAuthStore.setState({ user: makeUser({ dashboardBackground: null }) });
|
||||
|
||||
const { result } = await renderBackgroundHook();
|
||||
|
||||
expect(result.current.background).toEqual({ kind: 'none' });
|
||||
expect(updateDashboardBackgroundAction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user