// src/layout/__tests__/layout-state.test.ts import { describe, it, expect } from 'vitest' import { createInitialLayoutState, toggleSidebar, setSidebarMode, toggleRightPanel, setRightPanelCollapsed, setSidebarWidth, setRightPanelWidth, setEditorMode, isReadOnly, computeToolbarLeftOffset, computeToolbarRightOffset, RIBBON_WIDTH, MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH, MIN_RIGHT_PANEL_WIDTH, MAX_RIGHT_PANEL_WIDTH, } from '../layout-state' describe('layout-state', () => { describe('createInitialLayoutState', () => { it('starts mobile with just the ribbon and desktop with Quick Access expanded', () => { expect(createInitialLayoutState(390).sidebarMode).toBe('ribbon') expect(createInitialLayoutState(767).sidebarMode).toBe('ribbon') expect(createInitialLayoutState(768).sidebarMode).toBe('full') expect(createInitialLayoutState(1280).sidebarMode).toBe('full') }) it('returns default state with full sidebar mode', () => { const state = createInitialLayoutState() expect(state.sidebarWidth).toBe(240) expect(state.sidebarMode).toBe('full') expect(state.rightPanelWidth).toBe(280) expect(state.rightPanelCollapsed).toBe(true) }) it('returns default state with editorMode live-preview', () => { const state = createInitialLayoutState() expect(state.editorMode).toBe('live-preview') }) }) describe('toggleSidebar', () => { it('cycles hidden -> ribbon', () => { let state = createInitialLayoutState() state = { ...state, sidebarMode: 'hidden' } state = toggleSidebar(state) expect(state.sidebarMode).toBe('ribbon') }) it('cycles ribbon -> full', () => { let state = createInitialLayoutState() state = { ...state, sidebarMode: 'ribbon' } state = toggleSidebar(state) expect(state.sidebarMode).toBe('full') }) it('cycles full -> hidden', () => { let state = createInitialLayoutState() expect(state.sidebarMode).toBe('full') state = toggleSidebar(state) expect(state.sidebarMode).toBe('hidden') }) it('completes full cycle: hidden -> ribbon -> full -> hidden', () => { let state = createInitialLayoutState() state = { ...state, sidebarMode: 'hidden' } state = toggleSidebar(state) expect(state.sidebarMode).toBe('ribbon') state = toggleSidebar(state) expect(state.sidebarMode).toBe('full') state = toggleSidebar(state) expect(state.sidebarMode).toBe('hidden') }) }) describe('setSidebarMode', () => { it('sets mode to hidden', () => { let state = createInitialLayoutState() state = setSidebarMode(state, 'hidden') expect(state.sidebarMode).toBe('hidden') }) it('sets mode to ribbon', () => { let state = createInitialLayoutState() state = setSidebarMode(state, 'ribbon') expect(state.sidebarMode).toBe('ribbon') }) it('sets mode to full', () => { let state = createInitialLayoutState() state = { ...state, sidebarMode: 'hidden' } state = setSidebarMode(state, 'full') expect(state.sidebarMode).toBe('full') }) it('returns state unchanged when mode is the same', () => { const state = createInitialLayoutState() const result = setSidebarMode(state, 'full') expect(result).toBe(state) }) it('returns state unchanged for invalid mode', () => { const state = createInitialLayoutState() const result = setSidebarMode(state, 'invalid' as never) expect(result).toBe(state) }) }) describe('toggleRightPanel', () => { it('toggles right panel collapsed state', () => { let state = createInitialLayoutState() expect(state.rightPanelCollapsed).toBe(true) // Starts collapsed state = toggleRightPanel(state) expect(state.rightPanelCollapsed).toBe(false) state = toggleRightPanel(state) expect(state.rightPanelCollapsed).toBe(true) }) }) describe('setRightPanelCollapsed', () => { it('sets panel to collapsed', () => { let state = createInitialLayoutState() state = toggleRightPanel(state) // Now expanded (false) state = setRightPanelCollapsed(state, true) expect(state.rightPanelCollapsed).toBe(true) }) it('sets panel to expanded', () => { let state = createInitialLayoutState() expect(state.rightPanelCollapsed).toBe(true) // Starts collapsed state = setRightPanelCollapsed(state, false) expect(state.rightPanelCollapsed).toBe(false) }) it('is idempotent when already in desired state', () => { let state = createInitialLayoutState() expect(state.rightPanelCollapsed).toBe(true) state = setRightPanelCollapsed(state, true) expect(state.rightPanelCollapsed).toBe(true) }) }) describe('setSidebarWidth', () => { it('sets sidebar width', () => { let state = createInitialLayoutState() state = setSidebarWidth(state, 300) expect(state.sidebarWidth).toBe(300) }) it('clamps to minimum', () => { let state = createInitialLayoutState() state = setSidebarWidth(state, 50) expect(state.sidebarWidth).toBe(MIN_SIDEBAR_WIDTH) }) it('clamps to maximum', () => { let state = createInitialLayoutState() state = setSidebarWidth(state, 1000) expect(state.sidebarWidth).toBe(MAX_SIDEBAR_WIDTH) }) }) describe('setRightPanelWidth', () => { it('sets right panel width', () => { let state = createInitialLayoutState() state = setRightPanelWidth(state, 350) expect(state.rightPanelWidth).toBe(350) }) it('clamps to minimum', () => { let state = createInitialLayoutState() state = setRightPanelWidth(state, 50) expect(state.rightPanelWidth).toBe(MIN_RIGHT_PANEL_WIDTH) }) it('clamps to maximum', () => { let state = createInitialLayoutState() state = setRightPanelWidth(state, 1000) expect(state.rightPanelWidth).toBe(MAX_RIGHT_PANEL_WIDTH) }) }) describe('isReadOnly', () => { it('returns false for source mode', () => { expect(isReadOnly('source')).toBe(false) }) it('returns false for live-preview mode', () => { expect(isReadOnly('live-preview')).toBe(false) }) }) describe('setEditorMode', () => { it('sets editor mode to live-preview', () => { let state = createInitialLayoutState() state = setEditorMode(state, 'live-preview') expect(state.editorMode).toBe('live-preview') }) it('sets editor mode to source', () => { let state = createInitialLayoutState() state = setEditorMode(state, 'source') expect(state.editorMode).toBe('source') }) it('preserves other state fields when changing mode', () => { let state = createInitialLayoutState() state = setSidebarMode(state, 'hidden') state = setEditorMode(state, 'source') expect(state.editorMode).toBe('source') expect(state.sidebarMode).toBe('hidden') }) }) describe('computeToolbarLeftOffset', () => { it('returns 0 when sidebar is hidden', () => { expect(computeToolbarLeftOffset('hidden', 240)).toBe(0) }) it('returns RIBBON_WIDTH when sidebar is ribbon-only', () => { expect(computeToolbarLeftOffset('ribbon', 240)).toBe(RIBBON_WIDTH) }) it('returns RIBBON_WIDTH + sidebarWidth when sidebar is full', () => { expect(computeToolbarLeftOffset('full', 240)).toBe(RIBBON_WIDTH + 240) }) }) describe('computeToolbarRightOffset', () => { it('returns 0 when right panel is collapsed', () => { expect(computeToolbarRightOffset(true, 280)).toBe(0) }) it('returns rightPanelWidth when right panel is expanded', () => { expect(computeToolbarRightOffset(false, 280)).toBe(280) }) }) })