test: add edge case tests for tab drag-and-drop reorder

- Drag cancel (dragEnd without drop) does not trigger reorder
- Drag from last tab toward first produces correct reorder
- Active tab path is preserved after reorder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lucaronin
2026-02-24 10:17:48 +01:00
parent 8164576d6c
commit 4089e0ec4d
2 changed files with 87 additions and 0 deletions

View File

@@ -132,6 +132,71 @@ describe('TabBar', () => {
expect(screen.getAllByTestId('tab-modified-indicator')).toHaveLength(3)
})
it('does not reorder on drag cancel (dragEnd without drop)', () => {
const onReorderTabs = vi.fn()
const tabs = makeTabs(['Alpha', 'Beta', 'Gamma'])
render(
<TabBar
tabs={tabs}
activeTabPath={tabs[0].entry.path}
{...defaultProps}
onReorderTabs={onReorderTabs}
/>
)
const alphaTab = screen.getByText('Alpha').closest('[draggable]')!
const betaTab = screen.getByText('Beta').closest('[draggable]')!
fireEvent.dragStart(alphaTab, {
dataTransfer: { effectAllowed: 'move', setData: vi.fn() },
})
const rect = betaTab.getBoundingClientRect()
fireEvent.dragOver(betaTab, {
clientX: rect.left + rect.width * 0.75,
dataTransfer: { dropEffect: 'move' },
})
// Cancel via dragEnd (Escape or release outside tab bar)
fireEvent.dragEnd(alphaTab)
expect(onReorderTabs).not.toHaveBeenCalled()
})
it('reorders from last toward first position', () => {
const onReorderTabs = vi.fn()
const tabs = makeTabs(['Alpha', 'Beta', 'Gamma'])
render(
<TabBar
tabs={tabs}
activeTabPath={tabs[2].entry.path}
{...defaultProps}
onReorderTabs={onReorderTabs}
/>
)
const gammaTab = screen.getByText('Gamma').closest('[draggable]')!
const alphaTab = screen.getByText('Alpha').closest('[draggable]')!
fireEvent.dragStart(gammaTab, {
dataTransfer: { effectAllowed: 'move', setData: vi.fn() },
})
// jsdom returns zero-sized rects, so clientX always hits "right half"
// (insert after index 0 → insert index 1). This still validates
// that dragging the last tab toward the front produces a reorder.
const rect = alphaTab.getBoundingClientRect()
fireEvent.dragOver(alphaTab, {
clientX: rect.left + rect.width * 0.75,
dataTransfer: { dropEffect: 'move' },
})
fireEvent.drop(alphaTab, { dataTransfer: {} })
// Gamma (2) dragged onto Alpha (0) → reorder from 2 to 1
expect(onReorderTabs).toHaveBeenCalledWith(2, 1)
})
it('switches tab on click', () => {
const onSwitchTab = vi.fn()
const tabs = makeTabs(['Alpha', 'Beta'])

View File

@@ -205,6 +205,28 @@ describe('useTabManagement', () => {
expect(result.current.tabs.map(t => t.entry.title)).toEqual(['C', 'A', 'B'])
})
it('preserves active tab after reorder', async () => {
const { result } = renderHook(() => useTabManagement())
await act(async () => {
await result.current.handleSelectNote(makeEntry({ path: '/vault/a.md', title: 'A' }))
})
await act(async () => {
await result.current.handleSelectNote(makeEntry({ path: '/vault/b.md', title: 'B' }))
})
await act(async () => {
await result.current.handleSelectNote(makeEntry({ path: '/vault/c.md', title: 'C' }))
})
// C is active (last opened). Move it to the front.
act(() => {
result.current.handleReorderTabs(2, 0)
})
expect(result.current.tabs.map(t => t.entry.title)).toEqual(['C', 'A', 'B'])
expect(result.current.activeTabPath).toBe('/vault/c.md')
})
it('persists tab order to localStorage', async () => {
const { result } = renderHook(() => useTabManagement())