mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
127 lines
8.1 KiB
JavaScript
127 lines
8.1 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import process from 'node:process'
|
|
import { hash } from '../../refactor/scripts/releases.mjs'
|
|
import { canvasCandidate } from '../helpers/canvas.js'
|
|
import { dpipCandidate } from '../helpers/dpip.js'
|
|
import { expect, test } from './fixtures.js'
|
|
|
|
const canvas = await canvasCandidate()
|
|
const dpip = await dpipCandidate()
|
|
if (process.env.ARTPLAYER_BROWSER_ARTIFACTS)
|
|
assert(canvas.name === 'candidate-installed' && dpip.name === 'candidate-installed', 'Installed Canvas PiP requires both verified packages')
|
|
|
|
for (const core of ['published', 'candidate']) {
|
|
for (const ending of ['close', 'native-close', 'destroy']) {
|
|
test(`${core}: canvas and subtitles survive native Document PiP ${ending}`, async ({ page, context, browserName }, testInfo) => {
|
|
await page.route('**/canvas-pip.vtt', route => route.fulfill({ contentType: 'text/vtt', body: 'WEBVTT\n\n00:00:00.000 --> 00:00:03.000\nOpening caption\n\n00:00:03.000 --> 00:00:08.000\nPiP caption\n' }))
|
|
await page.goto(`/test/player.html?core=${core}`)
|
|
const supported = await page.evaluate(() => typeof window.documentPictureInPicture?.requestWindow === 'function')
|
|
const evidence = { core, ending, browserName, supported, canvas: { name: canvas.name, sha256: hash(canvas.source) }, dpip: { name: dpip.name, sha256: hash(dpip.code) }, outcome: 'incomplete' }
|
|
if (!supported) {
|
|
evidence.outcome = 'native-document-pip-unavailable'
|
|
await testInfo.attach('canvas-dpip', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
|
return
|
|
}
|
|
await page.addScriptTag({ content: `(() => {
|
|
const pending = new Set();
|
|
const requestAnimationFrame = callback => { const id = window.requestAnimationFrame(time => { pending.delete(id); callback(time); }); pending.add(id); return id; };
|
|
const cancelAnimationFrame = id => { pending.delete(id); window.cancelAnimationFrame(id); };
|
|
const module = { exports: {} }; const exports = module.exports;
|
|
${canvas.source}; window.canvasFactory = module.exports.default || module.exports;
|
|
window.canvasPending = pending;
|
|
})();` })
|
|
await page.addScriptTag({ content: `(() => { const module = { exports: {} }; const exports = module.exports; ${dpip.code}; window.dpipFactory = module.exports.default || module.exports; })();` })
|
|
await page.evaluate(() => {
|
|
window.canvasDraws = 0
|
|
window.canvasErrors = []
|
|
window.canvasPipEvents = []
|
|
window.art = new window.Artplayer({
|
|
container: '.player',
|
|
url: '/test/pattern.mp4',
|
|
muted: true,
|
|
loop: true,
|
|
subtitle: { url: '/canvas-pip.vtt' },
|
|
proxy: window.canvasFactory((context, video) => {
|
|
window.canvasDraws++
|
|
window.canvasContext = context
|
|
window.canvasVideo = video
|
|
}),
|
|
plugins: [window.dpipFactory({ fallbackToVideoPiP: false })],
|
|
})
|
|
window.originalCanvas = window.art.video
|
|
window.originalPlayer = window.art.template.$player
|
|
window.originalParent = window.originalPlayer.parentNode
|
|
window.pip = window.art.plugins.artplayerPluginDocumentPip
|
|
window.art.on('document-pip', active => window.canvasPipEvents.push(active))
|
|
window.art.on('artplayerProxyCanvas:error', error => window.canvasErrors.push(String(error)))
|
|
document.querySelector('#play').onclick = () => window.art.play()
|
|
const open = document.createElement('button')
|
|
open.id = 'canvas-open-pip'
|
|
open.textContent = 'Open Canvas PiP'
|
|
open.onclick = () => {
|
|
window.openingCanvasPip = window.pip.open()
|
|
}
|
|
document.body.append(open)
|
|
})
|
|
try {
|
|
await expect.poll(() => page.evaluate(() => window.art.isReady && window.art.subtitle.cues.length === 2)).toBe(true)
|
|
await page.click('#play')
|
|
await expect.poll(() => page.evaluate(() => window.canvasDraws)).toBeGreaterThan(1)
|
|
const popupPromise = context.waitForEvent('page', { timeout: 8000 })
|
|
await page.click('#canvas-open-pip')
|
|
const popup = await popupPromise
|
|
await page.evaluate(() => window.openingCanvasPip)
|
|
await expect(popup.locator('canvas.art-video')).toBeVisible()
|
|
evidence.entered = await page.evaluate(() => ({
|
|
active: window.pip.isActive,
|
|
sameCanvas: window.art.video === window.originalCanvas,
|
|
playerAdopted: window.originalPlayer.ownerDocument === window.documentPictureInPicture.window.document,
|
|
videoAdopted: window.canvasVideo.ownerDocument === window.originalPlayer.ownerDocument,
|
|
trackAdopted: window.art.template.$track.ownerDocument === window.originalPlayer.ownerDocument,
|
|
time: window.art.currentTime,
|
|
draws: window.canvasDraws,
|
|
}))
|
|
expect(evidence.entered.active && evidence.entered.sameCanvas && evidence.entered.playerAdopted && evidence.entered.videoAdopted && evidence.entered.trackAdopted).toBe(true)
|
|
await expect.poll(() => page.evaluate(() => window.canvasDraws)).toBeGreaterThan(evidence.entered.draws + 2)
|
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(evidence.entered.time + 0.1)
|
|
await page.evaluate(() => {
|
|
window.art.pause()
|
|
window.art.currentTime = 4
|
|
})
|
|
await expect(popup.locator('.art-subtitle')).toHaveText('PiP caption')
|
|
await expect.poll(() => page.evaluate(() => window.canvasPending.size)).toBe(0)
|
|
expect(await page.evaluate(() => window.canvasContext.getImageData(0, 0, 1, 1).data[3])).toBe(255)
|
|
if (ending === 'destroy') {
|
|
await page.evaluate(() => window.art.destroy(false))
|
|
}
|
|
else {
|
|
if (ending === 'native-close')
|
|
await page.evaluate(() => window.documentPictureInPicture.window.close())
|
|
else await page.evaluate(() => window.pip.close())
|
|
await expect.poll(() => page.evaluate(() => window.pip.isActive)).toBe(false)
|
|
expect(await page.evaluate(() => window.originalPlayer.parentNode === window.originalParent && window.canvasVideo.ownerDocument === document && window.originalCanvas === window.art.video)).toBe(true)
|
|
await expect(page.locator('.art-subtitle')).toHaveText('PiP caption')
|
|
await page.click('#play')
|
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(4.1)
|
|
await page.evaluate(() => window.art.destroy(false))
|
|
}
|
|
await expect.poll(() => page.evaluate(() => !window.documentPictureInPicture.window || window.documentPictureInPicture.window.closed)).toBe(true)
|
|
const draws = await page.evaluate(() => window.canvasDraws)
|
|
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))))
|
|
evidence.final = await page.evaluate(() => ({ active: window.pip.isActive, connected: window.canvasVideo.isConnected, paused: window.canvasVideo.paused, src: window.canvasVideo.getAttribute('src'), pending: window.canvasPending.size, draws: window.canvasDraws, placeholders: document.querySelectorAll('.artplayer-document-pip-placeholder').length, events: window.canvasPipEvents, errors: window.canvasErrors }))
|
|
expect(evidence.final).toEqual({ active: false, connected: false, paused: true, src: null, pending: 0, draws, placeholders: 0, events: ending === 'destroy' ? [true] : [true, false], errors: [] })
|
|
evidence.outcome = 'native-window-playback-subtitles-and-cleanup'
|
|
}
|
|
finally {
|
|
evidence.observed = await page.evaluate(() => ({ active: window.pip?.isActive, paused: window.canvasVideo?.paused, time: window.canvasVideo?.currentTime, draws: window.canvasDraws, subtitle: window.art?.template.$subtitle?.textContent, errors: window.canvasErrors, events: window.canvasPipEvents }))
|
|
await page.evaluate(() => {
|
|
if (!window.art.isDestroy)
|
|
window.art.destroy(false)
|
|
window.documentPictureInPicture.window?.close()
|
|
})
|
|
await testInfo.attach('canvas-dpip', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
|
}
|
|
})
|
|
}
|
|
}
|