import { describe, it, expect, beforeEach } from 'vitest'; import { configStore, ConfigState, Payload, serializeConfig, deserializeConfig } from '@/store/useConfigStore'; describe('useConfigStore (vanilla)', () => { beforeEach(() => { configStore.getState().reset(); }); describe('Initial State', () => { it('should have correct default values', () => { const state = configStore.getState(); expect(state.activeColors).toEqual({ primary: '#96a2b6', secondary: '#1e293b', accent: '#f59e0b', }); expect(state.activePersonaAttire).toBe('none'); expect(state.activeBody).toBe('basic'); expect(state.activePayloads).toEqual([]); expect(state.isHydrated).toBe(false); }); }); describe('setBody', () => { it('should update active body to edu', () => { configStore.getState().setBody('edu'); expect(configStore.getState().activeBody).toBe('edu'); }); it('should update active body back to basic', () => { configStore.getState().setBody('edu'); configStore.getState().setBody('basic'); expect(configStore.getState().activeBody).toBe('basic'); }); }); describe('setColors', () => { it('should update primary color', () => { configStore.getState().setColors({ primary: '#ff0000' }); const state = configStore.getState(); expect(state.activeColors.primary).toBe('#ff0000'); expect(state.activeColors.secondary).toBe('#1e293b'); expect(state.activeColors.accent).toBe('#f59e0b'); }); it('should update multiple colors at once', () => { configStore.getState().setColors({ primary: '#ff0000', secondary: '#00ff00', accent: '#0000ff', }); expect(configStore.getState().activeColors).toEqual({ primary: '#ff0000', secondary: '#00ff00', accent: '#0000ff', }); }); }); describe('setPersonaAttire', () => { it('should update persona attire', () => { configStore.getState().setPersonaAttire('Emarati Kandura'); expect(configStore.getState().activePersonaAttire).toBe('Emarati Kandura'); }); }); describe('addPayload', () => { it('should add a new payload', () => { const payload: Payload = { id: 'cam1', type: 'camera', position: 'head' }; configStore.getState().addPayload(payload); expect(configStore.getState().activePayloads).toHaveLength(1); expect(configStore.getState().activePayloads[0]).toEqual(payload); }); it('should not add duplicate payload by id', () => { const payload: Payload = { id: 'cam1', type: 'camera', position: 'head' }; configStore.getState().addPayload(payload); configStore.getState().addPayload(payload); expect(configStore.getState().activePayloads).toHaveLength(1); }); }); describe('removePayload', () => { it('should remove a payload by id', () => { const payload: Payload = { id: 'cam1', type: 'camera', position: 'head' }; configStore.getState().addPayload(payload); expect(configStore.getState().activePayloads).toHaveLength(1); configStore.getState().removePayload('cam1'); expect(configStore.getState().activePayloads).toHaveLength(0); }); }); describe('updatePayload', () => { it('should update an existing payload', () => { const payload: Payload = { id: 'cam1', type: 'camera', position: 'head' }; configStore.getState().addPayload(payload); configStore.getState().updatePayload('cam1', { position: 'chest' }); expect(configStore.getState().activePayloads[0].position).toBe('chest'); }); }); describe('clearPayloads', () => { it('should remove all payloads', () => { configStore.getState().addPayload({ id: 'cam1', type: 'camera', position: 'head' }); configStore.getState().addPayload({ id: 'cam2', type: 'camera', position: 'chest' }); expect(configStore.getState().activePayloads).toHaveLength(2); configStore.getState().clearPayloads(); expect(configStore.getState().activePayloads).toHaveLength(0); }); }); describe('reset', () => { it('should reset all state to defaults', () => { configStore.getState().setColors({ primary: '#ff0000' }); configStore.getState().setPersonaAttire('Industrial Vest'); configStore.getState().setBody('edu'); configStore.getState().addPayload({ id: 'cam1', type: 'camera', position: 'head' }); configStore.getState().setHydrated(true); configStore.getState().reset(); const state = configStore.getState(); expect(state.activeColors.primary).toBe('#96a2b6'); expect(state.activePersonaAttire).toBe('none'); expect(state.activeBody).toBe('basic'); expect(state.activePayloads).toEqual([]); expect(state.isHydrated).toBe(false); }); }); describe('hydrate', () => { it('should hydrate state from partial config', () => { configStore.getState().hydrate({ activeColors: { primary: '#ff0000', secondary: '#00ff00', accent: '#0000ff' }, activePersonaAttire: 'Emarati Kandura', }); const state = configStore.getState(); expect(state.activeColors.primary).toBe('#ff0000'); expect(state.activePersonaAttire).toBe('Emarati Kandura'); expect(state.isHydrated).toBe(true); }); }); }); describe('serializeConfig & deserializeConfig', () => { beforeEach(() => { configStore.getState().reset(); }); it('should serialize state to base64', () => { const state: ConfigState = { activeColors: { primary: '#ff0000', secondary: '#00ff00', accent: '#0000ff' }, activePersonaAttire: 'Test Attire', activeBody: 'basic', activePayloads: [{ id: 'p1', type: 'camera', position: 'head' }], isHydrated: true, }; const encoded = serializeConfig(state); expect(typeof encoded).toBe('string'); expect(encoded.length).toBeGreaterThan(0); }); it('should deserialize base64 to state', () => { const state: ConfigState = { activeColors: { primary: '#ff0000', secondary: '#00ff00', accent: '#0000ff' }, activePersonaAttire: 'Test Attire', activeBody: 'basic', activePayloads: [{ id: 'p1', type: 'camera', position: 'head' }], isHydrated: true, }; const encoded = serializeConfig(state); const decoded = deserializeConfig(encoded); expect(decoded).not.toBeNull(); expect(decoded?.activeColors).toEqual(state.activeColors); expect(decoded?.activePersonaAttire).toBe(state.activePersonaAttire); expect(decoded?.activePayloads).toEqual(state.activePayloads); }); it('should return null for invalid base64', () => { const result = deserializeConfig('not-valid-base64!!!'); expect(result).toBeNull(); }); it('should return null for invalid schema', () => { const invalidJson = btoa(JSON.stringify({ invalid: 'schema' })); const result = deserializeConfig(invalidJson); expect(result).toBeNull(); }); it('should round-trip complex state correctly', () => { const original: ConfigState = { activeColors: { primary: '#aabbcc', secondary: '#ddeeff', accent: '#112233' }, activePersonaAttire: 'Emarati Kandura', activeBody: 'edu', activePayloads: [ { id: 'cam1', type: 'PTZ Camera', position: 'head' }, { id: 'light1', type: 'LED Array', position: 'chest' }, { id: 'sensor1', type: 'Lidar', position: 'base' }, ], isHydrated: true, }; const encoded = serializeConfig(original); const decoded = deserializeConfig(encoded); expect(decoded).not.toBeNull(); expect(decoded?.activeColors).toEqual(original.activeColors); expect(decoded?.activePersonaAttire).toBe(original.activePersonaAttire); expect(decoded?.activeBody).toBe(original.activeBody); expect(decoded?.activePayloads).toHaveLength(3); expect(decoded?.activePayloads).toEqual(original.activePayloads); }); });