constellation-analyzer/src/stores/settingsStore.test.ts
Jan-Henrik Bruhn 9ffd62d54a feat: implement presentation mode for touch table displays
Add comprehensive presentation/viewer mode optimized for touch table
interactions with clean UI and touch-friendly timeline navigation.

State Management:
- Add presentationMode toggle to settingsStore with localStorage persistence
- Add preferPresentationMode to DocumentMetadata for per-document preferences
- Auto-enter presentation mode when opening documents that prefer it
- Add setDocumentPresentationPreference() helper to workspaceStore

UI Components:
- Create PresentationTimelineOverlay component with floating timeline control
  - Previous/Next navigation buttons with chevron icons
  - Horizontal scrollable state list
  - Only shows when document has 2+ states
  - Proper vertical alignment using flex items-stretch and centered content
  - Scales to ~10 states with max-w-screen-md (768px) container
- Create presentation.css for touch optimizations (60px+ touch targets)

UI Modifications:
- App.tsx: Conditional rendering hides editing chrome in presentation mode
- GraphEditor: Disable editing interactions, keep pan/zoom enabled
- MenuBar: Add "Presentation Mode" menu item
- Global shortcuts: F11 to toggle, Escape to exit presentation mode

Tests:
- Add presentation mode tests to settingsStore.test.ts
- Add document preference tests to workspaceStore.test.ts
- All 376 tests passing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-15 17:36:00 +01:00

192 lines
5.9 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import { useSettingsStore } from './settingsStore';
describe('settingsStore', () => {
beforeEach(() => {
// Clear localStorage
localStorage.clear();
// Reset store to initial state
useSettingsStore.setState({
autoZoomEnabled: true,
presentationMode: false,
});
});
describe('Initial State', () => {
it('should have correct default settings', () => {
const state = useSettingsStore.getState();
expect(state.autoZoomEnabled).toBe(true);
expect(state.presentationMode).toBe(false);
});
});
describe('Persistence', () => {
it('should persist to localStorage on change', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
// Check localStorage directly
const stored = localStorage.getItem('constellation-settings');
expect(stored).toBeTruthy();
const parsed = JSON.parse(stored!);
expect(parsed.state.autoZoomEnabled).toBe(false);
});
it('should load from localStorage on initialization', () => {
// Set initial value
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
// Simulate page reload by creating a new store instance
// In production, this happens when the page reloads
const stored = localStorage.getItem('constellation-settings');
expect(stored).toBeTruthy();
const parsed = JSON.parse(stored!);
expect(parsed.state.autoZoomEnabled).toBe(false);
});
it('should handle missing localStorage gracefully', () => {
// Clear localStorage
localStorage.clear();
// Should use default values
const state = useSettingsStore.getState();
expect(state.autoZoomEnabled).toBe(true);
});
});
describe('setAutoZoomEnabled', () => {
it('should enable auto zoom', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(true);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(true);
});
it('should disable auto zoom', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
});
it('should toggle auto zoom multiple times', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
setAutoZoomEnabled(true);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(true);
setAutoZoomEnabled(false);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
});
});
describe('Edge Cases', () => {
it('should handle rapid consecutive toggles', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
for (let i = 0; i < 100; i++) {
setAutoZoomEnabled(i % 2 === 0);
}
// Last iteration: i=99, 99 % 2 = 1, so i % 2 === 0 is false
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
});
it('should preserve setting across multiple operations', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
// Perform multiple reads
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
expect(useSettingsStore.getState().autoZoomEnabled).toBe(false);
});
});
describe('Store Versioning', () => {
it('should include version in persisted data', () => {
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
const stored = localStorage.getItem('constellation-settings');
expect(stored).toBeTruthy();
const parsed = JSON.parse(stored!);
expect(parsed.version).toBe(1);
});
});
describe('setPresentationMode', () => {
it('should enable presentation mode', () => {
const { setPresentationMode } = useSettingsStore.getState();
setPresentationMode(true);
expect(useSettingsStore.getState().presentationMode).toBe(true);
});
it('should disable presentation mode', () => {
const { setPresentationMode } = useSettingsStore.getState();
setPresentationMode(true);
setPresentationMode(false);
expect(useSettingsStore.getState().presentationMode).toBe(false);
});
it('should toggle presentation mode multiple times', () => {
const { setPresentationMode } = useSettingsStore.getState();
setPresentationMode(true);
expect(useSettingsStore.getState().presentationMode).toBe(true);
setPresentationMode(false);
expect(useSettingsStore.getState().presentationMode).toBe(false);
setPresentationMode(true);
expect(useSettingsStore.getState().presentationMode).toBe(true);
});
it('should persist presentation mode to localStorage', () => {
const { setPresentationMode } = useSettingsStore.getState();
setPresentationMode(true);
// Check localStorage directly
const stored = localStorage.getItem('constellation-settings');
expect(stored).toBeTruthy();
const parsed = JSON.parse(stored!);
expect(parsed.state.presentationMode).toBe(true);
});
});
describe('Future Extensibility', () => {
it('should maintain backward compatibility when new settings are added', () => {
// Set current setting
const { setAutoZoomEnabled } = useSettingsStore.getState();
setAutoZoomEnabled(false);
// Verify it persists correctly
const stored = localStorage.getItem('constellation-settings');
const parsed = JSON.parse(stored!);
expect(parsed.state.autoZoomEnabled).toBe(false);
// This test ensures the structure supports future settings
// When new settings are added, they should not break existing data
});
});
});