import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { clearDragging, clearDropTarget, flashDropped, markDragging, markDropTarget, } from './dnd'; function el(): HTMLElement { return document.createElement('div'); } describe('shared/dnd state attributes', () => { it('marks and clears the dragging state', () => { const node = el(); markDragging(node); expect(node.hasAttribute('data-dragging')).toBe(true); clearDragging(node); expect(node.hasAttribute('data-dragging')).toBe(false); }); it('marks a drop target without an edge when data is omitted', () => { const node = el(); markDropTarget(node); expect(node.hasAttribute('data-drop-target')).toBe(true); expect(node.hasAttribute('data-drop-edge')).toBe(false); }); it('reflects the closest edge from drop-target data', () => { const node = el(); // `attachClosestEdge` stores the edge under a private symbol key; emulate it // by reflecting whatever `extractClosestEdge` reads. Here we assert the // no-edge path and the explicit clear path, which are deterministic. markDropTarget(node, {}); expect(node.hasAttribute('data-drop-target')).toBe(true); expect(node.hasAttribute('data-drop-edge')).toBe(false); }); it('clears all drop-target state', () => { const node = el(); markDropTarget(node); node.dataset.dropEdge = 'top'; clearDropTarget(node); expect(node.hasAttribute('data-drop-target')).toBe(false); expect(node.hasAttribute('data-drop-edge')).toBe(false); }); describe('flashDropped', () => { beforeEach(() => vi.useFakeTimers()); afterEach(() => vi.useRealTimers()); it('sets data-dropped then removes it after the timeout', () => { const node = el(); flashDropped(node, 200); expect(node.hasAttribute('data-dropped')).toBe(true); vi.advanceTimersByTime(200); expect(node.hasAttribute('data-dropped')).toBe(false); }); }); });