import { describe, it, expect, afterEach } from 'vitest' import { nextTick, ref } from 'vue' import { useFocusTrap } from '../src/lib/use-focus-trap' function appendContainer() { const container = document.createElement('div') const first = document.createElement('button') first.textContent = 'first' const last = document.createElement('button') last.textContent = 'last' container.append(first, last) document.body.append(container) return { container, first, last } } describe('useFocusTrap', () => { afterEach(() => { document.body.replaceChildren() }) it('moves focus into the container on activation', async () => { const { container, first } = appendContainer() const containerRef = ref(container) const active = ref(false) useFocusTrap(containerRef, active) active.value = true await nextTick() await nextTick() expect(document.activeElement).toBe(first) }) it('uses the initialFocus override when provided', async () => { const { container, last } = appendContainer() const containerRef = ref(container) const active = ref(false) useFocusTrap(containerRef, active, { initialFocus: () => last }) active.value = true await nextTick() await nextTick() expect(document.activeElement).toBe(last) }) it('wraps Tab from the last focusable back to the first', async () => { const { container, first, last } = appendContainer() const containerRef = ref(container) const active = ref(true) useFocusTrap(containerRef, active) last.focus() const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true }) document.dispatchEvent(event) expect(document.activeElement).toBe(first) }) it('wraps Shift+Tab from the first focusable back to the last', async () => { const { container, first, last } = appendContainer() const containerRef = ref(container) const active = ref(true) useFocusTrap(containerRef, active) first.focus() const event = new KeyboardEvent('keydown', { key: 'Tab', shiftKey: true, bubbles: true, cancelable: true }) document.dispatchEvent(event) expect(document.activeElement).toBe(last) }) it('restores focus to the previously-focused element on deactivation', async () => { const opener = document.createElement('button') opener.textContent = 'opener' document.body.append(opener) opener.focus() const { container } = appendContainer() const containerRef = ref(container) const active = ref(false) useFocusTrap(containerRef, active) active.value = true await nextTick() await nextTick() active.value = false await nextTick() expect(document.activeElement).toBe(opener) }) })