Files
ArtPlayer/test/browser/global-events.spec.js

100 lines
4.3 KiB
JavaScript

import { expect, test } from './fixtures.js'
async function setup(page, core) {
await page.goto(`/test/player.html?core=${core}&chapter=published`)
await page.evaluate(() => window.createPlayer('/test/pattern.mp4'))
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
}
for (const action of ['rebind', 'destroy']) {
test(`candidate: ${action} during native global registration cancels the interrupted binding`, async ({ page }) => {
await setup(page, 'candidate')
expect(await page.evaluate((action) => {
const art = window.art
const frames = [document.createElement('iframe'), document.createElement('iframe')]
frames.forEach(frame => document.body.append(frame))
const [interrupted, newest] = frames
const target = interrupted.contentDocument
const original = target.addEventListener
target.addEventListener = function (name, ...args) {
if (name === 'click') {
if (action === 'destroy')
art.destroy()
else
art.events.bindGlobalEvents({ document: newest.contentDocument, window: newest.contentWindow })
}
return original.call(this, name, ...args)
}
const received = []
art.on('document:mouseup', event => received.push(event.target === newest.contentDocument ? 'newest' : 'stale'))
art.events.bindGlobalEvents({ document: target, window: interrupted.contentWindow })
document.dispatchEvent(new Event('mouseup'))
for (const frame of frames)
frame.contentDocument.dispatchEvent(new frame.contentWindow.Event('mouseup'))
if (!art.isDestroy)
art.destroy()
target.addEventListener = original
for (const frame of frames)
frame.remove()
return { received, remaining: art.events.destroyEvents.size }
}, action)).toEqual({ received: action === 'rebind' ? ['newest'] : [], remaining: 0 })
})
}
for (const core of ['published', 'candidate']) {
test(`${core}: global rebinding forwards original events once and releases the previous document`, async ({ page }) => {
await setup(page, core)
expect(await page.evaluate(() => {
const art = window.art
const frame = document.createElement('iframe')
document.body.append(frame)
const next = frame.contentDocument
const events = []
art.on('document:mouseup', event => events.push(event))
const first = new Event('mouseup')
document.dispatchEvent(first)
const returned = art.events.bindGlobalEvents({ document: next, window: frame.contentWindow })
art.events.bindGlobalEvents({ document: next, window: frame.contentWindow })
document.dispatchEvent(new Event('mouseup'))
const second = new frame.contentWindow.Event('mouseup')
next.dispatchEvent(second)
art.destroy()
next.dispatchEvent(new frame.contentWindow.Event('mouseup'))
frame.remove()
return { count: events.length, identity: events[0] === first && events[1] === second, returned: typeof returned }
})).toEqual({ count: 2, identity: true, returned: 'undefined' })
})
test(`${core}: failed global rebinding keeps the previous document and removes partial new listeners`, async ({ page }) => {
await setup(page, core)
expect(await page.evaluate(() => {
const art = window.art
const frame = document.createElement('iframe')
document.body.append(frame)
const next = frame.contentDocument
const original = next.addEventListener
const failure = new Error('document listener denied')
next.addEventListener = function (name, ...args) {
if (name === 'keydown')
throw failure
return original.call(this, name, ...args)
}
const received = []
art.on('document:mouseup', event => received.push(event.target === document ? 'old' : 'new'))
let sameError = false
try {
art.events.bindGlobalEvents({ document: next, window: frame.contentWindow })
}
catch (error) {
sameError = error === failure
}
next.addEventListener = original
document.dispatchEvent(new Event('mouseup'))
next.dispatchEvent(new frame.contentWindow.Event('mouseup'))
art.destroy()
frame.remove()
return { received, sameError }
})).toEqual({ received: core === 'candidate' ? ['old'] : ['new'], sameError: true })
})
}