import { afterEach, describe, expect, it, vi } from 'vitest'; import { isFavorite, readWorkspaceState, recordRecent, removeSavedView, saveCurrentView, toggleFavorite, WORKSPACE_EVENT, } from '../../src/operatorWorkspace'; afterEach(() => { window.localStorage.clear(); vi.restoreAllMocks(); }); describe('operator workspace preferences', () => { it('toggles favorites without duplicating the same path', () => { expect(toggleFavorite('Cache pool', '/pools/cache?range=24h')).toBe(true); expect(isFavorite('/pools/cache?range=24h')).toBe(true); expect(readWorkspaceState().favorites).toHaveLength(1); expect(toggleFavorite('Cache pool', '/pools/cache?range=24h')).toBe(false); expect(isFavorite('/pools/cache?range=24h')).toBe(false); expect(readWorkspaceState().favorites).toHaveLength(0); }); it('persists a saved view and removes it by exact route context', () => { saveCurrentView('Degraded services', '/services?state=degraded&range=24h'); expect(readWorkspaceState().views).toEqual([ expect.objectContaining({ label: 'Degraded services', path: '/services?state=degraded&range=24h', kind: 'view' }), ]); removeSavedView('/services?state=degraded&range=24h'); expect(readWorkspaceState().views).toHaveLength(0); }); it('keeps recent routes bounded, unique and excludes the 404 surface', () => { recordRecent('Missing', '/404'); for (let index = 0; index < 15; index += 1) recordRecent('Item ' + index, '/inventory/' + index); recordRecent('Item 14 updated', '/inventory/14'); const recent = readWorkspaceState().recent; expect(recent).toHaveLength(12); expect(recent[0]).toMatchObject({ label: 'Item 14 updated', path: '/inventory/14', kind: 'recent' }); expect(recent.filter((item) => item.path === '/inventory/14')).toHaveLength(1); expect(recent.some((item) => item.path === '/404')).toBe(false); }); it('fails closed on malformed storage and emits a workspace change event on writes', () => { window.localStorage.setItem('pulse.operator.workspace.v1', '{bad json'); expect(readWorkspaceState()).toEqual({ favorites: [], views: [], recent: [] }); const listener = vi.fn(); window.addEventListener(WORKSPACE_EVENT, listener); saveCurrentView('Overview', '/'); window.removeEventListener(WORKSPACE_EVENT, listener); expect(listener).toHaveBeenCalledTimes(1); }); });