92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
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<HTMLElement | null>(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<HTMLElement | null>(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<HTMLElement | null>(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<HTMLElement | null>(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<HTMLElement | null>(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)
|
|
})
|
|
})
|