mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -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
@@ -134,3 +134,29 @@ 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.
|
||||
|
||||
## Complete installed bundles
|
||||
|
||||
The shared `yarn test:package --browser` roster includes VAST. Its checked
|
||||
archive retains the real npm 1.0.0 dist/type paths; the same-name contract also
|
||||
verifies the frozen SDK archives. Generic package runtime/type fixtures still
|
||||
cover core/chapter only. Use the separate VAST type consumers for VAST claims.
|
||||
|
||||
`vast-package.spec.js` uses `browserCandidate()` to select a normal source build
|
||||
or the verified installed UMD, including the actual glomex implementation. It
|
||||
holds/aborts native SDK script requests to verify concurrent load rejection,
|
||||
fresh attempts and listener cleanup. A second case destroys the host before
|
||||
fulfilling the script with an inert readiness sentinel, which intentionally has
|
||||
no IMA player APIs: late construction or callbacks must not run. Main content
|
||||
still decodes after SDK failure. These are loader/lifetime tests, not Google IMA
|
||||
ad playback; `vast.spec.js` remains a separate controlled SDK boundary suite.
|
||||
|
||||
`yarn test:vast-native` defaults to the existing source build. With
|
||||
`ARTPLAYER_BROWSER_ARTIFACTS` set, its config requires verified core, Chapter and
|
||||
VAST installations, and all three native test files load the complete installed
|
||||
bundle. They preserve real remote IMA, published plugin controls, timeouts and
|
||||
zero retries. Input provenance is attached before SDK initialization, including
|
||||
for tests that fail before ad playback. This optional integration run stays
|
||||
outside normal PR checks. See the
|
||||
[installed VAST record](../../refactor/changes/2026-09-15-CI-01-vast-installed.md)
|
||||
for actual results and the remaining external SDK/device/distribution gates.
|
||||
@@ -1,9 +1,10 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import process from 'node:process'
|
||||
import { defineConfig } from '@playwright/test'
|
||||
import base from './playwright.config.js'
|
||||
import { verifyInstalledArtifacts } from './scripts/installed-artifacts.mjs'
|
||||
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Native VAST source validation does not accept unrelated artifact maps')
|
||||
if (process.env.ARTPLAYER_BROWSER_ARTIFACTS)
|
||||
verifyInstalledArtifacts(process.cwd(), process.env.ARTPLAYER_BROWSER_ARTIFACTS, ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-vast'])
|
||||
export default defineConfig(base, {
|
||||
testMatch: ['**/vast.native.js', '**/vast-recovery.native.js', '**/vast-skip.native.js'],
|
||||
timeout: 30000,
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "CI-01",
|
||||
"date": "2026-09-15",
|
||||
"sourceHead": "ce67eaa73ec177b23de9a4c7e27ba99fdf458ae9",
|
||||
"candidate": "Working tree included in the accompanying CI-01 complete VAST bundle checkpoint; code fingerprints normalize LF",
|
||||
"environment": {
|
||||
"node": "24.21.0",
|
||||
"yarn": "1.22.22",
|
||||
"platform": "win32"
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"file": "scripts/package-check.mjs",
|
||||
"sha256LF": "61529f6d109d6581ead9f32883b4082a02cd00c9bc6c396b1339a8c30530de09"
|
||||
},
|
||||
{
|
||||
"file": "scripts/browser-validation/scope.ts",
|
||||
"sha256LF": "746f751b2e1c40f7f2f5a8aafd40ff9c47066fc5716984d2feeda167ecfc41fc"
|
||||
},
|
||||
{
|
||||
"file": "playwright.vast-native.config.js",
|
||||
"sha256LF": "c1b8f0db85602adc6eda12460af1b0740ad380abceb59d565f12bbbf39ed7135"
|
||||
},
|
||||
{
|
||||
"file": "test/browser-validation.test.js",
|
||||
"sha256LF": "08b2772f18adc640adce948d00e9de64cb18e5e4f4135286ec62971521f2331f"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/vast-package.spec.js",
|
||||
"sha256LF": "60fad56473db0b3c7bc062342ced578d9176ab0f449c871dc5a2a54b001c9888"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/vast.native.js",
|
||||
"sha256LF": "9141ecf01a3c8474225c750f3024f2bbd1222bc6fa0b6446d8fa183680d294a5"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/vast-recovery.native.js",
|
||||
"sha256LF": "4c1969596742b72b04ad505175073bed5802ac1420922128fd0e1ddcceb11804"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/vast-skip.native.js",
|
||||
"sha256LF": "cfad59626989094aa92e40d4282d410c4596bf21dd2c908923992a9414b2fb4e"
|
||||
}
|
||||
],
|
||||
"packages": {
|
||||
"directory": "refactor/.cache/packages/run-yqnfgx",
|
||||
"reportSha256": "ea83dc2b4e3f66a247e1e700a4115ec0231e97ab2984c74593aef10c1e49f463",
|
||||
"count": 20,
|
||||
"names": [
|
||||
"artplayer",
|
||||
"artplayer-plugin-chapter",
|
||||
"artplayer-plugin-ambilight",
|
||||
"artplayer-proxy-canvas",
|
||||
"artplayer-plugin-document-pip",
|
||||
"artplayer-plugin-ads",
|
||||
"artplayer-plugin-audio-track",
|
||||
"artplayer-plugin-vtt-thumbnail",
|
||||
"artplayer-plugin-multiple-subtitles",
|
||||
"artplayer-plugin-hls-control",
|
||||
"artplayer-plugin-dash-control",
|
||||
"artplayer-plugin-auto-thumbnail",
|
||||
"artplayer-plugin-asr",
|
||||
"artplayer-plugin-chromecast",
|
||||
"artplayer-proxy-mediabunny",
|
||||
"artplayer-plugin-jassub",
|
||||
"artplayer-plugin-danmuku",
|
||||
"artplayer-plugin-danmuku-mask",
|
||||
"artplayer-tool-iframe",
|
||||
"artplayer-plugin-vast"
|
||||
],
|
||||
"vast": {
|
||||
"name": "artplayer-plugin-vast",
|
||||
"version": "1.2.0",
|
||||
"archive": "artplayer-plugin-vast.tgz",
|
||||
"sha256": "e765c2809cec4494d62811c9d2cd96ea8a3091e4cc75162ece31586b95f5f2d7",
|
||||
"files": {
|
||||
"package/ARCHITECTURE.md": "918c8f66ed6010c0b2fb8ca70ccc62101fcc126962829347eb3718242375d0f3",
|
||||
"package/README.md": "7ec086f19c899e315efcb136e037a02d951b0395d5f0ce239817be87ea4ab4e6",
|
||||
"package/dist/artplayer-plugin-vast.js": "cebaf6a44f80079841205498c4f855ba4e5c804ae7958c06eadda524d728e079",
|
||||
"package/dist/artplayer-plugin-vast.legacy.js": "8ebb4ebdd4c0fc5ddc467d5ee15b18ab7e5c078c15bbfd37dc33aa89eac1de92",
|
||||
"package/dist/artplayer-plugin-vast.mjs": "a63e6e8b27032ea690fe740e9ec0a98646346f1fcd3622740f1f5363f234a72b",
|
||||
"package/package.json": "d359f65c20ca85939a15d4502fdafd6258401aa4a3e421314e1275fe7102826e",
|
||||
"package/types/artplayer-plugin-vast.d.ts": "51257361f482f026a9b5ba84ca85d320d9e1457a34d0d259ac3c7b46c4fbd29c",
|
||||
"package/types/runtime-api.d.ts": "4634b65f2d1bbd6973a40390f3217251b69fc5167198a8409d9fed48500e106d",
|
||||
"package/types/runtime.d.cts": "cead9984e0e2644e67cc687380ed40aed0d561b9d6f9636bea3b98d71522b13e",
|
||||
"package/types/runtime.d.mts": "5abf25cba3dfaaea2652c0d3721f58ad243eb4d3a2fef80f5d27eb978973b586",
|
||||
"package/types/runtime.d.ts": "cead9984e0e2644e67cc687380ed40aed0d561b9d6f9636bea3b98d71522b13e"
|
||||
}
|
||||
},
|
||||
"wallSeconds": 113.47,
|
||||
"exitCode": 0,
|
||||
"genericConsumerScope": [
|
||||
"artplayer",
|
||||
"artplayer-plugin-chapter"
|
||||
]
|
||||
},
|
||||
"collection": {
|
||||
"directory": "refactor/.cache/ci01-vast-collection-report",
|
||||
"reportSha256": "98f1803d4c78173a843e35f3be2889253469fb7bdbcce9f02da93e23849b0b5a",
|
||||
"count": 2442,
|
||||
"files": 73,
|
||||
"collectionOnly": true
|
||||
},
|
||||
"source": {
|
||||
"directory": "refactor/.cache/ci01-vast-source-report",
|
||||
"reportSha256": "a2e75d564fbd87c467aef377e5c486e5db983633ee816f8575dcf4797607e8ea",
|
||||
"invocation": {
|
||||
"scope": "source",
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"vast-package.spec.js",
|
||||
"--workers=2"
|
||||
],
|
||||
"node": "24.21.0",
|
||||
"artifactMap": null,
|
||||
"installedPackages": 0
|
||||
},
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"vast-package.spec.js",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T20:39:43.739Z",
|
||||
"duration": 25485.434999999998,
|
||||
"expected": 36,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"counts": {
|
||||
"chromium/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"firefox/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"webkit/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"browserVersions": {
|
||||
"chromium": "153.0.8010.12",
|
||||
"firefox": "155.0",
|
||||
"webkit": "26.6"
|
||||
},
|
||||
"sdkVersions": [],
|
||||
"identityCounts": {
|
||||
"chromium/source-build": 12,
|
||||
"firefox/source-build": 12,
|
||||
"webkit/source-build": 12
|
||||
},
|
||||
"failures": [],
|
||||
"invocationSha256": "28d87cf83591b7927e472c05ddd2422b4a7f93d2af69845b6b53cbbe1768d2d7"
|
||||
},
|
||||
"installed": {
|
||||
"directory": "refactor/.cache/ci01-vast-installed-report",
|
||||
"reportSha256": "a0b7608243bee0371a0d0de83fba648c10fa6b0ee5eb3a06debde84016973b42",
|
||||
"invocation": {
|
||||
"scope": "installed",
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.installed.config.js",
|
||||
"vast-package.spec.js",
|
||||
"--workers=2"
|
||||
],
|
||||
"node": "24.21.0",
|
||||
"artifactMap": "D:\\github\\ArtPlayer\\refactor\\.cache\\packages\\run-yqnfgx\\browser-artifacts.json",
|
||||
"installedPackages": 20
|
||||
},
|
||||
"result": {
|
||||
"scope": "installed",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.installed.config.js",
|
||||
"vast-package.spec.js",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T20:42:41.950Z",
|
||||
"duration": 23818.322999999997,
|
||||
"expected": 36,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"counts": {
|
||||
"chromium/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"firefox/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"webkit/vast-package.spec.js": {
|
||||
"expected": 12,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"browserVersions": {
|
||||
"chromium": "153.0.8010.12",
|
||||
"firefox": "155.0",
|
||||
"webkit": "26.6"
|
||||
},
|
||||
"sdkVersions": [],
|
||||
"identityCounts": {
|
||||
"chromium/installed": 12,
|
||||
"firefox/installed": 12,
|
||||
"webkit/installed": 12
|
||||
},
|
||||
"failures": [],
|
||||
"invocationSha256": "4284fe5664b42cc83055f595a22f0ccb452fe9a44981bcc2f79430f5d7816dfc"
|
||||
},
|
||||
"native": {
|
||||
"directory": "refactor/.cache/ci01-vast-native-report",
|
||||
"reportSha256": "e65f83cc260088fcb62f9b05795991c7734b74e5d05ad3d0cc190f15461dc788",
|
||||
"invocation": {
|
||||
"scope": "installed-native",
|
||||
"command": "yarn test:vast-native",
|
||||
"head": "ce67eaa73ec177b23de9a4c7e27ba99fdf458ae9",
|
||||
"startedAt": "2026-09-14T20:44:01.4909743Z",
|
||||
"artifactMap": "D:\\github\\ArtPlayer\\refactor\\.cache\\packages\\run-yqnfgx\\browser-artifacts.json"
|
||||
},
|
||||
"result": {
|
||||
"exitCode": 0,
|
||||
"finishedAt": "2026-09-14T20:48:44.1700556Z"
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T20:44:02.273Z",
|
||||
"duration": 281695.31499999994,
|
||||
"expected": 39,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"counts": {
|
||||
"chromium/vast-recovery.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"firefox/vast-recovery.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"webkit/vast-recovery.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"chromium/vast-skip.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"firefox/vast-skip.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"webkit/vast-skip.native.js": {
|
||||
"expected": 2,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"chromium/vast.native.js": {
|
||||
"expected": 9,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"firefox/vast.native.js": {
|
||||
"expected": 9,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"webkit/vast.native.js": {
|
||||
"expected": 9,
|
||||
"unexpected": 0,
|
||||
"skipped": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"browserVersions": {
|
||||
"chromium": "153.0.8010.12",
|
||||
"firefox": "155.0",
|
||||
"webkit": "26.6"
|
||||
},
|
||||
"sdkVersions": [
|
||||
"3.789.0"
|
||||
],
|
||||
"identityCounts": {
|
||||
"chromium/installed": 10,
|
||||
"firefox/installed": 10,
|
||||
"webkit/installed": 10,
|
||||
"chromium/published": 3,
|
||||
"firefox/published": 3,
|
||||
"webkit/published": 3
|
||||
},
|
||||
"failures": []
|
||||
},
|
||||
"verification": {
|
||||
"tests": {
|
||||
"passed": 94,
|
||||
"failed": 0,
|
||||
"durationMs": 3676.2619,
|
||||
"log": "refactor/.cache/ci01-vast-tests.log",
|
||||
"logSha256": "aeae1681eef5ab7b20fead22cf3f8a15cc0ebf84025735555abc1cd8b1a2e542"
|
||||
},
|
||||
"lint": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-lint-complete.log",
|
||||
"logSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"libraryTypes": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-library-types.log",
|
||||
"logSha256": "647c339f0e832948a0fc7393cfeb4ff4e677c8df7b449abbdf3f519523fd782c"
|
||||
},
|
||||
"docsTypes": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-docs-types.log",
|
||||
"logSha256": "6dc9f3b0cbfb35e5b93dc8c9ec04cd2d64146a65c7f581614bcb289777b56795"
|
||||
},
|
||||
"ci": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-ci.log",
|
||||
"logSha256": "ae8f7eb4d69bd9bdded1bfd024dbc81778a9f5746ea59e8348416ee5f4117fd8"
|
||||
},
|
||||
"toolchain": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-toolchain.log",
|
||||
"logSha256": "e826888421079163997eb19d528152df86b03b7d0507877e099e569b461814fb"
|
||||
},
|
||||
"impact": {
|
||||
"exitCode": 0,
|
||||
"log": "refactor/.cache/ci01-vast-impact.log",
|
||||
"logSha256": "4aaebfd09336848065473b9db6e05b17da44d5810422144e0a5ac7341155089d"
|
||||
}
|
||||
},
|
||||
"limitations": [
|
||||
"The PR loader suite uses the complete glomex bundle but controls network failure/readiness. Its sentinel has no IMA player API and is not advertising playback.",
|
||||
"The original vast.spec.js continues to substitute glomex and is not represented as installed complete-bundle coverage.",
|
||||
"Only the separate native run uses the real remote IMA SDK. Current successful runs do not close earlier intermittent SDK9000 or historical WebKit first-frame failures.",
|
||||
"Published plugin controls retain frozen npm1.0.0 bytes; their existing fixture explicitly cleans up SDK resources after observation.",
|
||||
"Generic pack runtime/type consumers remain core/chapter only. VAST root/legacy/runtime installed type compatibility was separately verified in PKG-VAST-04.",
|
||||
"No physical-device evidence, remote CI run, full ecosystem acceptance, publication, or closure of CI-01/PKG-VAST-05."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# CI-01 VAST 完整安装包与真实 IMA 验证
|
||||
|
||||
## 实现范围
|
||||
|
||||
接续 `ce67eaa73ec177b23de9a4c7e27ba99fdf458ae9`。统一 browser 安装清单加入
|
||||
VAST,正常构建/pack/隔离安装二十包;校验真实 npm 1.0.0 的 dist/types 路径
|
||||
和冻结 SDK 归档。没有修改生产源码、公开接口/声明、依赖版本或 npm 入口。
|
||||
|
||||
原 `vast.spec.js` 通过替换 glomex 验证插件逻辑,继续作为源码范围的受控测试。
|
||||
新增 `vast-package.spec.js` 加载完整普通构建,包括真实 glomex 实现,分别在
|
||||
三代核心、两种兼容模式、三个引擎下验证两个边界:
|
||||
|
||||
- 两个并发注册共享一次真实 script 请求;网络失败传递同一个原生 error Event,
|
||||
两个注册均拒绝、各自释放 destroy listener、回调不执行。新注册产生第二次
|
||||
SDK 请求,失败后仍释放监听;主片继续实际解码和播放。
|
||||
- SDK 请求尚未完成时销毁核心,然后返回只含 readiness 标记的脚本。这个哨兵
|
||||
没有 IMA 播放器 API,迟到的结果不能创建 session 或调用用户回调。
|
||||
|
||||
这些是完整 glomex 的加载/销毁验证;受控网络和哨兵不计为 Google 广告播放。
|
||||
两种模式继续使用同一个完整包,已批准的 npm 默认与 workspace-1.2 行为保留。
|
||||
|
||||
独立 `test:vast-native` 默认仍构建源码;显式给出安装 map 后,config 核验核心、
|
||||
Chapter、VAST 文件及构建新鲜度,三份 native 测试直接加载安装 UMD。真实旧 npm
|
||||
插件仍使用固定归档。初始化前附加来源,失败在播放之前发生时也能核对候选。
|
||||
没有替换 AdsLoader/AdsManager、修改 SDK 超时、添加重试或把 native 测试移入
|
||||
普通 PR 的受控范围。
|
||||
|
||||
## 实测
|
||||
|
||||
Windows、Node 24.21.0、Yarn 1.22.22;Chromium 153.0.8010.12、Firefox
|
||||
155.0、WebKit 26.6;本轮真实 Google IMA 为 3.789.0。原始报告目录、输入摘要、
|
||||
逐文件结果和源码/安装/历史身份见
|
||||
[机器证据](../baselines/ci-vast-installed-validation.json)。
|
||||
|
||||
| 检查 | 实际结果 |
|
||||
| --- | --- |
|
||||
| `yarn test:package --browser` | 二十包正常构建/打包/隔离安装/离线冻结复装通过;run-yqnfgx,113.47 秒 |
|
||||
| installed 全量 collection | 73 文件、2,442 项;仅清单收集,不是全量运行 |
|
||||
| source 完整 SDK 加载边界 | 36/36,25,485.435 ms,三个引擎各 12 项 |
|
||||
| installed 完整 SDK 加载边界 | 36/36,23,818.323 ms,三个引擎各 12 项 |
|
||||
| installed-map 真实 IMA 专项 | 39/39,281,695.315 ms;零失败、skip、flaky 或重试 |
|
||||
| 单元/工程检查 | 94/94,3,676.2619 ms,包含原 VAST 导出/兼容/生命周期回归和 native 配置的无 map/坏 map 验证 |
|
||||
| 静态检查 | 改动文件只读 ESLint、library/docs-tools 严格类型、CI/影响范围和固定工具链通过 |
|
||||
|
||||
真实专项包含三个引擎各 13 项:三代核心 × 两种候选模式和一个历史插件共
|
||||
9 项播放/主片恢复,加 2 项真实 303 恢复/重建/活跃广告销毁、2 项 playUrl/SDK
|
||||
跳过按钮。全组 30 个安装候选、9 个历史对照,每个引擎分别 10/3;候选均附带
|
||||
核验过的安装身份。实际广告解码、SDK 事件顺序、点击可用的跳过按钮和恢复主片
|
||||
仍由原断言判定。本轮加载正常,没有启用用户许可的 VPN/脚本加载跳过例外。
|
||||
|
||||
这次 native 全组通过是本次安装候选证据,不是对过去间歇 SDK9000/迟到广告和
|
||||
旧插件 WebKit 首帧失败的生产修复。旧报告和开放风险保留;没有循环执行相同
|
||||
失败直到变绿。加载边界的首次 lint 两个多语句行已格式修正,原 lint 日志保留。
|
||||
|
||||
通用 pack 中 36 运行时、5 旧类型、8 精确类型模式仍仅覆盖 core/Chapter;VAST
|
||||
自己的根/legacy/runtime 十四组安装类型证据继续引用 PKG-VAST-04,不虚报为
|
||||
本次全包类型重跑。源码加载测试的 map 为 null;安装加载和 native 专项分别
|
||||
核验同一 run-yqnfgx 的完整 UMD,不使用外部化 glomex 的测试构建。
|
||||
|
||||
## 重跑和剩余工作
|
||||
|
||||
先执行 test:package --browser,设置其 ARTPLAYER_BROWSER_ARTIFACTS,然后运行
|
||||
`yarn test:browser:installed vast-package.spec.js --workers=2` 和独立的
|
||||
`yarn test:vast-native`。后者包含真实远端依赖;移除 map 才回到原源码模式。
|
||||
源码对照使用 `yarn test:browser:source vast-package.spec.js --workers=2`。
|
||||
三个入口保持各自报告目录,重跑前先归档旧证据。此次原始报告已在进程终态后
|
||||
归档为 `refactor/.cache/ci01-vast-{source,installed,native,collection}-report`;
|
||||
native 的实际调用/退出记录另存同前缀 invocation/result JSON。
|
||||
|
||||
CI-01、PKG-VAST-05 仍 doing;197/263 完成不变。物理 iOS/Android、SDK 间歇
|
||||
行为、完整分发/远端 CI 与发布复盘仍未完成。工作区保持已批准的公开兼容边界,
|
||||
没有发布、部署、推送或修改浏览器/VPN 设置。代码、测试、架构和证据随独立
|
||||
CI-01 本地提交,随后运行提交审计。
|
||||
@@ -1,5 +1,9 @@
|
||||
# PR 检查和 Pages 操作说明
|
||||
|
||||
最新统一安装清单含二十包。VAST 的完整 glomex 加载边界进入普通 installed
|
||||
范围;真实 IMA 仍由独立 test:vast-native 按显式安装 map 验证,本地 39/39
|
||||
通过不表示远端 CI 已覆盖真实广告。见[记录](changes/2026-09-15-CI-01-vast-installed.md)。
|
||||
|
||||
浏览器CI现在分别执行 `yarn test:browser:source` 和
|
||||
`yarn test:browser:installed`。前者清除继承的安装map并保留全部spec;后者要求已
|
||||
核验的统一包清单,执行明确列出的 installed 子集;清单维护在
|
||||
|
||||
+2
-2
@@ -509,7 +509,7 @@
|
||||
- ENG-09: [记录](changes/2026-09-12-ENG-09-integration.md) [记录](baselines/engineering-integration.json)
|
||||
- ENG-10: [记录](changes/2026-09-10-ENG-10-test-reliability.md) [记录](test-reliability.md)
|
||||
- ENG-11: [记录](build-analysis.md) [记录](baselines/bundle-attribution.json) [记录](changes/2026-09-11-ENG-11-build-analysis.md)
|
||||
- CI-01: [记录](ci-setup.md) [记录](changes/2026-09-13-CI-01-matrix-summary.md) [记录](baselines/ci-matrix-validation.json) [记录](changes/2026-09-13-CI-01-node-consumers.md) [记录](baselines/node-consumer-validation.json) [记录](changes/2026-09-14-CI-01-installed-full.md) [记录](baselines/ci-installed-full-validation.json) [记录](changes/2026-09-14-CI-01-source-chromium.md) [记录](baselines/ci-source-chromium-validation.json) [记录](changes/2026-09-15-CI-01-ads-installed.md) [记录](baselines/ci-ads-installed-validation.json) [记录](changes/2026-09-15-CI-01-subtitles-installed.md) [记录](baselines/ci-subtitles-installed-validation.json) [记录](changes/2026-09-15-CI-01-adaptive-installed.md) [记录](baselines/ci-adaptive-installed-validation.json) [记录](changes/2026-09-15-CI-01-asr-cast-installed.md) [记录](baselines/ci-asr-cast-installed-validation.json) [记录](changes/2026-09-15-CI-01-mediabunny-installed.md) [记录](baselines/ci-mediabunny-installed-validation.json) [记录](changes/2026-09-15-CI-01-jassub-installed.md) [记录](baselines/ci-jassub-installed-validation.json) [记录](changes/2026-09-15-CI-01-danmuku-installed.md) [记录](baselines/ci-danmuku-installed-validation.json) [记录](changes/2026-09-15-CI-01-browser-matrix.md) [记录](baselines/ci-browser-matrix-validation.json) [记录](changes/2026-09-15-CI-01-iframe-installed.md) [记录](baselines/ci-iframe-installed-validation.json)
|
||||
- CI-01: [记录](ci-setup.md) [记录](changes/2026-09-13-CI-01-matrix-summary.md) [记录](baselines/ci-matrix-validation.json) [记录](changes/2026-09-13-CI-01-node-consumers.md) [记录](baselines/node-consumer-validation.json) [记录](changes/2026-09-14-CI-01-installed-full.md) [记录](baselines/ci-installed-full-validation.json) [记录](changes/2026-09-14-CI-01-source-chromium.md) [记录](baselines/ci-source-chromium-validation.json) [记录](changes/2026-09-15-CI-01-ads-installed.md) [记录](baselines/ci-ads-installed-validation.json) [记录](changes/2026-09-15-CI-01-subtitles-installed.md) [记录](baselines/ci-subtitles-installed-validation.json) [记录](changes/2026-09-15-CI-01-adaptive-installed.md) [记录](baselines/ci-adaptive-installed-validation.json) [记录](changes/2026-09-15-CI-01-asr-cast-installed.md) [记录](baselines/ci-asr-cast-installed-validation.json) [记录](changes/2026-09-15-CI-01-mediabunny-installed.md) [记录](baselines/ci-mediabunny-installed-validation.json) [记录](changes/2026-09-15-CI-01-jassub-installed.md) [记录](baselines/ci-jassub-installed-validation.json) [记录](changes/2026-09-15-CI-01-danmuku-installed.md) [记录](baselines/ci-danmuku-installed-validation.json) [记录](changes/2026-09-15-CI-01-browser-matrix.md) [记录](baselines/ci-browser-matrix-validation.json) [记录](changes/2026-09-15-CI-01-iframe-installed.md) [记录](baselines/ci-iframe-installed-validation.json) [记录](changes/2026-09-15-CI-01-vast-installed.md) [记录](baselines/ci-vast-installed-validation.json)
|
||||
- CI-02: [记录](changes/2026-09-14-CI-02-pages-artifact.md) [记录](baselines/pages-artifact-validation.json) [记录](pages-deployment.md)
|
||||
- PILOT-01: [记录](changes/2026-09-10-PILOT-01-chapter.md) [记录](baselines/pilot-validation.json)
|
||||
- CORE-01: [记录](changes/2026-09-10-CORE-01-typed-utils.md) [记录](baselines/core-utils-validation.json)
|
||||
@@ -603,7 +603,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) [记录](changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md) [记录](baselines/vast-skip-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) [记录](changes/2026-09-15-CI-01-vast-installed.md) [记录](baselines/ci-vast-installed-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 @@
|
||||
# 进度与证据
|
||||
|
||||
## CI-01 VAST 完整安装包与真实 IMA
|
||||
|
||||
二十包安装准备通过。VAST 完整 glomex 加载边界在源码、安装范围各 36/36;
|
||||
真实 IMA 3.789.0 专项 39/39(30 安装候选、9 历史对照),三个引擎均无失败/
|
||||
跳过/重试,覆盖播放、303 恢复、重建、活跃广告销毁与真实跳过按钮。单元/工程
|
||||
94/94,见[记录](changes/2026-09-15-CI-01-vast-installed.md)。完整 installed
|
||||
清单现为 73 文件/2,442 项,本轮未全跑。197/263 完成;CI-01/VAST-05 仍 doing,
|
||||
以前的间歇失败、物理设备、其余分发和远端 CI 门槛保留。
|
||||
|
||||
## CI-01 Iframe 安装包与真实跨窗口组合
|
||||
|
||||
统一清单现含十九包,保留 Iframe 真实旧 npm 包与冻结 tool 工作区的不同身份。
|
||||
|
||||
+8
-4
@@ -779,11 +779,13 @@
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md",
|
||||
"refactor/baselines/vast-native-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md",
|
||||
"refactor/baselines/vast-skip-validation.json"
|
||||
"refactor/baselines/vast-skip-validation.json",
|
||||
"refactor/changes/2026-09-15-CI-01-vast-installed.md",
|
||||
"refactor/baselines/ci-vast-installed-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. 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."
|
||||
"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. CI-01 complete installed bundle checkpoint: source/installed native-script loader and cancellation controls each36/36; real remote IMA3.789.0 across three desktop engines39/39 (30 installed candidate,9 published controls), including303 recovery/recreation/active-ad destroy and actual skip UI. No retries/skips or VPN exception. This new successful run does not close earlier intermittent9000/late-ad/historical WebKit observations, physical-device or full distribution gates."
|
||||
},
|
||||
{
|
||||
"id": "SDK-08",
|
||||
@@ -3350,11 +3352,13 @@
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md",
|
||||
"refactor/baselines/vast-native-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md",
|
||||
"refactor/baselines/vast-skip-validation.json"
|
||||
"refactor/baselines/vast-skip-validation.json",
|
||||
"refactor/changes/2026-09-15-CI-01-vast-installed.md",
|
||||
"refactor/baselines/ci-vast-installed-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. 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."
|
||||
"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. CI-01 complete installed bundle checkpoint: source/installed native-script loader and cancellation controls each36/36; real remote IMA3.789.0 across three desktop engines39/39 (30 installed candidate,9 published controls), including303 recovery/recreation/active-ad destroy and actual skip UI. No retries/skips or VPN exception. This new successful run does not close earlier intermittent9000/late-ad/historical WebKit observations, physical-device or full distribution gates."
|
||||
},
|
||||
{
|
||||
"id": "VAST-DIST-01",
|
||||
|
||||
+6
-2
@@ -780,7 +780,9 @@
|
||||
"changes/2026-09-15-CI-01-browser-matrix.md",
|
||||
"baselines/ci-browser-matrix-validation.json",
|
||||
"changes/2026-09-15-CI-01-iframe-installed.md",
|
||||
"baselines/ci-iframe-installed-validation.json"
|
||||
"baselines/ci-iframe-installed-validation.json",
|
||||
"changes/2026-09-15-CI-01-vast-installed.md",
|
||||
"baselines/ci-vast-installed-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -3163,7 +3165,9 @@
|
||||
"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"
|
||||
"baselines/vast-skip-validation.json",
|
||||
"changes/2026-09-15-CI-01-vast-installed.md",
|
||||
"baselines/ci-vast-installed-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -109,7 +109,10 @@ Google的[AdsRequest接口](https://developers.google.com/interactive-media-ads/
|
||||
广告解码截图、主片播放位置及事件;远端SDK版本会变,结果仅代表对应运行环境。
|
||||
|
||||
三核心固定为npm5.1.7、npm5.4.0、候选5.4.1;实际npm1.0.0插件完整bundle通过
|
||||
归档校验后直接加载,候选两种模式使用同一生产构建配置的内存bundle。历史插件的
|
||||
归档校验后直接加载,候选两种模式默认使用同一生产构建配置的内存bundle。
|
||||
设置 ARTPLAYER_BROWSER_ARTIFACTS 后改为核验并加载安装包;config 要求核心、
|
||||
Chapter、VAST 的安装和源码新鲜度证据,三个 native 文件都保留早期输入身份附件。
|
||||
历史插件的
|
||||
SDK清理由夹具在证据后显式补做,不能据DOM被核心移除就认为旧插件拥有SDK清理。
|
||||
源代码组合通过不等于最终tarball通过,也不等于iOS/Android物理设备通过。
|
||||
|
||||
@@ -125,3 +128,9 @@ SDK清理由夹具在证据后显式补做,不能据DOM被核心移除就认
|
||||
最终5/6(另1项9000失败)、共享服务12/12及固定WebKit诊断3/3见
|
||||
[增补记录](changes/2026-09-14-PKG-VAST-05-skip-checkpoint.md)。媒体采样仅用于
|
||||
记录,未放宽原首帧断言;三次通过不能覆盖先前间歇失败。
|
||||
|
||||
统一安装清单中的 `vast-package.spec.js` 只覆盖完整打包 glomex 的脚本加载、
|
||||
并发拒绝、重试请求和销毁边界。它通过网络拦截控制失败,迟到成功仅提供空的
|
||||
IMA readiness 哨兵;不会执行广告。原 `vast.spec.js` 继续替换 glomex 边界,
|
||||
不纳入完整安装 bundle 声明。真实广告仍必须单独执行上述 native 入口,并按
|
||||
实际 SDK/网络结果记录。见[安装检查点](changes/2026-09-15-CI-01-vast-installed.md)。
|
||||
@@ -29,6 +29,14 @@ Iframe baseline/lifecycle-only/boundaries-only diagnostic flags. The separate
|
||||
history server still uses `iframeCandidate()` and may receive a core-only map;
|
||||
its source/explicit tool selection has not become installed-tool acceptance.
|
||||
|
||||
VAST's installed entry is `vast-package.spec.js`: complete glomex bundle,
|
||||
controlled native SDK script failure/readiness, registration cleanup and actual
|
||||
main-content decoding. The original `vast.spec.js` substitutes the glomex boundary
|
||||
and remains source-only. Real Google IMA execution stays in `test:vast-native`;
|
||||
that separate config now accepts a verified core/Chapter/VAST installation map
|
||||
and all native candidate files record the installed identity before initialization.
|
||||
Loader tests cannot stand in for native advertising, devices or SDK availability.
|
||||
|
||||
Ads media/lifecycle and UI files use `test/helpers/browser-candidate.js` to select
|
||||
the verified installed plugin whenever an artifact map is present. An additional
|
||||
ARTPLAYER_ADS_ARTIFACT override is rejected instead of mixing candidates. Missing,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PlaywrightTestConfig } from '@playwright/test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
export type BrowserScope = 'source' | 'installed'
|
||||
export const installedPackages = ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-ambilight', 'artplayer-proxy-canvas', 'artplayer-plugin-document-pip', 'artplayer-plugin-ads', 'artplayer-plugin-audio-track', 'artplayer-plugin-vtt-thumbnail', 'artplayer-plugin-multiple-subtitles', 'artplayer-plugin-hls-control', 'artplayer-plugin-dash-control', 'artplayer-plugin-auto-thumbnail', 'artplayer-plugin-asr', 'artplayer-plugin-chromecast', 'artplayer-proxy-mediabunny', 'artplayer-plugin-jassub', 'artplayer-plugin-danmuku', 'artplayer-plugin-danmuku-mask', 'artplayer-tool-iframe']
|
||||
export const installedPackages = ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-ambilight', 'artplayer-proxy-canvas', 'artplayer-plugin-document-pip', 'artplayer-plugin-ads', 'artplayer-plugin-audio-track', 'artplayer-plugin-vtt-thumbnail', 'artplayer-plugin-multiple-subtitles', 'artplayer-plugin-hls-control', 'artplayer-plugin-dash-control', 'artplayer-plugin-auto-thumbnail', 'artplayer-plugin-asr', 'artplayer-plugin-chromecast', 'artplayer-proxy-mediabunny', 'artplayer-plugin-jassub', 'artplayer-plugin-danmuku', 'artplayer-plugin-danmuku-mask', 'artplayer-tool-iframe', 'artplayer-plugin-vast']
|
||||
export const installedTests = [
|
||||
'playback.spec.js',
|
||||
'lifecycle.spec.js',
|
||||
@@ -76,6 +76,7 @@ export const installedTests = [
|
||||
'iframe-navigation.spec.js',
|
||||
'iframe-player.spec.js',
|
||||
'iframe-editor.spec.js',
|
||||
'vast-package.spec.js',
|
||||
]
|
||||
|
||||
export function browserInvocation(scope: string, args: string[], environment: NodeJS.ProcessEnv) {
|
||||
|
||||
@@ -116,6 +116,7 @@ export async function checkPackages({ release = false, include = [] } = {}) {
|
||||
'artplayer-plugin-danmuku': async () => (await import('../refactor/scripts/danmuku-contract.mjs')).verifyDanmukuContract(),
|
||||
'artplayer-plugin-danmuku-mask': async () => (await import('../refactor/scripts/danmuku-mask-contract.mjs')).verifyDanmukuMaskContract(),
|
||||
'artplayer-tool-iframe': async () => (await import('../refactor/scripts/iframe-contract.mjs')).verifyIframeContract(),
|
||||
'artplayer-plugin-vast': async () => (await import('../refactor/scripts/vast-contract.mjs')).verifyVastContract(),
|
||||
'artplayer-plugin-audio-track': async () => (await import('../refactor/scripts/audio-contract.mjs')).verifyAudioContract(),
|
||||
'artplayer-plugin-vtt-thumbnail': async () => (await import('../refactor/scripts/vtt-thumbnail-contract.mjs')).verifyVttThumbnailContract(),
|
||||
'artplayer-plugin-multiple-subtitles': async () => (await import('../refactor/scripts/multiple-subtitles-contract.mjs')).verifyMultipleSubtitlesContract(),
|
||||
|
||||
@@ -24,6 +24,19 @@ test('Source invocation clears inherited artifact selection without changing cal
|
||||
assert(fs.existsSync(path.resolve('test/browser', file)))
|
||||
})
|
||||
|
||||
test('Native VAST keeps its source default and rejects an invalid explicit installation before browser launch', () => {
|
||||
const env = { ...process.env }
|
||||
delete env.ARTPLAYER_BROWSER_ARTIFACTS
|
||||
const command = 'const { default: config } = await import("./playwright.vast-native.config.js"); if (config.timeout !== 30000 || config.workers !== 1) throw new Error("Native execution policy changed");'
|
||||
const source = spawnSync(process.execPath, ['--input-type=module', '-e', command], { encoding: 'utf8', env, windowsHide: true })
|
||||
assert.equal(source.status, 0, source.stderr)
|
||||
const missing = path.resolve('refactor/.cache/absent-vast-native-artifact-map.json')
|
||||
assert(!fs.existsSync(missing))
|
||||
const installed = spawnSync(process.execPath, ['--input-type=module', '-e', command], { encoding: 'utf8', env: { ...env, ARTPLAYER_BROWSER_ARTIFACTS: missing }, windowsHide: true })
|
||||
assert.equal(installed.status, 1)
|
||||
assert.match(installed.stderr, /ENOENT/)
|
||||
})
|
||||
|
||||
test('Browser invocation rejects ambiguous scopes and output/configuration overrides', () => {
|
||||
assert.throws(() => browserInvocation('unknown', [], {}), /Choose/)
|
||||
assert.throws(() => browserInvocation('installed', [], {}), /require ARTPLAYER/)
|
||||
|
||||
@@ -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