mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-25 08:01:20 -08:00
refactor(core): CORE-17 type input events and own interaction lifetimes
This commit is contained in:
1 parent
88aef830df
commit
a842058136
72 files changed
+31156
-1219
No files matched your search
@@ -0,0 +1,133 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Use the repository Node test runner.
|
||||
import { test } from 'node:test'
|
||||
import { loadModules } from './helpers/load.js'
|
||||
|
||||
const { globalInit, ownListeners, proxyListener, removeListener, destroyListeners, beginLifecycle, getScope } = await loadModules({
|
||||
globalInit: 'packages/artplayer/src/events/globalInit',
|
||||
...Object.fromEntries(['ownListeners', 'proxyListener', 'removeListener', 'destroyListeners'].map(name => [name, { file: 'packages/artplayer/src/events/listener-registry', name }])),
|
||||
beginLifecycle: { file: 'packages/artplayer/src/lifecycle/instance', name: 'beginLifecycle' },
|
||||
getScope: { file: 'packages/artplayer/src/lifecycle/instance', name: 'getScope' },
|
||||
})
|
||||
|
||||
function source() {
|
||||
const window = new EventTarget()
|
||||
const document = Object.assign(new EventTarget(), { defaultView: window })
|
||||
return { document, window }
|
||||
}
|
||||
|
||||
function fixture() {
|
||||
const initial = source()
|
||||
const received = []
|
||||
const art = {
|
||||
template: { $player: { ownerDocument: initial.document } },
|
||||
emit: (...args) => received.push(args),
|
||||
}
|
||||
beginLifecycle(art)
|
||||
const registry = { destroyEvents: new Set() }
|
||||
ownListeners(registry, art)
|
||||
registry.proxy = (...args) => proxyListener(registry, ...args)
|
||||
registry.remove = dispose => removeListener(registry, dispose)
|
||||
const scope = getScope(art)
|
||||
scope.add(() => {
|
||||
destroyListeners(registry)
|
||||
return undefined
|
||||
})
|
||||
globalInit(art, registry)
|
||||
return { initial, art, registry, scope, received }
|
||||
}
|
||||
|
||||
test('global rebinding selects current owner targets, keeps event identity and original window fallback', () => {
|
||||
const f = fixture()
|
||||
const next = source()
|
||||
const event = new Event('mouseup')
|
||||
const scroll = new Event('scroll')
|
||||
f.registry.bindGlobalEvents({ document: next.document })
|
||||
f.initial.document.dispatchEvent(new Event('mouseup'))
|
||||
next.document.dispatchEvent(event)
|
||||
next.window.dispatchEvent(new Event('scroll'))
|
||||
f.initial.window.dispatchEvent(scroll)
|
||||
assert.deepEqual(f.received, [['document:mouseup', event], ['window:scroll', scroll]])
|
||||
f.art.template.$player.ownerDocument = next.document
|
||||
f.registry.bindGlobalEvents()
|
||||
f.initial.window.dispatchEvent(new Event('scroll'))
|
||||
next.window.dispatchEvent(scroll)
|
||||
assert.equal(f.received.length, 3)
|
||||
f.scope.dispose()
|
||||
next.document.dispatchEvent(event)
|
||||
assert.equal(f.received.length, 3)
|
||||
assert.equal(f.registry.destroyEvents.size, 0)
|
||||
})
|
||||
|
||||
test('window registration failure rolls back the staged document while old listeners keep working', () => {
|
||||
const f = fixture()
|
||||
const next = source()
|
||||
const failure = new Error('window failure')
|
||||
next.window.addEventListener = () => {
|
||||
throw failure
|
||||
}
|
||||
assert.throws(() => f.registry.bindGlobalEvents(next), error => error === failure)
|
||||
const event = new Event('mouseup')
|
||||
next.document.dispatchEvent(new Event('mouseup'))
|
||||
f.initial.document.dispatchEvent(event)
|
||||
assert.deepEqual(f.received, [['document:mouseup', event]])
|
||||
assert.equal(f.registry.destroyEvents.size, 15)
|
||||
f.scope.dispose()
|
||||
})
|
||||
|
||||
test('staged listeners do not forward before commit while the previous binding remains active', () => {
|
||||
const f = fixture()
|
||||
const next = source()
|
||||
const original = next.window.addEventListener
|
||||
const oldEvent = new Event('mouseup')
|
||||
next.window.addEventListener = function (name, ...args) {
|
||||
if (name === 'resize') {
|
||||
next.document.dispatchEvent(new Event('mouseup'))
|
||||
f.initial.document.dispatchEvent(oldEvent)
|
||||
}
|
||||
return original.call(this, name, ...args)
|
||||
}
|
||||
f.registry.bindGlobalEvents(next)
|
||||
assert.deepEqual(f.received, [['document:mouseup', oldEvent]])
|
||||
const nextEvent = new Event('mouseup')
|
||||
next.document.dispatchEvent(nextEvent)
|
||||
f.initial.document.dispatchEvent(new Event('mouseup'))
|
||||
assert.deepEqual(f.received, [['document:mouseup', oldEvent], ['document:mouseup', nextEvent]])
|
||||
f.scope.dispose()
|
||||
})
|
||||
|
||||
test('a newer reentrant global binding wins and the interrupted registration is released', () => {
|
||||
const f = fixture()
|
||||
const interrupted = source()
|
||||
const newest = source()
|
||||
const original = interrupted.document.addEventListener
|
||||
interrupted.document.addEventListener = function (name, ...args) {
|
||||
if (name === 'click')
|
||||
f.registry.bindGlobalEvents(newest)
|
||||
return original.call(this, name, ...args)
|
||||
}
|
||||
f.registry.bindGlobalEvents(interrupted)
|
||||
f.initial.document.dispatchEvent(new Event('mouseup'))
|
||||
interrupted.document.dispatchEvent(new Event('mouseup'))
|
||||
const event = new Event('mouseup')
|
||||
newest.document.dispatchEvent(event)
|
||||
assert.deepEqual(f.received, [['document:mouseup', event]])
|
||||
assert.equal(f.registry.destroyEvents.size, 15)
|
||||
f.scope.dispose()
|
||||
})
|
||||
|
||||
test('destroy during rebinding clears staged and old listeners and later bind remains inert', () => {
|
||||
const f = fixture()
|
||||
const next = source()
|
||||
const original = next.document.addEventListener
|
||||
next.document.addEventListener = function (...args) {
|
||||
f.scope.dispose()
|
||||
return original.apply(this, args)
|
||||
}
|
||||
f.registry.bindGlobalEvents(next)
|
||||
assert.equal(f.registry.destroyEvents.size, 0)
|
||||
f.registry.bindGlobalEvents()
|
||||
f.initial.document.dispatchEvent(new Event('mouseup'))
|
||||
next.document.dispatchEvent(new Event('mouseup'))
|
||||
assert.deepEqual(f.received, [])
|
||||
})
|
||||
Reference in new issue
Block a user