mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-14 08:26:16 -08:00
test(vast): [PKG-VAST-05] checkpoint native tag requests and skip controls
This commit is contained in:
1 parent
75da50a454
commit
09459955c6
13 files changed
+1789
-9
No files matched your search
@@ -128,4 +128,9 @@ availability is an explicit environment gate. No SDK boundary is substituted.
|
||||
Reports include bundle/media hashes, XML, SDK/browser versions, event order, decoded
|
||||
ad frames and resumed content state. See the validation record for actual results;
|
||||
adding this command does not establish device or final distribution acceptance.
|
||||
The native skip case requests a local HTTP VAST tag via `playUrl`, verifies its
|
||||
response and clicks IMA's own enabled skip button after the skippable event. Its
|
||||
countdown already has an accessible skip name; visibility alone is insufficient.
|
||||
The local XML server permits only IMA origins on that fixture route. Native SDK
|
||||
timeouts remain failures even when a late ad subsequently plays or skips correctly.
|
||||
Physical device validation remains05 and full distribution06.
|
||||
@@ -5,7 +5,7 @@ import base from './playwright.config.js'
|
||||
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Native VAST source validation does not accept unrelated artifact maps')
|
||||
export default defineConfig(base, {
|
||||
testMatch: ['**/vast.native.js', '**/vast-recovery.native.js'],
|
||||
testMatch: ['**/vast.native.js', '**/vast-recovery.native.js', '**/vast-skip.native.js'],
|
||||
timeout: 30000,
|
||||
workers: 1,
|
||||
outputDir: 'refactor/.cache/vast-native/results',
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,56 @@
|
||||
# PKG-VAST-05:playUrl、真实跳过按钮和失败分层
|
||||
|
||||
前置HEAD75da50a45。本次继续05,保持doing;生产源码、公开类型、依赖和产物没有
|
||||
变化,不把测试夹具修正包装成播放器缺陷修复。全部原报告和新证据见
|
||||
[vast-skip-validation.json](../baselines/vast-skip-validation.json)。
|
||||
|
||||
## 新增的实际覆盖
|
||||
|
||||
`test/browser/vast-skip.native.js`在候选核心的两种VAST模式下调用playUrl,真实IMA
|
||||
iframe通过HTTP读取广告XML,核对200、MIME、CORS与响应原文;广告实际解码后,
|
||||
等待AdSkippableStateChanged和可用的SDK按钮,真实点击,再验证AdSkipped、主片
|
||||
恢复及销毁。没有调用模拟事件、强制隐藏广告、伪造时间或通过skipAd替代UI。
|
||||
|
||||
[Google AdsManager接口](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/interface/google.ima.AdsManager#skip)
|
||||
明确限制:当IMA自己显示跳过按钮时,程序skip方法不负责跳过。因此本项直接测试
|
||||
SDK按钮。观察到的SDK为3.789.0,浏览器与前检查点相同。
|
||||
|
||||
`vast-fixture.mjs`生成8秒pattern.mp4广告、5秒跳过点、独立本地跟踪图片;
|
||||
`server.mjs`增加一个测试XML映射及XML MIME。仅这个资源允许明确的http/https
|
||||
imasdk.googleapis.com来源并返回凭据CORS和Vary:Origin,不给其他路由统一加CORS。
|
||||
正常PR套件只服务该本地资源,不自动运行外部SDK测试。没有新增依赖或脚本。
|
||||
|
||||
## 实际结果与失败记录
|
||||
|
||||
| 批次 | 结果 | 原因或实际范围 |
|
||||
| --- | --- | --- |
|
||||
| 4秒素材,首次HTTP标签 | 0/2 | 测试服务缺少CORS,真实iframe请求被拒绝;主片继续播放 |
|
||||
| 补CORS,仍用4秒/1秒跳过点 | 0/2 | 广告真实完成但没有跳过状态/按钮;没有推断所有短广告都不支持跳过 |
|
||||
| 8秒/5秒素材,旧按钮等待 | 0/2 | 1项SDK9000/标签等待超时;1项在倒计时已暴露的Skip Ad控件上过早点击 |
|
||||
| 等待真实可跳过事件和可用按钮 | 5/6 | 三引擎两模式;Chromium默认项收到9000后虽完成跳过/恢复仍判失败 |
|
||||
| WebKit旧插件媒体采样诊断 | 3/3 | 预先固定3次执行、无重试;未修改原首帧断言,不关闭历史失败 |
|
||||
| 既有播放/切源/错误/Range回归 | 12/12 | 三引擎、新旧核心;验证共享测试服务未破坏已有路径 |
|
||||
|
||||
所有浏览器进程退出后才读取最终JSON/归档,记录实际退出码。SDK加载和广告请求
|
||||
超时仍保持失败,没有提高SDK默认5秒/10秒预算;HTTP响应等待由默认整例30秒
|
||||
收紧到7秒以更快暴露资源读取失败。首三轮失败用于修正可定位的夹具问题,不作为
|
||||
成功证据;未反复运行相同断言直到变绿。最终5/6不是完整兼容通过。
|
||||
|
||||
## 旧WebKit首帧问题的新增证据
|
||||
|
||||
上个检查点的失败trace里,主脚本和bridge都返回200,AdStarted之后有实际
|
||||
“Linear Ad”画面(画面时钟00:00:00,12),随后AdComplete/主片恢复也发生了。
|
||||
它不能再被表述为没有播放广告;但当时首帧video属性断言为何始终不成立仍未确定。
|
||||
`vast.native.js`现在保存每次采样的currentSrc/src、尺寸、时间、readyState和paused,
|
||||
原判定不变。固定三次诊断都通过,不能覆盖旧失败或宣称间歇问题已修复。
|
||||
|
||||
## 后续与回退
|
||||
|
||||
专项只读lint、plan/risk-register生成与检查通过;风险/浏览器runner工程测试6通过,
|
||||
固定Node24.21.0/Yarn1.22.22严格工具链检查通过。git diff --check通过。没有为
|
||||
该测试改动重建生产包;上一步运行时、类型与分发文件保持原样。
|
||||
|
||||
更新包架构、维护说明和风险/进度,05仍doing。下一步是SDK9000后迟到广告的可控
|
||||
真实SDK复现与处置、历史首帧观测差异、物理iOS/Android验证及06分发。不能把这些
|
||||
环境门槛拖延其他依赖已满足的源码任务。没有修改用户VPN/浏览器保护,也未使用
|
||||
VAST脚本加载豁免。该检查点可独立回退;未push、未发布npm。
|
||||
+1
-1
@@ -602,7 +602,7 @@
|
||||
- PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md)
|
||||
- PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md) [记录](changes/2026-09-14-PKG-VAST-03-compatibility.md) [记录](baselines/vast-compatibility-validation.json)
|
||||
- PKG-VAST-04: [记录](changes/2026-09-14-PKG-VAST-04-types.md) [记录](baselines/vast-types-validation.json) [记录](vast-type-decision.md) [记录](vast-validation.md)
|
||||
- PKG-VAST-05: [记录](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md) [记录](baselines/vast-native-validation.json)
|
||||
- PKG-VAST-05: [记录](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md) [记录](baselines/vast-native-validation.json) [记录](changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md) [记录](baselines/vast-skip-validation.json)
|
||||
- PKG-CAST-01: [记录](baselines/chromecast-release.json) [记录](baselines/chromecast-contract.md) [记录](baselines/chromecast-contract-validation.json) [记录](changes/2026-09-13-PKG-CAST-01-contracts.md)
|
||||
- PKG-CAST-02: [记录](changes/2026-09-13-PKG-CAST-02-failures.md) [记录](baselines/chromecast-failures-validation.json)
|
||||
- PKG-CAST-03: [记录](changes/2026-09-13-PKG-CAST-03-runtime.md) [记录](baselines/chromecast-runtime-validation.json)
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-VAST-05 增补真实playUrl和SDK跳过按钮
|
||||
|
||||
真实HTTP标签、广告解码、跳过事件/按钮点击及主片恢复最终5/6通过;Chromium默认
|
||||
项虽完成跳过/恢复,因先出现SDK9000仍判失败。修复测试资源CORS与倒计时按钮
|
||||
误判,保留三轮失败,不修改生产代码。共享服务播放/切源/错误/Range回归12/12。
|
||||
旧WebKit失败trace确有广告画面;新增原始video采样后固定3次诊断通过,原失败
|
||||
仍未关闭。见[记录](changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md)和
|
||||
[证据](baselines/vast-skip-validation.json)。05保持doing,任务总数和完成数不变。
|
||||
|
||||
## PKG-VAST-05 真实 IMA 桌面验证检查点,仍进行中
|
||||
|
||||
新增独立`test:vast-native`,真实远端IMA3.789.0与本地广告媒体,不替换SDK。
|
||||
|
||||
+8
-4
@@ -777,11 +777,13 @@
|
||||
"refactor/vast-validation.md",
|
||||
"refactor/baselines/vast-behavior-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md",
|
||||
"refactor/baselines/vast-native-validation.json"
|
||||
"refactor/baselines/vast-native-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md",
|
||||
"refactor/baselines/vast-skip-validation.json"
|
||||
],
|
||||
"compatibleResolution": "@glomex/vast-ima-player loadImaSdk loads external IMA; preserve event/content/ad state and teardown, do not equate mocks with vendor service acceptance.",
|
||||
"closureCriteria": "固定 SDK/外部资源版本和环境;成功/失败/切换/销毁有真实证据,设备和网络限制逐项记录。",
|
||||
"workspaceState": "Real IMA3.789.0 executes with immutable npm1.0.0/candidate bundles: final27 desktop combinations22 passed5 failed; error303 recovery/recreation/active-ad destruction6 passed. Initial27 were23 passed4 failed and are preserved. SDK9000/late loading and historical WebKit ad-frame failures remain open. IAB SDK200 but bridge document ERR_BLOCKED_BY_CLIENT; physical devices/playUrl/skip not accepted. No VPN exception or timeout widening/retry-to-green."
|
||||
"workspaceState": "Real IMA3.789.0 executes with immutable npm1.0.0/candidate bundles: final27 desktop combinations22 passed5 failed; error303 recovery/recreation/active-ad destruction6 passed. Initial27 were23 passed4 failed and are preserved. SDK9000/late loading and historical WebKit ad-frame failures remain open. IAB SDK200 but bridge document ERR_BLOCKED_BY_CLIENT; physical devices/playUrl/skip not accepted. No VPN exception or timeout widening/retry-to-green. Native playUrl/IMA skip UI adds5/6 passes (one9000 failure despite later skip), shared server12/12 passes. Historical WebKit trace contains real ad frames; three fixed raw-media diagnostic runs passed without changing the assertion, so the original intermittent failure is not closed."
|
||||
},
|
||||
{
|
||||
"id": "SDK-08",
|
||||
@@ -3335,11 +3337,13 @@
|
||||
"refactor/changes/2026-09-14-PKG-VAST-03-compatibility.md",
|
||||
"refactor/baselines/vast-compatibility-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md",
|
||||
"refactor/baselines/vast-native-validation.json"
|
||||
"refactor/baselines/vast-native-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md",
|
||||
"refactor/baselines/vast-skip-validation.json"
|
||||
],
|
||||
"compatibleResolution": "Reproduce pending SDK/callback destruction, errors, duplicate IDs and stale ad events before adding compatible cleanup and state ownership.",
|
||||
"closureCriteria": "Tests prove cleanup during load/callback rejection/core destruction and distinguish explicit plugin recreation from terminal core destruction; vendor media restoration is separately verified.",
|
||||
"workspaceState": "Task03 controlled82 Node/162 browser checks remain valid; task05 adds6 real IMA303 recovery/recreation/active-ad core destruction passes across three engines/two modes. Native full combination failures, devices and remaining ad lifecycle paths keep this risk open; no claim of complete vendor/device acceptance."
|
||||
"workspaceState": "Task03 controlled82 Node/162 browser checks remain valid; task05 adds6 real IMA303 recovery/recreation/active-ad core destruction passes across three engines/two modes. Native full combination failures, devices and remaining ad lifecycle paths keep this risk open; no claim of complete vendor/device acceptance. Native playUrl/IMA skip UI adds5/6 passes (one9000 failure despite later skip), shared server12/12 passes. Historical WebKit trace contains real ad frames; three fixed raw-media diagnostic runs passed without changing the assertion, so the original intermittent failure is not closed."
|
||||
},
|
||||
{
|
||||
"id": "VAST-DIST-01",
|
||||
|
||||
+3
-1
@@ -3140,7 +3140,9 @@
|
||||
"acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成",
|
||||
"evidence": [
|
||||
"changes/2026-09-14-PKG-VAST-05-native-checkpoint.md",
|
||||
"baselines/vast-native-validation.json"
|
||||
"baselines/vast-native-validation.json",
|
||||
"changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md",
|
||||
"baselines/vast-skip-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -117,3 +117,11 @@ SDK清理由夹具在证据后显式补做,不能据DOM被核心移除就认
|
||||
广告播放中核心销毁。当前结果见[05检查点](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md):
|
||||
最终组合22/27,恢复6/6;SDK超时/迟到、旧插件首帧及真机未关闭。独立入口失败应
|
||||
保留为失败,不能用默认受控套件通过抵消,也不能为稳定CI添加宽泛skip。
|
||||
|
||||
`vast-skip.native.js`经真实HTTP调用playUrl,只允许IMA来源读取测试XML,验证响应
|
||||
原文/MIME/CORS及广告解码;等待SDK可跳过事件和可用按钮后点击,断言AdSkipped与
|
||||
主片恢复。SDK倒计时控件提前有Skip Ad名称,不能只靠名称和visible就点击。
|
||||
8秒生成视频配5秒跳过点;4秒/1秒素材未出现跳过状态的结果独立保留,不泛化。
|
||||
最终5/6(另1项9000失败)、共享服务12/12及固定WebKit诊断3/3见
|
||||
[增补记录](changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md)。媒体采样仅用于
|
||||
记录,未放宽原首帧断言;三次通过不能覆盖先前间歇失败。
|
||||
@@ -11,6 +11,7 @@ import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases
|
||||
import { performanceHtml, performanceScript } from '../../scripts/performance-fixture.mjs'
|
||||
import { getEntryFile } from '../../scripts/projects.js'
|
||||
import { getGlobalName, getViteBuildConfig } from '../../scripts/utils.js'
|
||||
import { skippableVast } from './vast-fixture.mjs'
|
||||
|
||||
const workspace = fileURLToPath(new URL('../../', import.meta.url))
|
||||
|
||||
@@ -94,7 +95,8 @@ add('/test/audio-tone.m4a', fs.readFileSync(path.join(workspace, 'test/browser/m
|
||||
add('/test/thumbnail-pattern.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/thumbnail-pattern.mp4')), { kind: 'generated-media', file: 'test/browser/media/thumbnail-pattern.mp4' })
|
||||
add('/test/auto-thumbnail-timeline.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/auto-thumbnail-timeline.mp4')), { kind: 'generated-media', file: 'test/browser/media/auto-thumbnail-timeline.mp4' })
|
||||
|
||||
const mime = { '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.json': 'application/json', '.css': 'text/css', '.mp4': 'video/mp4', '.m4a': 'audio/mp4', '.webm': 'video/webm', '.vtt': 'text/vtt', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.wasm': 'application/wasm', '.woff2': 'font/woff2' }
|
||||
const mime = { '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.json': 'application/json', '.xml': 'application/xml', '.css': 'text/css', '.mp4': 'video/mp4', '.m4a': 'audio/mp4', '.webm': 'video/webm', '.vtt': 'text/vtt', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.wasm': 'application/wasm', '.woff2': 'font/woff2' }
|
||||
add('/test/vast-skippable.xml', Buffer.from(skippableVast(`http://127.0.0.1:${port}`)), { kind: 'local-vast-fixture', file: 'test/browser/vast-fixture.mjs' })
|
||||
add('/test/declaration-cues.vtt', fs.readFileSync(path.join(workspace, 'test/browser/media/declaration-cues.vtt')), { kind: 'test-subtitles', file: 'test/browser/media/declaration-cues.vtt' })
|
||||
add('/test/thumbnail-grid.svg', fs.readFileSync(path.join(workspace, 'test/browser/media/thumbnail-grid.svg')), { kind: 'test-thumbnail-grid', file: 'test/browser/media/thumbnail-grid.svg' })
|
||||
add('/test/legacy-safe-area.js', fs.readFileSync(path.join(workspace, 'test/helpers/legacy-safe-area.js')), { kind: 'frozen-own-source', file: 'test/helpers/legacy-safe-area.js', commit: 'ccf77c4e' })
|
||||
@@ -170,6 +172,11 @@ const server = http.createServer((req, res) => {
|
||||
return
|
||||
}
|
||||
if (files.has(url.pathname)) {
|
||||
if (url.pathname === '/test/vast-skippable.xml' && ['http://imasdk.googleapis.com', 'https://imasdk.googleapis.com'].includes(req.headers.origin)) {
|
||||
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true')
|
||||
res.setHeader('Vary', 'Origin')
|
||||
}
|
||||
send(req, res, files.get(url.pathname), url.pathname)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
export function skippableVast(origin) {
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VAST version="3.0"><Ad id="artplayer-skippable"><InLine>
|
||||
<AdSystem version="1">ArtPlayer test fixture</AdSystem><AdTitle>Local skippable ad</AdTitle>
|
||||
<Impression><![CDATA[${origin}/assets/vast/nonlinear-320x50.png?tracking=impression]]></Impression>
|
||||
<Creatives><Creative><Linear skipoffset="00:00:05"><Duration>00:00:08</Duration>
|
||||
<TrackingEvents><Tracking event="skip"><![CDATA[${origin}/assets/vast/nonlinear-320x50.png?tracking=skip]]></Tracking></TrackingEvents>
|
||||
<MediaFiles><MediaFile delivery="progressive" type="video/mp4" width="320" height="180"><![CDATA[${origin}/test/pattern.mp4?skippable=1]]></MediaFile></MediaFiles>
|
||||
</Linear></Creative></Creatives></InLine></Ad></VAST>`
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import fs from 'node:fs'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.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')
|
||||
|
||||
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 page.evaluate(async (compatibility) => {
|
||||
window.createPlayer('/assets/sample/video.mp4')
|
||||
window.skipEvents = []
|
||||
await window.art.plugins.add(window.artplayerPluginVast((context) => {
|
||||
window.skipContext = context
|
||||
const player = context.init()
|
||||
for (const type of ['AdStarted', 'AdComplete', 'AdSkipped', 'AdSkippableStateChanged', 'AdContentPauseRequested', 'AdContentResumeRequested', 'AdError']) {
|
||||
player.addEventListener(type, event => window.skipEvents.push({ type, at: performance.now(), time: window.art.currentTime, paused: window.art.template.$video.paused, skipOffset: event.detail?.ad?.getSkipTimeOffset(), error: event.detail?.error?.message }))
|
||||
}
|
||||
}, compatibility ? { compatibility } : undefined))
|
||||
}, compatibility)
|
||||
await page.locator('#play').click()
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.5)
|
||||
await page.evaluate(() => {
|
||||
document.querySelector('#play').onclick = () => window.skipContext.playUrl(`${location.origin}/test/vast-skippable.xml`)
|
||||
})
|
||||
const beforeAd = await page.evaluate(() => window.art.currentTime)
|
||||
const responsePromise = page.waitForResponse(response => response.url().endsWith('/test/vast-skippable.xml'), { timeout: 7000 })
|
||||
await page.locator('#play').click()
|
||||
const response = await responsePromise
|
||||
expect(response.status()).toBe(200)
|
||||
expect(response.headers()['content-type']).toBe('application/xml')
|
||||
expect(['http://imasdk.googleapis.com', 'https://imasdk.googleapis.com']).toContain(response.headers()['access-control-allow-origin'])
|
||||
const xml = await response.text()
|
||||
expect(xml).toBe(skippableVast(new URL(page.url()).origin))
|
||||
await testInfo.attach('native-vast-skip.xml', { contentType: 'application/xml', body: xml })
|
||||
await expect.poll(() => page.evaluate(() => window.skipEvents.some(event => event.type === 'AdStarted'))).toBe(true)
|
||||
await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/test/pattern.mp4?skippable=1') && video.videoWidth > 0 && video.currentTime > 0))).toBe(true)
|
||||
expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(true)
|
||||
await testInfo.attach('native-vast-before-skip.png', { contentType: 'image/png', body: await page.screenshot() })
|
||||
await expect.poll(() => page.evaluate(() => window.skipEvents.some(event => event.type === 'AdSkippableStateChanged'))).toBe(true)
|
||||
let skipButton
|
||||
await expect.poll(async () => {
|
||||
for (const frame of page.frames()) {
|
||||
const button = frame.getByRole('button', { name: /skip ad/i })
|
||||
if (await button.count() === 1 && await button.isVisible() && await button.isEnabled()) {
|
||||
skipButton = button
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}).toBe(true)
|
||||
await testInfo.attach('native-vast-skip-button.png', { contentType: 'image/png', body: await page.screenshot() })
|
||||
await skipButton.click()
|
||||
await expect.poll(() => page.evaluate(() => window.skipEvents.filter(event => event.type === 'AdSkipped').length)).toBe(1)
|
||||
await expect.poll(() => page.evaluate(() => window.skipEvents.some(event => event.type === 'AdContentResumeRequested'))).toBe(true)
|
||||
await expect(page.locator('[id^="art-"]')).toBeHidden()
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.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 page.evaluate(() => window.art.destroy())
|
||||
await expect(page.locator('[id^="art-"]')).toHaveCount(0)
|
||||
})
|
||||
}
|
||||
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
await testInfo.attach('native-vast-skip-final', { contentType: 'application/json', body: JSON.stringify(await page.evaluate(() => ({ events: window.skipEvents, imaVersion: window.google?.ima?.VERSION, videos: [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, time: video.currentTime, width: video.videoWidth, paused: video.paused })) }))) })
|
||||
for (const [index, frame] of page.frames().entries()) {
|
||||
if (frame !== page.mainFrame())
|
||||
await testInfo.attach(`native-vast-frame-${index}`, { contentType: 'text/plain', body: await frame.locator('body').ariaSnapshot().catch(error => String(error)) })
|
||||
}
|
||||
await page.evaluate(() => window.art?.destroy())
|
||||
})
|
||||
@@ -17,6 +17,7 @@ test.afterEach(async ({ page }, testInfo) => {
|
||||
error: window.nativeVastError,
|
||||
imaVersion: window.google?.ima?.VERSION,
|
||||
events: window.nativeVastEvents,
|
||||
mediaSamples: window.nativeVastMediaSamples,
|
||||
videos: [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, time: video.currentTime, duration: video.duration, width: video.videoWidth, height: video.videoHeight, paused: video.paused, ended: video.ended })),
|
||||
containerConnected: window.nativeVastContext?.container?.isConnected,
|
||||
coreVersion: window.Artplayer?.version,
|
||||
@@ -41,6 +42,7 @@ for (const core of ['published-5.1.7', 'published', 'candidate']) {
|
||||
await page.evaluate(({ compatibility, historical }) => {
|
||||
window.nativeVastHistorical = historical
|
||||
window.nativeVastEvents = []
|
||||
window.nativeVastMediaSamples = []
|
||||
window.nativeVastRegistration = 'pending'
|
||||
window.createPlayer('/assets/sample/video.mp4')
|
||||
const factory = window.artplayerPluginVast.default || window.artplayerPluginVast
|
||||
@@ -81,7 +83,11 @@ for (const core of ['published-5.1.7', 'published', 'candidate']) {
|
||||
await page.locator('#play').click()
|
||||
await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdStarted'))).toBe(true)
|
||||
await expect(page.locator('[id^="art-"]')).toBeVisible()
|
||||
await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/assets/vast/linear-video.mp4') && video.videoWidth > 0 && video.videoHeight > 0 && video.currentTime > 0))).toBe(true)
|
||||
await expect.poll(() => page.evaluate(() => {
|
||||
const videos = [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, declaredSrc: video.src, width: video.videoWidth, height: video.videoHeight, time: video.currentTime, readyState: video.readyState, paused: video.paused }))
|
||||
window.nativeVastMediaSamples.push({ at: performance.now(), videos })
|
||||
return videos.some(video => video.src.includes('/assets/vast/linear-video.mp4') && video.width > 0 && video.height > 0 && video.time > 0)
|
||||
})).toBe(true)
|
||||
const decodedAd = await page.evaluate(() => [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, width: video.videoWidth, height: video.videoHeight, time: video.currentTime })).filter(video => video.src.includes('/assets/vast/linear-video.mp4')))
|
||||
expect(decodedAd.some(video => video.width > 0 && video.height > 0)).toBe(true)
|
||||
expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(true)
|
||||
|
||||
Reference in new issue
Block a user