mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 10:56:15 -08:00
111 lines
3.7 KiB
JavaScript
111 lines
3.7 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
// eslint-disable-next-line test/no-import-node-test -- Verify focus modality ownership and document rebinding.
|
|
import { test } from 'node:test'
|
|
import { loadModules } from './helpers/load.js'
|
|
|
|
const { focusVisibility, captureMovedFocus, ResourceScope } = await loadModules({
|
|
focusVisibility: { file: 'packages/artplayer/src/accessibility/focus', name: 'focusVisibility' },
|
|
captureMovedFocus: { file: 'packages/artplayer/src/accessibility/moved-focus', name: 'captureMovedFocus' },
|
|
ResourceScope: 'packages/artplayer/src/lifecycle/scope',
|
|
})
|
|
|
|
test('DOM moves restore the same connected descendant and preserve externally moved focus', () => {
|
|
const body = {}
|
|
const outside = {}
|
|
const doc = { body, activeElement: null }
|
|
let count = 0
|
|
const child = { ownerDocument: doc, isConnected: true, focus(options) {
|
|
assert.deepEqual(options, { preventScroll: true })
|
|
count++
|
|
doc.activeElement = this
|
|
} }
|
|
const root = { ownerDocument: doc, contains: target => target === child }
|
|
doc.activeElement = child
|
|
const restore = captureMovedFocus(root)
|
|
doc.activeElement = body
|
|
restore()
|
|
assert.equal(doc.activeElement, child)
|
|
restore()
|
|
assert.equal(count, 1)
|
|
doc.activeElement = outside
|
|
restore()
|
|
assert.equal(doc.activeElement, outside)
|
|
doc.activeElement = body
|
|
child.isConnected = false
|
|
restore()
|
|
assert.equal(count, 1)
|
|
child.isConnected = true
|
|
doc.activeElement = outside
|
|
const unrelated = captureMovedFocus(root)
|
|
doc.activeElement = body
|
|
unrelated()
|
|
assert.equal(count, 1)
|
|
})
|
|
|
|
function fixture() {
|
|
const scope = new ResourceScope()
|
|
const doc = Object.assign(new EventTarget(), { activeElement: null })
|
|
const classes = new Set()
|
|
const child = {}
|
|
const root = Object.assign(new EventTarget(), {
|
|
ownerDocument: doc,
|
|
contains: value => value === child,
|
|
classList: {
|
|
contains: name => classes.has(name),
|
|
remove: name => classes.delete(name),
|
|
toggle: (name, active) => active ? classes.add(name) : classes.delete(name),
|
|
},
|
|
})
|
|
let shows = 0
|
|
const focused = focusVisibility(scope, root, () => shows++)
|
|
const focus = () => {
|
|
root.ownerDocument.activeElement = child
|
|
root.dispatchEvent(new Event('focusin'))
|
|
}
|
|
return { scope, doc, root, child, classes, focused, focus, shows: () => shows }
|
|
}
|
|
|
|
test('keyboard visibility follows actual focus without making pointer focus sticky', () => {
|
|
const f = fixture()
|
|
assert.equal(f.focused(), false)
|
|
f.focus()
|
|
assert.equal(f.focused(), true)
|
|
assert.equal(f.shows(), 1)
|
|
f.doc.dispatchEvent(new Event('mousedown'))
|
|
assert.equal(f.focused(), false)
|
|
assert.equal(f.classes.size, 0)
|
|
f.doc.dispatchEvent(new Event('keydown'))
|
|
assert.equal(f.focused(), true)
|
|
assert.equal(f.shows(), 2)
|
|
f.doc.dispatchEvent(new Event('keydown'))
|
|
assert.equal(f.shows(), 2)
|
|
f.doc.activeElement = null
|
|
f.root.dispatchEvent(new Event('focusout'))
|
|
assert.equal(f.focused(), false)
|
|
assert.equal(f.classes.size, 0)
|
|
f.scope.dispose()
|
|
})
|
|
|
|
test('moving a focused player rebinds modality listeners and disposal releases both documents', () => {
|
|
const f = fixture()
|
|
f.focus()
|
|
const next = Object.assign(new EventTarget(), { activeElement: null })
|
|
f.root.ownerDocument = next
|
|
f.focus()
|
|
f.doc.dispatchEvent(new Event('mousedown'))
|
|
assert.equal(f.focused(), true)
|
|
next.dispatchEvent(new Event('touchstart'))
|
|
assert.equal(f.focused(), false)
|
|
next.dispatchEvent(new Event('keydown'))
|
|
assert.equal(f.focused(), true)
|
|
const shows = f.shows()
|
|
f.scope.dispose()
|
|
assert.equal(f.focused(), false)
|
|
assert.equal(f.classes.size, 0)
|
|
for (const target of [f.doc, next, f.root])
|
|
target.dispatchEvent(new Event('keydown'))
|
|
f.focus()
|
|
assert.equal(f.shows(), shows)
|
|
assert.equal(f.classes.size, 0)
|
|
})
|