mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-14 00:06:17 -08:00
test(ci): [CI-01] validate installed VAST loaders and native IMA
This commit is contained in:
1 parent
ce67eaa73e
commit
a4234230e6
18 files changed
+668
-24
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const candidate = await browserCandidate('artplayer-plugin-vast')
|
||||
const sdkUrl = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js'
|
||||
|
||||
async function setup(page, core, compatibility, testInfo) {
|
||||
const requests = []
|
||||
await page.route(sdkUrl, route => requests.push(route))
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
await page.addScriptTag({ content: candidate.code })
|
||||
await page.evaluate((compatibility) => {
|
||||
window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true })
|
||||
window.vastCallbacks = 0
|
||||
window.vastListeners = new Set()
|
||||
window.vastSettlements = []
|
||||
const on = window.art.on
|
||||
const off = window.art.off
|
||||
window.art.on = function (name, listener) {
|
||||
if (name === 'destroy')
|
||||
window.vastListeners.add(listener)
|
||||
return on.call(this, name, listener)
|
||||
}
|
||||
window.art.off = function (name, listener) {
|
||||
if (name === 'destroy')
|
||||
window.vastListeners.delete(listener)
|
||||
return off.call(this, name, listener)
|
||||
}
|
||||
window.registerVast = () => {
|
||||
const plugin = window.artplayerPluginVast(() => window.vastCallbacks++, { compatibility })
|
||||
return window.art.plugins.add(plugin).then(
|
||||
() => window.vastSettlements.push({ status: 'resolved' }),
|
||||
error => window.vastSettlements.push({ status: 'rejected', error }),
|
||||
)
|
||||
}
|
||||
if (window.artplayerPluginVast.default !== window.artplayerPluginVast)
|
||||
throw new Error('Default factory alias changed')
|
||||
}, compatibility)
|
||||
await testInfo.attach('vast-package-inputs', { contentType: 'application/json', body: JSON.stringify({ core, compatibility: compatibility || 'npm-default', provenance: candidate.provenance, sdkUrl, scope: 'Complete normal bundle including glomex. Native script requests are held/failed or fulfilled with an inert readiness sentinel; no real Google IMA/ad playback claim.' }) })
|
||||
return requests
|
||||
}
|
||||
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
const state = await page.evaluate(() => ({ callbacks: window.vastCallbacks, listeners: window.vastListeners?.size, destroyed: window.art?.isDestroy, settlements: window.vastSettlements?.map(({ status, error }) => ({ status, errorType: error?.type })), scripts: [...document.scripts].map(script => script.src).filter(src => src.includes('imasdk.googleapis.com')) }))
|
||||
await testInfo.attach('vast-package-state', { contentType: 'application/json', body: JSON.stringify(state) })
|
||||
await page.evaluate(() => {
|
||||
if (window.art && !window.art.isDestroy)
|
||||
window.art.destroy()
|
||||
})
|
||||
})
|
||||
|
||||
for (const core of ['published-5.1.7', 'published', 'candidate']) {
|
||||
for (const compatibility of [undefined, 'workspace-1.2']) {
|
||||
test(`VAST package ${core}/${compatibility || 'npm-default'}: shared SDK failure rejects both registrations and permits another request`, async ({ page }, testInfo) => {
|
||||
const requests = await setup(page, core, compatibility, testInfo)
|
||||
await page.evaluate(() => {
|
||||
void window.registerVast()
|
||||
void window.registerVast()
|
||||
})
|
||||
await expect.poll(() => requests.length).toBe(1)
|
||||
expect(await page.evaluate(() => window.vastListeners.size)).toBe(2)
|
||||
await requests[0].abort('failed')
|
||||
await expect.poll(() => page.evaluate(() => window.vastSettlements.length)).toBe(2)
|
||||
expect(await page.evaluate(() => ({ statuses: window.vastSettlements.map(item => item.status), sameError: window.vastSettlements[0].error === window.vastSettlements[1].error, errorType: window.vastSettlements[0].error.type, callbacks: window.vastCallbacks, listeners: window.vastListeners.size }))).toEqual({ statuses: ['rejected', 'rejected'], sameError: true, errorType: 'error', callbacks: 0, listeners: 0 })
|
||||
await page.evaluate(() => {
|
||||
void window.registerVast()
|
||||
})
|
||||
await expect.poll(() => requests.length).toBe(2)
|
||||
await requests[1].abort('failed')
|
||||
await expect.poll(() => page.evaluate(() => window.vastSettlements.length)).toBe(3)
|
||||
expect(await page.evaluate(() => ({ status: window.vastSettlements[2].status, callbacks: window.vastCallbacks, listeners: window.vastListeners.size, registered: Boolean(window.art.plugins.artplayerPluginVast) }))).toEqual({ status: 'rejected', callbacks: 0, listeners: 0, registered: false })
|
||||
await expect(page.locator('.player video')).toHaveCount(1)
|
||||
await page.locator('video').evaluate(video => video.play())
|
||||
await expect.poll(() => page.locator('video').evaluate(video => video.currentTime)).toBeGreaterThan(0.2)
|
||||
const pixel = await page.locator('video').evaluate((video) => {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = 80
|
||||
canvas.height = 45
|
||||
const context = canvas.getContext('2d')
|
||||
context.drawImage(video, 0, 0, 80, 45)
|
||||
return [...context.getImageData(30, 2, 1, 1).data]
|
||||
})
|
||||
expect(pixel[0]).toBeGreaterThan(180)
|
||||
expect(pixel[1]).toBeGreaterThan(180)
|
||||
expect(pixel[2]).toBeLessThan(80)
|
||||
await testInfo.attach('vast-package-content-frame', { contentType: 'application/json', body: JSON.stringify({ pixel }) })
|
||||
})
|
||||
|
||||
test(`VAST package ${core}/${compatibility || 'npm-default'}: destroy before SDK readiness suppresses late callbacks and construction`, async ({ page }, testInfo) => {
|
||||
const requests = await setup(page, core, compatibility, testInfo)
|
||||
await page.evaluate(() => {
|
||||
void window.registerVast()
|
||||
})
|
||||
await expect.poll(() => requests.length).toBe(1)
|
||||
await page.evaluate(() => window.art.destroy())
|
||||
await expect(page.locator('.player')).toBeEmpty()
|
||||
expect(await page.evaluate(() => window.vastListeners.size)).toBe(0)
|
||||
await requests[0].fulfill({ contentType: 'text/javascript', body: 'window.google = { ima: { fixtureReady: true } };' })
|
||||
await expect.poll(() => page.evaluate(() => window.vastSettlements.map(item => item.status))).toEqual(['resolved'])
|
||||
expect(await page.evaluate(() => ({ callbacks: window.vastCallbacks, listeners: window.vastListeners.size, destroyed: window.art.isDestroy, sentinel: window.google.ima.fixtureReady }))).toEqual({ callbacks: 0, listeners: 0, destroyed: true, sentinel: true })
|
||||
await expect(page.locator('.player')).toBeEmpty()
|
||||
expect(requests).toHaveLength(1)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Bundle the real SDK once before test discovery.
|
||||
const code = await compilePackage('artplayer-plugin-vast', 'umd')
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Select the complete source or installed SDK bundle before discovery.
|
||||
const { code, provenance } = await browserCandidate('artplayer-plugin-vast')
|
||||
|
||||
for (const compatibility of [undefined, 'workspace-1.2']) {
|
||||
test(`real IMA ${compatibility || 'npm-default'} recovers from empty VAST, recreates and destroys an active ad`, async ({ page }, testInfo) => {
|
||||
await page.goto('/test/player.html?core=candidate')
|
||||
await page.addScriptTag({ content: code })
|
||||
await testInfo.attach('native-vast-inputs', { contentType: 'application/json', body: JSON.stringify({ provenance, sourceSha256: hash(code), compatibility: compatibility || 'npm-default', scope: 'Complete glomex bundle with real remote Google IMA; no SDK substitution.' }) })
|
||||
await page.evaluate(async (compatibility) => {
|
||||
window.createPlayer('/assets/sample/video.mp4')
|
||||
window.recoveryEvents = []
|
||||
@@ -65,7 +66,7 @@ for (const compatibility of [undefined, 'workspace-1.2']) {
|
||||
expect(state.terminalInit).toBeNull()
|
||||
expect(state.events.filter(event => event.type === 'AdError')).toHaveLength(1)
|
||||
await expect(page.locator('[id^="art-"]')).toHaveCount(0)
|
||||
await testInfo.attach('native-vast-recovery', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(code), compatibility: compatibility || 'npm-default', failure, ...state }) })
|
||||
await testInfo.attach('native-vast-recovery', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(code), provenance, compatibility: compatibility || 'npm-default', failure, ...state }) })
|
||||
await testInfo.attach('native-vast-recovery.xml', { contentType: 'application/xml', body: await page.evaluate(() => window.recoveryXml) })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import fs from 'node:fs'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
import { skippableVast } from './vast-fixture.mjs'
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Native SDK bundle is shared by test discovery.
|
||||
const code = await compilePackage('artplayer-plugin-vast', 'umd')
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Select the complete source or installed SDK bundle before discovery.
|
||||
const { code, provenance } = await browserCandidate('artplayer-plugin-vast')
|
||||
|
||||
for (const compatibility of [undefined, 'workspace-1.2']) {
|
||||
test(`real IMA ${compatibility || 'npm-default'} requests playUrl and skips through the SDK button`, async ({ page }, testInfo) => {
|
||||
await page.goto('/test/player.html?core=candidate')
|
||||
await page.addScriptTag({ content: code })
|
||||
await testInfo.attach('native-vast-inputs', { contentType: 'application/json', body: JSON.stringify({ provenance, sourceSha256: hash(code), compatibility: compatibility || 'npm-default', scope: 'Complete glomex bundle with real remote Google IMA; no SDK substitution.' }) })
|
||||
await page.evaluate(async (compatibility) => {
|
||||
window.createPlayer('/assets/sample/video.mp4')
|
||||
window.skipEvents = []
|
||||
@@ -62,7 +63,7 @@ for (const compatibility of [undefined, 'workspace-1.2']) {
|
||||
const state = await page.evaluate(() => ({ events: window.skipEvents, time: window.art.currentTime, paused: window.art.template.$video.paused, imaVersion: window.google.ima.VERSION }))
|
||||
expect(state.paused).toBe(false)
|
||||
expect(state.events.filter(event => event.type === 'AdError' || event.type === 'AdComplete')).toEqual([])
|
||||
await testInfo.attach('native-vast-skip', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(code), xmlSha256: hash(xml), mediaSha256: hash(fs.readFileSync('test/browser/media/pattern.mp4')), compatibility: compatibility || 'npm-default', beforeAd, ...state }) })
|
||||
await testInfo.attach('native-vast-skip', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(code), provenance, xmlSha256: hash(xml), mediaSha256: hash(fs.readFileSync('test/browser/media/pattern.mp4')), compatibility: compatibility || 'npm-default', beforeAd, ...state }) })
|
||||
await page.evaluate(() => window.art.destroy())
|
||||
await expect(page.locator('[id^="art-"]')).toHaveCount(0)
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import fs from 'node:fs'
|
||||
import { hash, readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { verifyVastContract } from '../../refactor/scripts/vast-contract.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Compile the real bundled SDK before test discovery.
|
||||
const code = await compilePackage('artplayer-plugin-vast', 'umd')
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Select the complete source or installed SDK bundle before discovery.
|
||||
const { code, provenance } = await browserCandidate('artplayer-plugin-vast')
|
||||
// eslint-disable-next-line antfu/no-top-level-await -- Verify immutable published bytes before native test discovery.
|
||||
const contract = await verifyVastContract()
|
||||
const historicalCode = readMember(contract.archives.get('artplayer-plugin-vast@1.0.0'), 'package/dist/artplayer-plugin-vast.js').toString()
|
||||
@@ -38,7 +38,7 @@ for (const core of ['published-5.1.7', 'published', 'candidate']) {
|
||||
test(`real IMA ${core} / ${implementation} plays local VAST media and resumes content`, async ({ page }, testInfo) => {
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
await page.addScriptTag({ content: bundle })
|
||||
await testInfo.attach('native-vast-inputs', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(bundle), sdk: historical ? 'immutable npm1.0.0 bundled SDK; real remote Google IMA' : '@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA', media: { file: mediaFile, sha256: hash(fs.readFileSync(mediaFile)), contentFile: 'docs/assets/sample/video.mp4', contentSha256: hash(fs.readFileSync('docs/assets/sample/video.mp4')) }, implementation, core, compatibility: compatibility || 'npm-default' }) })
|
||||
await testInfo.attach('native-vast-inputs', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(bundle), provenance: historical ? { kind: 'published', name: 'artplayer-plugin-vast', version: '1.0.0' } : provenance, sdk: historical ? 'immutable npm1.0.0 bundled SDK; real remote Google IMA' : '@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA', media: { file: mediaFile, sha256: hash(fs.readFileSync(mediaFile)), contentFile: 'docs/assets/sample/video.mp4', contentSha256: hash(fs.readFileSync('docs/assets/sample/video.mp4')) }, implementation, core, compatibility: compatibility || 'npm-default' }) })
|
||||
await page.evaluate(({ compatibility, historical }) => {
|
||||
window.nativeVastHistorical = historical
|
||||
window.nativeVastEvents = []
|
||||
|
||||
Reference in new issue
Block a user