mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-19 11:21:20 -08:00
test(danmuku): [PKG-DANMUKU-08] verify native PiP and current-source mask combinations
This commit is contained in:
1 parent
88ce836f85
commit
b54a890832
9 files changed
+4741
-9
No files matched your search
@@ -0,0 +1,161 @@
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { dpipCandidate } from '../helpers/dpip.js'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const dpip = await dpipCandidate()
|
||||
let danmuku
|
||||
test.beforeAll(async () => {
|
||||
danmuku = process.env.ARTPLAYER_DANMUKU_ARTIFACT
|
||||
? fs.readFileSync(process.env.ARTPLAYER_DANMUKU_ARTIFACT, 'utf8')
|
||||
: await compilePackage('artplayer-plugin-danmuku', 'umd')
|
||||
})
|
||||
|
||||
for (const core of ['published', 'candidate']) {
|
||||
for (const ending of ['close', 'native-close', 'destroy']) {
|
||||
test(`${core}: Danmuku, heatmap and Worker survive native Document PiP ${ending}`, async ({ page, context }, testInfo) => {
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
const supported = await page.evaluate(() => typeof window.documentPictureInPicture?.requestWindow === 'function')
|
||||
const evidence = { core, ending, supported, danmuku: { input: process.env.ARTPLAYER_DANMUKU_ARTIFACT || 'source UMD', sha256: hash(danmuku) }, dpip: { input: dpip.name, sha256: hash(dpip.code) }, outcome: 'incomplete', rounds: [] }
|
||||
if (!supported) {
|
||||
evidence.outcome = 'native-document-pip-unavailable'
|
||||
await testInfo.attach('danmuku-dpip', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
||||
return
|
||||
}
|
||||
await page.evaluate(() => {
|
||||
window.combinationWorkers = []
|
||||
const NativeWorker = window.Worker
|
||||
window.Worker = class extends NativeWorker {
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.record = { terminated: 0, replies: 0 }
|
||||
window.combinationWorkers.push(this.record)
|
||||
this.addEventListener('message', () => this.record.replies++)
|
||||
}
|
||||
|
||||
terminate() {
|
||||
this.record.terminated++
|
||||
return super.terminate()
|
||||
}
|
||||
}
|
||||
})
|
||||
await page.addScriptTag({ content: danmuku })
|
||||
await page.addScriptTag({ content: `(() => { const module = { exports: {} }; const exports = module.exports; ${dpip.code}; window.dpipFactory = module.exports.default || module.exports; })();` })
|
||||
await page.evaluate(() => {
|
||||
window.combinationVisible = []
|
||||
window.combinationErrors = []
|
||||
window.combinationEvents = []
|
||||
window.art = new window.Artplayer({
|
||||
container: '.player',
|
||||
url: '/assets/sample/video.mp4',
|
||||
muted: true,
|
||||
plugins: [window.artplayerPluginDanmuku({ danmuku: [], heatmap: true, emitter: true, speed: 4 }), window.dpipFactory({ fallbackToVideoPiP: false })],
|
||||
})
|
||||
window.danmuku = window.art.plugins.artplayerPluginDanmuku
|
||||
window.danmukuOwner = window.danmuku.config({})
|
||||
window.pip = window.art.plugins.artplayerPluginDocumentPip
|
||||
window.combinationPlayer = window.art.template.$player
|
||||
window.combinationLayer = window.art.template.$danmuku
|
||||
window.combinationParent = window.combinationPlayer.parentNode
|
||||
window.art.on('document-pip', value => window.combinationEvents.push(value))
|
||||
window.art.on('artplayerPluginDanmuku:error', error => window.combinationErrors.push(String(error)))
|
||||
window.art.on('artplayerPluginDanmuku:visible', row => window.combinationVisible.push({ text: row.text, ref: row.$ref, time: window.art.currentTime }))
|
||||
document.querySelector('#play').onclick = () => window.art.play()
|
||||
const open = document.createElement('button')
|
||||
open.id = 'danmuku-open-pip'
|
||||
open.textContent = 'Open Danmuku PiP'
|
||||
open.onclick = () => {
|
||||
window.openingDanmukuPip = window.pip.open()
|
||||
}
|
||||
document.body.append(open)
|
||||
})
|
||||
try {
|
||||
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
|
||||
await page.click('#play')
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1)
|
||||
for (let round = 0; round < 2; round++) {
|
||||
const popupPromise = context.waitForEvent('page', { timeout: 8000 })
|
||||
await page.click('#danmuku-open-pip')
|
||||
const popup = await popupPromise
|
||||
await page.evaluate(() => window.openingDanmukuPip)
|
||||
await expect(popup.locator('video.art-video')).toBeVisible()
|
||||
await expect(popup.locator('.artplayer-plugin-danmuku')).toHaveCount(1)
|
||||
const text = `PiP row ${round}`
|
||||
await page.evaluate(async (text) => {
|
||||
await window.danmuku.load([{ text, time: window.art.currentTime + 0.5, mode: 1 }])
|
||||
}, text)
|
||||
await expect.poll(() => page.evaluate(text => window.combinationVisible.some(row => row.text === text), text)).toBe(true)
|
||||
await expect(popup.getByText(text, { exact: true })).toBeVisible()
|
||||
const snapshot = await page.evaluate((text) => {
|
||||
const row = window.combinationVisible.find(row => row.text === text)
|
||||
const rect = row.ref.getBoundingClientRect()
|
||||
const popup = window.documentPictureInPicture.window
|
||||
return {
|
||||
time: window.art.currentTime,
|
||||
rowTime: row.time,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
adopted: row.ref.ownerDocument === popup.document && window.combinationLayer.ownerDocument === popup.document,
|
||||
inLayer: window.combinationLayer.contains(row.ref),
|
||||
position: popup.getComputedStyle(row.ref).position,
|
||||
player: window.combinationPlayer.ownerDocument === popup.document,
|
||||
heatmap: window.art.controls.heatmap.ownerDocument === popup.document && !!window.art.controls.heatmap.querySelector('svg'),
|
||||
workers: window.combinationWorkers.map(worker => ({ ...worker })),
|
||||
}
|
||||
}, text)
|
||||
evidence.rounds.push(snapshot)
|
||||
expect(snapshot.adopted && snapshot.inLayer && snapshot.player && snapshot.heatmap).toBe(true)
|
||||
expect(snapshot.width).toBeGreaterThan(0)
|
||||
expect(snapshot.height).toBeGreaterThan(0)
|
||||
expect(snapshot.position).toBe('absolute')
|
||||
expect(snapshot.workers).toHaveLength(1)
|
||||
expect(snapshot.workers[0].replies).toBeGreaterThan(0)
|
||||
if (round === 0)
|
||||
await testInfo.attach('native-danmuku-page', { contentType: 'image/png', body: await popup.screenshot() })
|
||||
if (round === 1 && ending === 'destroy') {
|
||||
await page.evaluate(() => window.art.destroy(false))
|
||||
}
|
||||
else {
|
||||
await page.evaluate(ending => ending === 'native-close' ? window.documentPictureInPicture.window.close() : window.pip.close(), ending)
|
||||
await expect.poll(() => page.evaluate(() => window.pip.isActive)).toBe(false)
|
||||
expect(await page.evaluate(() => window.combinationPlayer.parentNode === window.combinationParent && window.combinationLayer.ownerDocument === document)).toBe(true)
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(snapshot.time + 0.1)
|
||||
}
|
||||
}
|
||||
if (ending !== 'destroy')
|
||||
await page.evaluate(() => window.art.destroy(false))
|
||||
await expect.poll(() => page.evaluate(() => !window.documentPictureInPicture.window || window.documentPictureInPicture.window.closed)).toBe(true)
|
||||
evidence.final = await page.evaluate(() => ({
|
||||
active: window.pip.isActive,
|
||||
workers: window.combinationWorkers,
|
||||
errors: window.combinationErrors,
|
||||
events: window.combinationEvents,
|
||||
frame: window.danmukuOwner.scheduler.frame,
|
||||
operation: window.danmukuOwner.scheduler.operation,
|
||||
nodes: window.combinationLayer.children.length,
|
||||
settings: document.querySelectorAll('.artplayer-plugin-danmuku').length,
|
||||
placeholders: document.querySelectorAll('.artplayer-document-pip-placeholder').length,
|
||||
}))
|
||||
expect(evidence.final.active).toBe(false)
|
||||
expect(evidence.final.workers).toHaveLength(1)
|
||||
expect(evidence.final.workers[0].terminated).toBe(1)
|
||||
expect(evidence.final.errors).toEqual([])
|
||||
// Destroy suppresses further public events, as in the existing native PiP contract.
|
||||
expect(evidence.final.events).toEqual(ending === 'destroy' ? [true, false, true] : [true, false, true, false])
|
||||
expect(evidence.final.frame).toBeNull()
|
||||
expect(evidence.final.operation).toBeNull()
|
||||
expect(evidence.final.nodes + evidence.final.settings + evidence.final.placeholders).toBe(0)
|
||||
evidence.outcome = 'native-playback-danmuku-and-cleanup-passed'
|
||||
}
|
||||
finally {
|
||||
await testInfo.attach('danmuku-dpip', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
||||
await page.evaluate(() => {
|
||||
if (window.art && !window.art.isDestroy)
|
||||
window.art.destroy(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,11 @@ import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const artifact = process.env.ARTPLAYER_MASK_ARTIFACT || 'packages/artplayer-plugin-danmuku-mask/dist/artplayer-plugin-danmuku-mask.js'
|
||||
const code = fs.readFileSync(artifact, 'utf8')
|
||||
const artifact = process.env.ARTPLAYER_MASK_ARTIFACT || 'source UMD'
|
||||
let code
|
||||
const baseline = JSON.parse(fs.readFileSync('refactor/baselines/danmuku-mask-release.json', 'utf8'))
|
||||
const assets = baseline.sdk.assets.map(({ file, sha256 }) => {
|
||||
const bytes = fs.readFileSync(file)
|
||||
@@ -17,8 +18,14 @@ const assets = baseline.sdk.assets.map(({ file, sha256 }) => {
|
||||
return { file, sha256: actual, baselineSha256: sha256, normalizedLF }
|
||||
})
|
||||
const media = 'docs/assets/sample/steve-jobs.mp4'
|
||||
const danmukuFile = 'packages/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js'
|
||||
const danmukuCode = fs.readFileSync(danmukuFile, 'utf8')
|
||||
const danmukuFile = process.env.ARTPLAYER_DANMUKU_ARTIFACT || 'source UMD'
|
||||
let danmukuCode
|
||||
test.beforeAll(async () => {
|
||||
;[code, danmukuCode] = await Promise.all([
|
||||
process.env.ARTPLAYER_MASK_ARTIFACT ? fs.readFileSync(artifact, 'utf8') : compilePackage('artplayer-plugin-danmuku-mask', 'umd'),
|
||||
process.env.ARTPLAYER_DANMUKU_ARTIFACT ? fs.readFileSync(danmukuFile, 'utf8') : compilePackage('artplayer-plugin-danmuku', 'umd'),
|
||||
])
|
||||
})
|
||||
|
||||
for (const core of ['candidate', 'published', 'published-5.3.1-beta.1']) {
|
||||
test(`Mask actual local MediaPipe model renders, stops and restarts with ${core} core`, async ({ page }, testInfo) => {
|
||||
|
||||
Reference in new issue
Block a user