mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 03:46:16 -08:00
162 lines
7.4 KiB
JavaScript
162 lines
7.4 KiB
JavaScript
import { expect, test } from './fixtures.js'
|
|
|
|
async function setup(page, core = 'candidate') {
|
|
await page.goto(`/test/player.html?core=${core}&chapter=published`)
|
|
await page.evaluate(() => {
|
|
const before = document.createElement('button')
|
|
before.id = 'before-player'
|
|
before.textContent = 'Before player'
|
|
document.body.prepend(before)
|
|
window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true, hotkey: true, setting: true, fullscreenWeb: true, screenshot: true })
|
|
window.keyboardHits = []
|
|
window.art.on('hotkey', event => window.keyboardHits.push(event.code))
|
|
})
|
|
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
|
|
await page.locator('#before-player').focus()
|
|
}
|
|
|
|
async function tabPastNativeVideo(page) {
|
|
await page.keyboard.press('Tab')
|
|
// Firefox includes the native video in its existing sequential focus order.
|
|
if (await page.locator('.art-video').evaluate(element => element.ownerDocument.activeElement === element))
|
|
await page.keyboard.press('Tab')
|
|
}
|
|
|
|
async function tabToPlay(page) {
|
|
await tabPastNativeVideo(page)
|
|
await expect(page.locator('.art-control-progress')).toBeFocused()
|
|
await page.keyboard.press('Tab')
|
|
}
|
|
|
|
test('published: Tab skips the non-interactive main controls', async ({ page }) => {
|
|
await setup(page, 'published')
|
|
await tabPastNativeVideo(page)
|
|
await expect(page.locator('#play')).toBeFocused()
|
|
expect(await page.locator('.art-controls [tabindex="0"]').count()).toBe(0)
|
|
})
|
|
|
|
test('candidate: keyboard reaches stable play control and toggles once with focus retained', async ({ page }) => {
|
|
await setup(page)
|
|
await tabToPlay(page)
|
|
const play = page.locator('.art-control-playAndPause')
|
|
await expect(play).toBeFocused()
|
|
await expect(play).toHaveAttribute('role', 'button')
|
|
await expect(play).toHaveAttribute('aria-label', 'Play')
|
|
await page.keyboard.press('Enter')
|
|
await expect.poll(() => page.evaluate(() => window.art.playing && window.art.currentTime > 0.1)).toBe(true)
|
|
await expect(play).toBeFocused()
|
|
await expect(play).toHaveAttribute('aria-label', 'Pause')
|
|
await page.keyboard.down('Space')
|
|
expect(await page.evaluate(() => window.art.playing)).toBe(true)
|
|
await page.keyboard.up('Space')
|
|
await expect.poll(() => page.evaluate(() => window.art.video.paused)).toBe(true)
|
|
await expect(play).toBeFocused()
|
|
expect(await page.evaluate(() => window.keyboardHits)).toEqual([])
|
|
await page.keyboard.press('Tab')
|
|
await expect(page.locator('.art-control-volume .art-icon-volumeClose')).toBeFocused()
|
|
})
|
|
|
|
test('candidate: mute state, focus visibility and automatic hiding follow keyboard focus', async ({ page }) => {
|
|
await setup(page)
|
|
await tabToPlay(page)
|
|
await page.keyboard.press('Enter')
|
|
await expect.poll(() => page.evaluate(() => window.art.playing)).toBe(true)
|
|
await page.evaluate(() => {
|
|
window.Artplayer.CONTROL_HIDE_TIME = 0
|
|
})
|
|
await page.keyboard.press('Tab')
|
|
const muted = page.locator('.art-control-volume .art-icon-volumeClose')
|
|
const audible = page.locator('.art-control-volume .art-icon-volume')
|
|
await expect(muted).toBeFocused()
|
|
await expect(muted).toHaveAttribute('aria-label', 'Mute')
|
|
await expect(muted).toHaveAttribute('aria-pressed', 'true')
|
|
await page.keyboard.press('Space')
|
|
await expect(audible).toBeFocused()
|
|
await expect(audible).toHaveAttribute('aria-pressed', 'false')
|
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.5)
|
|
expect(await page.evaluate(() => window.art.controls.show)).toBe(true)
|
|
expect(await audible.evaluate(element => getComputedStyle(element).outlineStyle)).not.toBe('none')
|
|
expect(await page.evaluate(() => window.keyboardHits)).toEqual([])
|
|
await page.locator('#before-player').focus()
|
|
await expect.poll(() => page.evaluate(() => window.art.controls.show)).toBe(false)
|
|
expect(await page.evaluate(() => window.art.isFocus)).toBe(false)
|
|
})
|
|
|
|
test('candidate: custom control keyboard clicks retain the callback and release on replacement', async ({ page }) => {
|
|
await setup(page)
|
|
await page.evaluate(() => {
|
|
const art = window.art
|
|
window.customHits = []
|
|
art.controls.add({ name: 'keyboard-custom', position: 'right', html: 'Custom', click(component, event) {
|
|
window.customHits.push({ same: this === art, component: component === art.controls, type: event.type })
|
|
} })
|
|
})
|
|
const control = page.locator('.art-control-keyboard-custom')
|
|
await control.focus()
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.down('Space')
|
|
await page.keyboard.down('Space')
|
|
await page.keyboard.up('Space')
|
|
expect(await page.evaluate(() => window.customHits)).toEqual([
|
|
{ same: true, component: true, type: 'click' },
|
|
{ same: true, component: true, type: 'click' },
|
|
])
|
|
await page.keyboard.down('Space')
|
|
await page.evaluate(() => {
|
|
const art = window.art
|
|
window.oldControl = art.controls['keyboard-custom']
|
|
art.controls.update({ name: 'keyboard-custom', html: 'Replaced' })
|
|
})
|
|
await page.keyboard.up('Space')
|
|
await page.evaluate(() => {
|
|
window.oldControl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
|
|
})
|
|
expect(await page.evaluate(() => window.customHits.length)).toBe(2)
|
|
await control.focus()
|
|
await page.keyboard.press('Enter')
|
|
expect(await page.evaluate(() => window.customHits.length)).toBe(3)
|
|
await page.evaluate(() => window.art.destroy(false))
|
|
expect(await page.evaluate(() => {
|
|
window.oldControl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
|
|
return window.customHits.length
|
|
})).toBe(3)
|
|
})
|
|
|
|
test('candidate: native buttons inside custom controls retain activation without player hotkeys', async ({ page }) => {
|
|
await setup(page)
|
|
await page.evaluate(() => {
|
|
const art = window.art
|
|
window.nativeButtonHits = 0
|
|
window.parentButtonHits = 0
|
|
const button = document.createElement('button')
|
|
button.textContent = 'Native action'
|
|
button.addEventListener('click', () => window.nativeButtonHits++)
|
|
art.controls.add({ name: 'native-action', position: 'right', html: button, click() {
|
|
window.parentButtonHits++
|
|
} })
|
|
art.hotkey.add('KeyK', () => window.keyboardHits.push('custom-k'))
|
|
})
|
|
const parent = page.locator('.art-control-native-action')
|
|
const button = parent.locator('button')
|
|
await expect(parent).not.toHaveAttribute('role', 'button')
|
|
await button.focus()
|
|
await page.keyboard.press('Space')
|
|
await page.keyboard.press('Enter')
|
|
expect(await page.evaluate(() => ({ native: window.nativeButtonHits, parent: window.parentButtonHits, paused: window.art.video.paused, hotkeys: window.keyboardHits }))).toEqual({ native: 2, parent: 2, paused: true, hotkeys: [] })
|
|
await page.keyboard.press('k')
|
|
expect(await page.evaluate(() => window.keyboardHits)).toEqual(['custom-k', 'KeyK'])
|
|
})
|
|
|
|
test('candidate: pointer focus does not prevent the existing automatic control hiding', async ({ page }) => {
|
|
await setup(page)
|
|
// Start a pointer interaction after setup's programmatic focus.
|
|
await page.locator('.art-control-playAndPause .art-icon-play').click()
|
|
await expect.poll(() => page.evaluate(() => window.art.playing)).toBe(true)
|
|
await page.evaluate(() => {
|
|
window.Artplayer.CONTROL_HIDE_TIME = 0
|
|
})
|
|
await page.mouse.move(900, 650)
|
|
await expect.poll(() => page.evaluate(() => window.art.controls.show)).toBe(false)
|
|
await expect.poll(() => page.locator('.art-bottom').evaluate(element => getComputedStyle(element).opacity)).toBe('0')
|
|
})
|