mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
fix(auto-thumbnail): [PKG-AUTO-THUMB-13] ignore registration after destroy
This commit is contained in:
1 parent
9ba3c82f99
commit
876fa4c328
22 files changed
+4084
-11
No files matched your search
@@ -0,0 +1,50 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Verify late asynchronous installation ownership.
|
||||
import test from 'node:test'
|
||||
import { autoThumbnailCandidate, autoThumbnailEnvironment } from './helpers/auto-thumbnail.js'
|
||||
|
||||
const implementation = await autoThumbnailCandidate()
|
||||
|
||||
for (const mode of ['retained-host', 'unavailable-host-members']) {
|
||||
test(`Auto-thumbnail registration after destroy is inert: ${mode}`, async () => {
|
||||
const env = autoThumbnailEnvironment(implementation)
|
||||
env.art.isDestroy = true
|
||||
if (mode === 'unavailable-host-members') {
|
||||
for (const key of ['on', 'off', 'option']) {
|
||||
Object.defineProperty(env.art, key, { get() {
|
||||
throw new Error(`Destroyed host ${key} must not be read`)
|
||||
} })
|
||||
}
|
||||
}
|
||||
const pending = env.factory({ width: 80, number: 1 })(env.art)
|
||||
assert.equal(typeof pending.then, 'function', 'Late registration retains the asynchronous public shape')
|
||||
assert.deepEqual({ ...await pending }, { name: 'artplayerPluginAutoThumbnail' })
|
||||
assert.equal([...env.listeners.values()].reduce((count, set) => count + set.size, 0), 0)
|
||||
env.art.emit('video:loadedmetadata')
|
||||
assert.equal(env.videos.length, 0)
|
||||
assert.equal(env.canvases.length, 0)
|
||||
assert.equal(env.timers.size, 0)
|
||||
assert.equal(env.updates.length, 0)
|
||||
assert.equal(env.urls.size, 0)
|
||||
})
|
||||
}
|
||||
|
||||
for (const marker of [false, undefined]) {
|
||||
test(`Auto-thumbnail live registration remains compatible with isDestroy=${marker}`, async () => {
|
||||
const env = autoThumbnailEnvironment(implementation)
|
||||
if (marker !== undefined)
|
||||
env.art.isDestroy = marker
|
||||
await env.factory({ width: 80, number: 1 })(env.art)
|
||||
env.art.emit('video:loadedmetadata')
|
||||
assert.equal(env.videos.length, 1)
|
||||
env.metadata()
|
||||
env.seeked()
|
||||
env.finish()
|
||||
assert.equal(env.updates.length, 1)
|
||||
assert.equal(env.urls.size, 1)
|
||||
env.art.emit('destroy')
|
||||
assert.equal(env.urls.size, 0)
|
||||
assert.equal(env.timers.size, 0)
|
||||
assert.equal(env.attached.size, 0)
|
||||
})
|
||||
}
|
||||
@@ -529,6 +529,14 @@ The first immediate-pixel WebKit failure remains in the refactor evidence.
|
||||
This is native desktop media playback, not physical audibility or full devices.
|
||||
`document-site.spec.js` also checks generated guide links and Run Code parameters.
|
||||
|
||||
## Auto-thumbnail delayed registration
|
||||
|
||||
Auto-thumbnail's `auto-thumbnail-registration.spec.js` separately checks direct
|
||||
registrars delivered after real core destruction. It keeps the Promise/name
|
||||
contract, records zero subscriptions and verifies a late metadata event cannot
|
||||
allocate a hidden native video. It uses the source/artifact/installed resolver;
|
||||
this boundary test does not replace successful decoding or first-frame tests.
|
||||
|
||||
## VTT Thumbnail documentation examples
|
||||
|
||||
yarn test:browser document-vtt.spec.js document-site.spec.js --workers=1 validates both generated guides and their Run Code destinations after yarn build:docs. The guide test requires the original demo verbatim, preserves the original demo video and substitutes local VTT/SVG resources, and inspects actual preview screenshot pixels with pngjs. It covers red/blue crops from real mouse hover, inclusive endpoint selection via public setBar with a MouseEvent, a gap, destroy and a late event on both cores. It loads local dist explicitly and records its hash; this does not replace the verified installed-artifact suite, physical touch tests or full playback acceptance.
|
||||
@@ -0,0 +1,39 @@
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { autoThumbnailCandidate } from '../helpers/auto-thumbnail.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const implementation = await autoThumbnailCandidate()
|
||||
for (const core of ['published', 'candidate']) {
|
||||
test(`Auto-thumbnail delayed factory installation stays inert after ${core} core destruction`, async ({ page }, testInfo) => {
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
await page.addScriptTag({ content: implementation.code })
|
||||
const evidence = await page.evaluate(async () => {
|
||||
window.createPlayer('/test/pattern.mp4')
|
||||
const art = window.art
|
||||
const install = window.artplayerPluginAutoThumbnail({ width: 80, number: 1 })
|
||||
art.destroy()
|
||||
const subscriptions = []
|
||||
const on = art.on
|
||||
art.on = function (name, callback) {
|
||||
subscriptions.push(name)
|
||||
return on.call(this, name, callback)
|
||||
}
|
||||
try {
|
||||
const pending = install(art)
|
||||
const asynchronous = typeof pending.then === 'function'
|
||||
const result = await pending
|
||||
art.emit('video:loadedmetadata')
|
||||
const videos = document.querySelectorAll('video').length
|
||||
const canvases = document.querySelectorAll('canvas').length
|
||||
// Clean up the deliberate regression probe even when the old bundle leaks.
|
||||
art.emit('destroy')
|
||||
return { destroyed: art.isDestroy, asynchronous, result, subscriptions, videos, canvases }
|
||||
}
|
||||
finally {
|
||||
art.on = on
|
||||
}
|
||||
})
|
||||
await testInfo.attach('auto-thumbnail-late-registration', { contentType: 'application/json', body: JSON.stringify({ core, sha256: hash(implementation.code), provenance: implementation.provenance, ...evidence }) })
|
||||
expect(evidence).toEqual({ destroyed: true, asynchronous: true, result: { name: 'artplayerPluginAutoThumbnail' }, subscriptions: [], videos: 0, canvases: 0 })
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user