import { describe, it, expect, vi, afterEach } from 'vitest' import { nextTick, ref } from 'vue' import { usePopoverPosition } from '../src/lib/use-popover-position' function mockRect(el: HTMLElement, rect: Partial) { vi.spyOn(el, 'getBoundingClientRect').mockReturnValue({ top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0, x: 0, y: 0, toJSON: () => {}, ...rect, } as DOMRect) } describe('usePopoverPosition', () => { afterEach(() => { document.body.replaceChildren() vi.restoreAllMocks() }) it('places the content below the trigger when there is enough room', async () => { const trigger = document.createElement('button') const content = document.createElement('div') document.body.append(trigger, content) mockRect(trigger, { top: 100, bottom: 130, left: 20, width: 80 }) Object.defineProperty(content, 'offsetHeight', { value: 40, configurable: true }) vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(800) vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000) const open = ref(false) const position = usePopoverPosition(ref(trigger), ref(content), open) open.value = true await nextTick() await nextTick() expect(position.side).toBe('bottom') expect(position.top).toBe(134) expect(position.minWidth).toBe(80) }) it('flips above the trigger when there is not enough room below', async () => { const trigger = document.createElement('button') const content = document.createElement('div') document.body.append(trigger, content) mockRect(trigger, { top: 700, bottom: 730, left: 20, width: 80 }) Object.defineProperty(content, 'offsetHeight', { value: 200, configurable: true }) vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(800) vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000) const open = ref(false) const position = usePopoverPosition(ref(trigger), ref(content), open) open.value = true await nextTick() await nextTick() expect(position.side).toBe('top') expect(position.top).toBeLessThan(700) }) })