diff --git a/src/components/SplitPane.test.tsx b/src/components/SplitPane.test.tsx index 5e06c8f9..39f1c9b8 100644 --- a/src/components/SplitPane.test.tsx +++ b/src/components/SplitPane.test.tsx @@ -7,6 +7,7 @@ import { triggerResize, clearResizeObservers } from '../test/setup'; // These match the mock in test/setup.ts const CONTAINER_WIDTH = 1024; const CONTAINER_HEIGHT = 768; +const DEFAULT_DIVIDER_SIZE = 1; describe('SplitPane', () => { beforeEach(() => { @@ -122,10 +123,14 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(2); - // First pane: 30% of 1024 = 307.2px - expect(panes[0]).toHaveStyle({ width: `${CONTAINER_WIDTH * 0.3}px` }); - // Second pane: remaining 70% = 716.8px - expect(panes[1]).toHaveStyle({ width: `${CONTAINER_WIDTH * 0.7}px` }); + // Available space = container - divider = 1024 - 1 = 1023px + const availableWidth = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE; + // First pane: 30% of available space (306.9px) + const pane1Width = parseFloat((panes[0] as HTMLElement).style.width); + expect(pane1Width).toBeCloseTo(availableWidth * 0.3, 1); + // Second pane: remaining 70% of available space (716.1px) + const pane2Width = parseFloat((panes[1] as HTMLElement).style.width); + expect(pane2Width).toBeCloseTo(availableWidth * 0.7, 1); }); it('distributes remaining space equally among multiple auto-sized panes', async () => { @@ -144,10 +149,12 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(3); + // Available space = container - (2 dividers * 1px) = 1024 - 2 = 1022px + const availableWidth = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE * 2; // First pane: 200px fixed expect(panes[0]).toHaveStyle({ width: '200px' }); - // Remaining (1024 - 200) = 824px split equally: 412px each - const remainingEach = (CONTAINER_WIDTH - 200) / 2; + // Remaining (1022 - 200) = 822px split equally: 411px each + const remainingEach = (availableWidth - 200) / 2; expect(panes[1]).toHaveStyle({ width: `${remainingEach}px` }); expect(panes[2]).toHaveStyle({ width: `${remainingEach}px` }); }); @@ -167,8 +174,10 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(2); - // Each pane gets 50% = 512px - const halfWidth = CONTAINER_WIDTH / 2; + // Available space = container - divider = 1024 - 1 = 1023px + // Each pane gets 50% = 511.5px + const availableWidth = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE; + const halfWidth = availableWidth / 2; expect(panes[0]).toHaveStyle({ width: `${halfWidth}px` }); expect(panes[1]).toHaveStyle({ width: `${halfWidth}px` }); }); @@ -189,12 +198,14 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(3); - // First two panes: 25% each = 256px - const quarterWidth = CONTAINER_WIDTH * 0.25; + // Available space = container - (2 dividers * 1px) = 1024 - 2 = 1022px + const availableWidth = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE * 2; + // First two panes: 25% each of available space + const quarterWidth = availableWidth * 0.25; expect(panes[0]).toHaveStyle({ width: `${quarterWidth}px` }); expect(panes[1]).toHaveStyle({ width: `${quarterWidth}px` }); - // Third pane: remaining 50% = 512px - expect(panes[2]).toHaveStyle({ width: `${CONTAINER_WIDTH * 0.5}px` }); + // Third pane: remaining 50% of available space + expect(panes[2]).toHaveStyle({ width: `${availableWidth * 0.5}px` }); }); it('handles vertical direction correctly', async () => { @@ -212,10 +223,12 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(2); - // First pane: 25% of 768 = 192px - expect(panes[0]).toHaveStyle({ height: `${CONTAINER_HEIGHT * 0.25}px` }); - // Second pane: remaining 75% = 576px - expect(panes[1]).toHaveStyle({ height: `${CONTAINER_HEIGHT * 0.75}px` }); + // Available height = container - divider = 768 - 1 = 767px + const availableHeight = CONTAINER_HEIGHT - DEFAULT_DIVIDER_SIZE; + // First pane: 25% of available height + expect(panes[0]).toHaveStyle({ height: `${availableHeight * 0.25}px` }); + // Second pane: remaining 75% of available height + expect(panes[1]).toHaveStyle({ height: `${availableHeight * 0.75}px` }); }); it('respects controlled size prop over defaultSize', async () => { @@ -235,10 +248,12 @@ describe('SplitPane initial size calculation', () => { const panes = container.querySelectorAll('[data-pane="true"]'); expect(panes).toHaveLength(2); + // Available space = container - divider = 1024 - 1 = 1023px + const availableWidth = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE; // First pane: controlled size of 400px (not 30%) expect(panes[0]).toHaveStyle({ width: '400px' }); - // Second pane: remaining 624px - expect(panes[1]).toHaveStyle({ width: `${CONTAINER_WIDTH - 400}px` }); + // Second pane: remaining available space minus first pane + expect(panes[1]).toHaveStyle({ width: `${availableWidth - 400}px` }); }); it('updates pane sizes when controlled size prop changes', async () => { @@ -355,9 +370,11 @@ describe('SplitPane container resize behavior', () => { const panes = container.querySelectorAll('[data-pane="true"]'); - // Initial: 200px + 824px = 1024px + // Available space = container - divider = 1024 - 1 = 1023px + const initialAvailable = CONTAINER_WIDTH - DEFAULT_DIVIDER_SIZE; + // Initial: 200px + 823px = 1023px (available space) expect(panes[0]).toHaveStyle({ width: '200px' }); - expect(panes[1]).toHaveStyle({ width: `${CONTAINER_WIDTH - 200}px` }); + expect(panes[1]).toHaveStyle({ width: `${initialAvailable - 200}px` }); // Simulate container resize to 2048px (double) await act(async () => { @@ -365,9 +382,15 @@ describe('SplitPane container resize behavior', () => { await vi.runAllTimersAsync(); }); + // Available space at new size = 2048 - 1 = 2047px + const newAvailable = 2048 - DEFAULT_DIVIDER_SIZE; // Uncontrolled panes should scale proportionally - expect(panes[0]).toHaveStyle({ width: '400px' }); - expect(panes[1]).toHaveStyle({ width: `${2048 - 400}px` }); + // Original ratio: 200/1023 and 823/1023 + const expectedPane1 = (200 / initialAvailable) * newAvailable; + const expectedPane2 = + ((initialAvailable - 200) / initialAvailable) * newAvailable; + expect(panes[0]).toHaveStyle({ width: `${expectedPane1}px` }); + expect(panes[1]).toHaveStyle({ width: `${expectedPane2}px` }); }); it('maintains controlled sizes in vertical direction on container resize', async () => { @@ -398,3 +421,101 @@ describe('SplitPane container resize behavior', () => { expect(panes[1]).toHaveStyle({ height: '300px' }); }); }); + +describe('SplitPane divider size accounting', () => { + beforeEach(() => { + clearResizeObservers(); + }); + + it('accounts for divider width when calculating percentage-based pane sizes', async () => { + // Custom divider with a known width + const DividerWithWidth = (props: { + direction: string; + onMouseDown?: () => void; + onTouchStart?: () => void; + onTouchEnd?: () => void; + onKeyDown?: () => void; + }) => ( +
+ ); + + const { container } = render( +