Files
ArtPlayer/test/browser/accessibility-info.spec.js

137 lines
5.7 KiB
JavaScript

import { expect, test } from './fixtures.js'
async function setup(page) {
await page.goto('/test/player.html?core=candidate&chapter=published')
await page.evaluate(() => {
window.infoEvents = []
const outside = document.createElement('button')
outside.id = 'info-outside'
outside.textContent = 'Outside'
document.body.append(outside)
window.art = new window.Artplayer({
container: '.player',
url: '/test/pattern.mp4',
muted: true,
fullscreenWeb: true,
controls: [{ name: 'info-trigger', position: 'right', html: 'Info', click() { this.info.show = true } }],
})
window.art.on('info', value => window.infoEvents.push(value))
})
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
}
test('candidate: info keyboard entry, Space close and Escape preserve the opening control', async ({ page }) => {
await setup(page)
const trigger = page.locator('.art-control-info-trigger')
await trigger.focus()
await page.keyboard.press('Enter')
await expect(page.locator('.art-info-close')).toBeFocused()
await expect(page.locator('.art-info-close')).toHaveAttribute('aria-label', 'Close')
await expect(page.locator('.art-info')).toHaveAttribute('aria-label', 'Video Info')
await page.keyboard.press('Space')
await expect(page.locator('.art-info')).toBeHidden()
await expect(trigger).toBeFocused()
await page.evaluate(() => {
window.art.fullscreenWeb = true
})
await page.keyboard.press('Enter')
await expect(page.locator('.art-info-close')).toBeFocused()
await page.keyboard.press('Escape')
await expect(page.locator('.art-info')).toBeHidden()
await expect(trigger).toBeFocused()
expect(await page.evaluate(() => window.art.fullscreenWeb)).toBe(true)
await page.keyboard.press('Escape')
expect(await page.evaluate(() => window.art.fullscreenWeb)).toBe(false)
expect(await page.evaluate(() => window.infoEvents)).toEqual([true, false, true, false])
})
test('candidate: info pointer and programmatic visibility preserve unrelated focus', async ({ page }) => {
await setup(page)
await page.locator('.art-control-info-trigger').click()
await expect(page.locator('.art-info-close')).not.toBeFocused()
await page.locator('#info-outside').focus()
await page.evaluate(() => {
window.art.info.show = false
window.art.info.show = true
window.art.info.show = false
})
await expect(page.locator('#info-outside')).toBeFocused()
})
test('candidate: repeated info init replaces keyboard bindings and retains the current return target', async ({ page }) => {
await setup(page)
await page.locator('.art-control-info-trigger').focus()
await page.keyboard.press('Enter')
await page.evaluate(() => {
window.art.info.init()
window.art.info.init()
window.infoEvents.length = 0
})
await page.keyboard.press('Enter')
await expect(page.locator('.art-info')).toBeHidden()
await expect(page.locator('.art-control-info-trigger')).toBeFocused()
expect(await page.evaluate(() => window.infoEvents)).toEqual([false])
})
test('candidate: info with a removed origin returns to the player and destruction disables retained controls', async ({ page }) => {
await setup(page)
await page.locator('.art-control-info-trigger').focus()
await page.keyboard.press('Enter')
await page.evaluate(() => window.art.controls.remove('info-trigger'))
await page.keyboard.press('Escape')
await expect(page.locator('.art-video-player')).toBeFocused()
await page.evaluate(() => {
window.retainedInfo = window.art.template.$infoClose
window.art.destroy(false)
window.infoEvents.length = 0
window.retainedInfo.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
window.retainedInfo.click()
})
expect(await page.evaluate(() => window.infoEvents)).toEqual([])
})
for (const core of ['published', 'candidate']) {
test(`${core}: optional SSR info wrapper may be absent without preventing polling and close`, async ({ page }) => {
await page.goto(`/test/player.html?core=${core}&chapter=published`)
expect(await page.evaluate(() => {
const container = document.querySelector('.player')
container.innerHTML = window.Artplayer.html
container.querySelector('.art-info').className = 'caller-info'
const close = container.querySelector('.art-info-close')
const panel = container.querySelector('.art-info-panel')
const art = new window.Artplayer({ container, url: '', useSSR: true })
art.info.show = true
close.click()
const result = { absent: art.template.$info === null, retained: art.template.$infoClose === close && art.template.$infoPanel === panel, closed: !art.info.show }
art.destroy()
return result
})).toEqual({ absent: true, retained: true, closed: true })
})
}
test('candidate: failed info name initialization releases its handlers and permits a clean retry', async ({ page }) => {
await setup(page)
expect(await page.evaluate(() => {
const get = window.art.i18n.get
const count = window.art.e.info.length
const failure = new Error('name failed')
window.art.i18n.get = () => {
throw failure
}
let same = false
try {
window.art.info.init()
}
catch (error) { same = error === failure }
window.art.i18n.get = get
const released = window.art.e.info.length === count - 1
window.art.info.init()
return { same, released }
})).toEqual({ same: true, released: true })
await page.locator('.art-control-info-trigger').focus()
await page.keyboard.press('Enter')
await expect(page.locator('.art-info-close')).toBeFocused()
await page.keyboard.press('Escape')
await expect(page.locator('.art-control-info-trigger')).toBeFocused()
})