import { describe, it, expect, afterEach } from 'vitest'; const { clickOutside } = await import('./clickOutside'); describe('clickOutside action', () => { const nodes: HTMLElement[] = []; function makeNode(): HTMLElement { const node = document.createElement('div'); document.body.appendChild(node); nodes.push(node); return node; } afterEach(() => { nodes.forEach((n) => n.remove()); nodes.length = 0; }); it('registers a capture-phase click listener on mount', () => { const node = makeNode(); const original = document.addEventListener.bind(document); let registered = false; document.addEventListener = (type: string, _fn: unknown, opts: unknown) => { if (type === 'click' && opts === true) registered = true; original(type as string, _fn as EventListener, opts as boolean); }; clickOutside(node); expect(registered).toBe(true); document.addEventListener = original; }); it('dispatches clickoutside when clicking outside the node', () => { const node = makeNode(); const outside = makeNode(); let fired = false; node.addEventListener('clickoutside', () => (fired = true)); clickOutside(node); outside.click(); expect(fired).toBe(true); }); it('does not dispatch clickoutside when clicking inside the node', () => { const node = makeNode(); const child = document.createElement('span'); node.appendChild(child); let fired = false; node.addEventListener('clickoutside', () => (fired = true)); clickOutside(node); child.click(); expect(fired).toBe(false); }); it('removes the listener on destroy', () => { const node = makeNode(); const outside = makeNode(); let count = 0; node.addEventListener('clickoutside', () => count++); const { destroy } = clickOutside(node); destroy(); outside.click(); expect(count).toBe(0); }); });