// @vitest-environment jsdom import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen, fireEvent } from '@testing-library/react' import { SplitPane } from '@/components/split-pane/split-pane' // Helper to set a cookie function setCookie(key: string, value: string) { Object.defineProperty(document, 'cookie', { writable: true, configurable: true, value: `sp:${key}=${encodeURIComponent(value)}`, }) } function clearCookies() { Object.defineProperty(document, 'cookie', { writable: true, configurable: true, value: '', }) } describe('SplitPane', () => { beforeEach(() => { clearCookies() // Default: desktop viewport Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 1440 }) window.dispatchEvent(new Event('resize')) }) afterEach(() => { vi.restoreAllMocks() }) it('renders 2 panes', () => { render( Pane A,
Pane B
]} defaultSplit={[30, 70]} cookieKey="test-2pane" /> ) expect(screen.getByText('Pane A')).toBeTruthy() expect(screen.getByText('Pane B')).toBeTruthy() }) it('renders 3 panes with 2 dividers', () => { const { container } = render( Left,
Middle
,
Right
, ]} defaultSplit={[28, 35, 37]} cookieKey="test-3pane" /> ) expect(screen.getByText('Left')).toBeTruthy() expect(screen.getByText('Middle')).toBeTruthy() expect(screen.getByText('Right')).toBeTruthy() // 2 dividers: cursor-col-resize elements const dividers = container.querySelectorAll('.cursor-col-resize') expect(dividers).toHaveLength(2) }) it('restores splits from cookie on mount', () => { const stored = JSON.stringify([40, 60]) setCookie('test-restore', stored) const { container } = render( A,
B
]} defaultSplit={[20, 80]} cookieKey="test-restore" /> ) // Left pane should have width 40%, not the default 20% const paneDiv = container.querySelector('[style*="40%"]') expect(paneDiv).toBeTruthy() }) it('falls back to defaultSplit when cookie is invalid', () => { setCookie('test-invalid', 'not-valid-json') const { container } = render( A,
B
]} defaultSplit={[25, 75]} cookieKey="test-invalid" /> ) const paneDiv = container.querySelector('[style*="25%"]') expect(paneDiv).toBeTruthy() }) it('renders tabs on mobile viewport', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 768 }) window.dispatchEvent(new Event('resize')) render( Content A,
Content B
]} defaultSplit={[50, 50]} cookieKey="test-mobile" tabLabels={['Tab A', 'Tab B']} /> ) expect(screen.getByText('Tab A')).toBeTruthy() expect(screen.getByText('Tab B')).toBeTruthy() // Only first tab content visible by default expect(screen.getByText('Content A')).toBeTruthy() expect(screen.queryByText('Content B')).toBeNull() }) it('switches tab content on mobile', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600 }) window.dispatchEvent(new Event('resize')) render( Content A,
Content B
]} defaultSplit={[50, 50]} cookieKey="test-mobile-switch" tabLabels={['Tab A', 'Tab B']} /> ) // Click second tab fireEvent.click(screen.getByText('Tab B')) expect(screen.queryByText('Content A')).toBeNull() expect(screen.getByText('Content B')).toBeTruthy() }) it('back button not visible on tab 0 in mobile', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600 }) window.dispatchEvent(new Event('resize')) render( A,
B
,
C
]} defaultSplit={[33, 33, 34]} cookieKey="test-back-hidden" tabLabels={['T1', 'T2', 'T3']} /> ) // On tab 0, no back button expect(screen.queryByLabelText('Terug')).toBeNull() }) it('back button visible on tab > 0 and navigates back', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600 }) window.dispatchEvent(new Event('resize')) render( A,
B
,
C
]} defaultSplit={[33, 33, 34]} cookieKey="test-back-nav" tabLabels={['T1', 'T2', 'T3']} /> ) // Switch to tab 2 fireEvent.click(screen.getByText('T3')) expect(screen.getByText('C')).toBeTruthy() expect(screen.getByLabelText('Terug')).toBeTruthy() // Click back → tab 1 fireEvent.click(screen.getByLabelText('Terug')) expect(screen.getByText('B')).toBeTruthy() // Click back again → tab 0, no back button fireEvent.click(screen.getByLabelText('Terug')) expect(screen.getByText('A')).toBeTruthy() expect(screen.queryByLabelText('Terug')).toBeNull() }) it('controlled activeTab prop switches the active pane', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600 }) window.dispatchEvent(new Event('resize')) const { rerender } = render( A,
B
,
C
]} defaultSplit={[33, 33, 34]} cookieKey="test-controlled" tabLabels={['T1', 'T2', 'T3']} activeTab={0} onActiveTabChange={vi.fn()} /> ) expect(screen.getByText('A')).toBeTruthy() rerender( A,
B
,
C
]} defaultSplit={[33, 33, 34]} cookieKey="test-controlled" tabLabels={['T1', 'T2', 'T3']} activeTab={2} onActiveTabChange={vi.fn()} /> ) expect(screen.getByText('C')).toBeTruthy() }) it('does not render dividers on mobile', () => { Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600 }) window.dispatchEvent(new Event('resize')) const { container } = render( A,
B
]} defaultSplit={[50, 50]} cookieKey="test-no-dividers" /> ) const dividers = container.querySelectorAll('.cursor-col-resize') expect(dividers).toHaveLength(0) }) })