mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
test(ci): [CI-01] checkpoint installed adaptive and thumbnail coverage
This commit is contained in:
1 parent
7094cf6f9c
commit
b90de99bc2
25 files changed
+10494
-45
No files matched your search
@@ -140,7 +140,7 @@ jobs:
|
||||
# These extra installed packages are required by the browser helpers.
|
||||
# Other ecosystem installation/SDK gates remain tracked by CI-01.
|
||||
run: |
|
||||
yarn test:package --include=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 2>&1 | tee refactor/.cache/ci/browser-packages.log
|
||||
yarn test:package --include=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 2>&1 | tee refactor/.cache/ci/browser-packages.log
|
||||
node --input-type=module -e 'import fs from "node:fs"; const { output } = JSON.parse(fs.readFileSync("refactor/.cache/packages/latest.json")); fs.appendFileSync(process.env.GITHUB_ENV, `ARTPLAYER_BROWSER_ARTIFACTS=${output}/browser-artifacts.json\n`);'
|
||||
- name: Run all source browser checks
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
@@ -227,3 +227,15 @@ The internal type checkpoint and its core-host assignment fixture are recorded i
|
||||
`refactor/changes/2026-09-13-PKG-AUTO-THUMB-03-internal-types.md`. A core host can
|
||||
hold partial user thumbnail options; extraction publishes a complete sheet. Do not
|
||||
require the host's existing getter to have every generated-sheet field.
|
||||
|
||||
## Shared installed browser scope
|
||||
|
||||
autoThumbnailCandidate reads verified installed bytes through browser-candidate.js. Native video/JPEG lifecycle and pixel files retain their stub player host and exact presentation-callback/fallback limits. The historical file still loads its frozen old artifacts. Installed mode rejects frozen-workspace and explicit-artifact overrides. These are native extraction checks, not full core integration or first-frame acceptance on every engine.
|
||||
|
||||
Use the exact twelve-package preparation command and scope rules in
|
||||
../../scripts/browser-validation/README.md. Missing, stale or changed installation
|
||||
inputs fail without source fallback. Attachments distinguish selected installed,
|
||||
source and published inputs. Source mode retains existing explicit artifact use.
|
||||
The generic Node/type consumer remains core/chapter-only. Module forms, physical
|
||||
devices, editor demos and release readiness retain their separate package gates.
|
||||
See ../../refactor/changes/2026-09-15-CI-01-adaptive-installed.md for actual results.
|
||||
@@ -213,3 +213,15 @@ controls and strict candidate recovery with new/old core versions. Node tests
|
||||
cover invalid measurements, missing capabilities, SDK replacement, teardown,
|
||||
reentrancy, identity changes and error recovery. Standalone old SDK/old-plugin
|
||||
limitations, physical devices and full release acceptance remain separately tracked.
|
||||
|
||||
## Shared installed browser scope
|
||||
|
||||
dash-control.spec.js exercises native MP4 and real core DOM with controlled SDK methods. dash-sdk.spec.js loads the actual frozen dash.js 4.5.2/5.2.1 SDKs and MPD fixtures. Its SDK capability attachment does not claim a plugin was loaded; dash-plugin-inputs records the selected plugin only in integration cases. Installed mode rejects diagnostic SDK substitutions and synthetic recovery probes.
|
||||
|
||||
Use the exact twelve-package preparation command and scope rules in
|
||||
../../scripts/browser-validation/README.md. Missing, stale or changed installation
|
||||
inputs fail without source fallback. Attachments distinguish selected installed,
|
||||
source and published inputs. Source mode retains existing explicit artifact use.
|
||||
The generic Node/type consumer remains core/chapter-only. Module forms, physical
|
||||
devices, editor demos and release readiness retain their separate package gates.
|
||||
See ../../refactor/changes/2026-09-15-CI-01-adaptive-installed.md for actual results.
|
||||
@@ -142,3 +142,15 @@ extends the repository root and must not ship to consumers. PKG-HLS-PACK-01
|
||||
compares real Yarn archives before/after the exclusion: all distribution and
|
||||
declaration bytes must remain identical, with every historical entry retained.
|
||||
See ../../refactor/changes/2026-09-15-PKG-HLS-PACK-01-config.md.
|
||||
|
||||
## Shared installed browser scope
|
||||
|
||||
hls-control.spec.js uses a frozen SDK without workers; hls-sdk.spec.js uses the frozen SDK version matrix and real workers. Both select verified installed plugin bytes and retain published plugin controls.
|
||||
|
||||
Use the exact twelve-package preparation command and scope rules in
|
||||
../../scripts/browser-validation/README.md. Missing, stale or changed installation
|
||||
inputs fail without source fallback. Attachments distinguish selected installed,
|
||||
source and published inputs. Source mode retains existing explicit artifact use.
|
||||
The generic Node/type consumer remains core/chapter-only. Module forms, physical
|
||||
devices, editor demos and release readiness retain their separate package gates.
|
||||
See ../../refactor/changes/2026-09-15-CI-01-adaptive-installed.md for actual results.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,65 @@
|
||||
# CI-01 HLS、DASH 与 Auto Thumbnail 接入安装范围
|
||||
|
||||
## 实现与边界
|
||||
|
||||
十二包统一安装名单新增 HLS Control、DASH Control、Auto Thumbnail。七个浏览器
|
||||
文件通过 browser-candidate.js 加载校验后的实际 tarball 安装文件,拒绝显式产物
|
||||
覆盖和 Auto Thumbnail frozen baseline;缺失/过期/篡改安装不退回源码。
|
||||
既有源码入口保留,DASH 安装入口额外拒绝诊断 SDK 替换与恢复探针,防止诊断变体
|
||||
混入正常验收。source 模式仍保留明确诊断开关。相关守卫负例已纳入 Node 测试。
|
||||
|
||||
HLS 使用固定实际 SDK、manifest/分片,区分无 Worker 与有真实 Worker 两套用例。
|
||||
DASH 的 controlled 文件仅验证真实核心 DOM/原生 MP4 和受控 SDK 方法;SDK 文件
|
||||
加载真实固定 dash.js 4.5.2/5.2.1。SDK 能力附件只记录可用候选,不声称加载插件;
|
||||
dash-plugin-inputs 记录集成场景的实际选包。纯原生 SDK 无插件对照保持不变。
|
||||
Auto Thumbnail 使用原生视频、Canvas 和 JPEG,但核心宿主是 stub;无原生帧呈现
|
||||
回调时首两格仍为诊断而非通过,AUTO-THUMB-PIXEL-01 不因此关闭。
|
||||
|
||||
首次十二包准备被 HLS 的 tsconfig 泄漏拦截;PKG-HLS-PACK-01 已独立修复并提交
|
||||
7094cf6f9,详细旧/中间/新归档证据另存。CI 接入未改公开生产 API、超时、SDK 或
|
||||
断言;lint 自动修正了改动文件内既有 finally 括号格式。无新增依赖,根锁不变。
|
||||
|
||||
## 工程验证
|
||||
|
||||
Windows x64,固定 Node 24.21.0、Yarn 1.22.22。run-UmEnUj 实际十二包构建/pack/
|
||||
隔离安装/冻结复装和完整成员核验通过。通用消费者仍只覆盖 core/chapter 的
|
||||
36 运行时、5 旧类型模式、8 精确类型模式,不是全生态 Node/类型准入。
|
||||
|
||||
相关单元 278/278、工程 47/47、scoped lint、library 严格类型、严格工具链、CI
|
||||
工作流契约与 actionlint 1.7.12 通过;未调用 shellcheck/pyflakes。初始 lint
|
||||
四处格式错误日志保留,最终改正。完整 installed collection 为 32 文件/1137 项;
|
||||
本轮实跑仅新增七文件三引擎 375 项,workers=2,retries=0,结果见机器证据。
|
||||
|
||||
## 维护与剩余工作
|
||||
|
||||
维护入口为三个包的 ARCHITECTURE.md、scripts/browser-validation/README.md、
|
||||
test/package/README.md。所有实际失败、能力跳过和原生对照单独计数;保留旧
|
||||
AUDIO-BUFFER-01 与 CHAPTER-TIMING-01 报告,未在本次重复执行此前插件集合。
|
||||
CI-01 与各包真实 SDK/设备/完整分发门槛继续开放。尚未运行远端 Actions,也没有
|
||||
发布候选授权。回退此检查点恢复九包 installed 范围;HLS 排除配置修复为独立提交。
|
||||
|
||||
## 实测结果
|
||||
|
||||
Chromium 153.0.8010.12、Firefox 155.0、WebKit 26.6。375 项共 293 通过、
|
||||
2 失败、80 跳过,耗时 350.040 秒,实际退出 1、无重试;Chromium/Firefox 各
|
||||
124 通过与 1 失败,WebKit 45 通过与 80 能力跳过。32 文件/1137 项只是完整
|
||||
collection,本轮没有重跑其他二十五文件,不能将新子集结果当成完整十二包 CI。
|
||||
|
||||
两项失败均为裸 dash.js 4.5.2 的暂停边界 seek,重新播放后 currentTime 停在 6,
|
||||
未达到大于 6.2 的断言。该路径未创建 ArtPlayer 实例,候选插件没有参与;已有
|
||||
DASH-SEEK-01 与候选插件的精确版本修复分别保留。实际候选插件集成通过并不修复
|
||||
裸 SDK。状态附件在清理后的视频尺寸/时间归零不能被反推为失败当时的解码状态。
|
||||
原始 trace/截图/报告保留在 ci01-adaptive-installed-report,读取旧附件路径时映射
|
||||
到归档目录的 results;没有重跑覆盖、升级 SDK 或放宽 seek 断言。
|
||||
|
||||
80 项跳过全部在 Windows WebKit:DASH SDK 48、HLS 主矩阵 16、HLS SDK 矩阵 16。
|
||||
实际能力记录仍验证无 MSE 的边界,不等于适配流播放通过。Auto Thumbnail 三引擎
|
||||
候选 27 项通过,但 WebKit 两个像素用例对首两格仅记录诊断,不能关闭首帧风险。
|
||||
测试输入附件确认 221 项选择已验证候选安装文件,其中含能力边界与受控宿主,
|
||||
不把该数当作 221 项真实自适应解码。固定 SDK 为 hls.js 1.5.17/1.7.2、dash.js
|
||||
4.5.2/5.2.1,来源和实际包成员哈希均保留。
|
||||
|
||||
刻意继承 installed map 后,source 入口清除了它。三个 Chromium 源码定向用例
|
||||
(HLS 解码/选择、DASH 5.2.1 MPD/选择、Auto Thumbnail pattern 像素)3/3 通过,
|
||||
附件均为 source-build;这不重验所有源码文件。所有结果见
|
||||
[机器证据](../baselines/ci-adaptive-installed-validation.json)。
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
浏览器CI现在分别执行 `yarn test:browser:source` 和
|
||||
`yarn test:browser:installed`。前者清除继承的安装map并保留全部spec;后者要求已
|
||||
核验的core/chapter/Ambilight/Canvas/Document PiP/Ads/Audio Track/VTT Thumbnail/Multiple Subtitles安装,执行明确列出的installed子集。两步不
|
||||
核验的core/chapter/Ambilight/Canvas/Document PiP/Ads/Audio Track/VTT Thumbnail/Multiple Subtitles/HLS Control/DASH Control/Auto Thumbnail安装,执行明确列出的installed子集。两步不
|
||||
吞失败,普通失败后仍保存另一范围的证据,分别上传browser-source/browser-installed。
|
||||
入口与报告规则见[维护说明](../scripts/browser-validation/README.md)。source全量
|
||||
耗时/60分钟预算、其余插件安装矩阵与远端运行仍待CI-01/CI-04,不计为已通过。
|
||||
|
||||
+1
-1
@@ -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)
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# 进度与证据
|
||||
|
||||
## CI-01 自适应控制和自动缩略图接入安装矩阵
|
||||
|
||||
十二包实际安装通过,清单扩展到 32 文件/1137 项。新增七文件三引擎实跑
|
||||
375 项:293 通过、2 裸 dash.js 4.5.2 seek 失败、80 Windows WebKit MSE 能力
|
||||
跳过。Auto Thumbnail 首帧限制仍保留,未把能力诊断计为通过。源码定向 3/3、
|
||||
相关单元 278/278、工程 47/47 通过;见[记录](changes/2026-09-15-CI-01-adaptive-installed.md)。
|
||||
CI-01 继续 doing,197/263 完成;后续补齐其余安装覆盖并审查全矩阵耗时与失败归类。
|
||||
|
||||
## PKG-HLS-PACK-01 修正实现配置进入 npm 包
|
||||
|
||||
十二包安装准备发现 HLS 的内部 tsconfig 未排除。已修正 .npmignore,实际旧包
|
||||
|
||||
+9
-4
@@ -3080,10 +3080,13 @@
|
||||
"refactor/changes/2026-09-14-CI-01-source-chromium.md",
|
||||
"refactor/baselines/ci-source-chromium-validation.json",
|
||||
"refactor/changes/2026-09-14-PKG-DASH-SEEK-01-buffer-metrics.md",
|
||||
"refactor/baselines/dash-seek-recovery-validation.json"
|
||||
"refactor/baselines/dash-seek-recovery-validation.json",
|
||||
"refactor/changes/2026-09-15-CI-01-adaptive-installed.md",
|
||||
"refactor/baselines/ci-adaptive-installed-validation.json"
|
||||
],
|
||||
"compatibleResolution": "PKG-DASH-SEEK-01 已在候选插件按精确版本和真实空缓冲同步 SDK 指标,新旧核心及两引擎严格跳转通过。裸 SDK 4.5.2 和冻结旧插件仍保留原始失败;不伪造媒体事件、不偏移 seek、不强制升级 SDK,完整组合及发布验收仍开放。",
|
||||
"closureCriteria": "原失败的新旧核心/插件组合有确定根因与对应修复/可验证环境边界;原生对照及原顺序、原目标回归成立,后续偶然通过不能关闭。"
|
||||
"closureCriteria": "原失败的新旧核心/插件组合有确定根因与对应修复/可验证环境边界;原生对照及原顺序、原目标回归成立,后续偶然通过不能关闭。",
|
||||
"workspaceState": "CI-01 十二包安装扩展中,裸 SDK 4.5.2 在 Chromium/Firefox 的恢复时间仍为 6,原断言大于 6.2 失败;候选插件集成通过不关闭裸 SDK 原始缺陷,完整失败报告保留。"
|
||||
},
|
||||
{
|
||||
"id": "ADS-TYPE-01",
|
||||
@@ -4259,11 +4262,13 @@
|
||||
"refactor/changes/2026-09-14-PKG-AUTO-THUMB-03-first-seek.md",
|
||||
"refactor/baselines/auto-thumbnail-first-seek.json",
|
||||
"refactor/changes/2026-09-14-PKG-AUTO-THUMB-03-native-decoder.md",
|
||||
"refactor/baselines/auto-thumbnail-native-decoder.json"
|
||||
"refactor/baselines/auto-thumbnail-native-decoder.json",
|
||||
"refactor/changes/2026-09-15-CI-01-adaptive-installed.md",
|
||||
"refactor/baselines/ci-adaptive-installed-validation.json"
|
||||
],
|
||||
"compatibleResolution": "Establish actual decoded-frame readiness for the existing timeline/grid and preserve silent independent extraction; do not waive colored pixel checks as unsupported media. Intrinsic-size hidden/opacity/clip/visible rendering crossed with current/readyState/first-loadeddata-event strategies still misses the unique first frame in all 12 Windows WebKit profiles. Correct Firefox frames retain totalVideoFrames=0, so that counter cannot be a portable readiness gate. Do not reintroduce these unvalidated workarounds. First-seek diagnostics additionally exclude drawing the first loadeddata frame without seek, one/two RAF waits, post-seek RAF waits and verified forward/back seeking on the recorded Windows WebKit host. The warm comparison first had an invalid stale-event completion, then a timeout; final bounded retries verify actual [1,1,0] seeking and still miss purple. Controls retain purple. These are exclusions, not production fixes.",
|
||||
"closureCriteria": "Candidate source and artifacts generate usable sampled pixels on native browser controls with lifecycle checks; supported Safari and core combinations remain explicit final gates.",
|
||||
"workspaceState": "The frames module now waits for native presentation and seek completion on capable browsers. Chromium/Firefox source/main/legacy assert all five cells including first purple frame, second red cell, legitimate black and presentation times. Callback-less Windows WebKit first two cells remain diagnostic, later cells asserted; physical Safari/core combinations remain open. 84 native lifecycle/pixel cases passed with explicit held native-frame vs Blob-fallback paths; 19 new Node cases fail 17 ways on prior checkpoint and all 52 current cases pass per candidate. Risk and task03 remain open. Native-only18-case Windows probe also misses the purple first frame in all6 WebKit26.6 cases (hidden/visible paused and immediate play-pause, original and no-B-frame H.264);12 Chromium/Firefox controls recover it. No ArtPlayer/plugin is imported, narrowing but not resolving the native surface boundary. Rate/offset/layout explorations failed and must not be reintroduced as assumed fixes."
|
||||
"workspaceState": "The frames module now waits for native presentation and seek completion on capable browsers. Chromium/Firefox source/main/legacy assert all five cells including first purple frame, second red cell, legitimate black and presentation times. Callback-less Windows WebKit first two cells remain diagnostic, later cells asserted; physical Safari/core combinations remain open. 84 native lifecycle/pixel cases passed with explicit held native-frame vs Blob-fallback paths; 19 new Node cases fail 17 ways on prior checkpoint and all 52 current cases pass per candidate. Risk and task03 remain open. Native-only18-case Windows probe also misses the purple first frame in all6 WebKit26.6 cases (hidden/visible paused and immediate play-pause, original and no-B-frame H.264);12 Chromium/Firefox controls recover it. No ArtPlayer/plugin is imported, narrowing but not resolving the native surface boundary. Rate/offset/layout explorations failed and must not be reintroduced as assumed fixes. CI-01 实际安装候选三引擎生命周期/像素 27 项通过;Windows WebKit 两个像素用例仍明确仅验证后面三格,首两格为诊断。没有将此结果用于关闭原首帧风险或认定完整核心组合。"
|
||||
},
|
||||
{
|
||||
"id": "VTT-THUMB-DIST-01",
|
||||
|
||||
@@ -90,7 +90,7 @@ export function validateCIWorkflow(source) {
|
||||
const vueIndex = browser.steps.findIndex(step => step.run === 'yarn test:vue-consumer 2>&1 | tee refactor/.cache/ci/vue-consumer.log')
|
||||
assert(vueIndex > consumerIndex && !Object.hasOwn(browser.steps[vueIndex], 'if'), 'Run Vue installed consumers after restoring canonical Node')
|
||||
assert(browser.steps.some(step => step.uses?.startsWith('actions/upload-artifact@') && step.if === 'always()' && step.with.path.split('\n').includes('refactor/.cache/vue-consumer-*/')), 'Retain Vue consumer failure evidence')
|
||||
const extraIndex = browser.steps.findIndex(step => step.run?.startsWith('yarn test:package --include=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 '))
|
||||
const extraIndex = browser.steps.findIndex(step => step.run?.startsWith('yarn test:package --include=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 '))
|
||||
const sourceEngineIndex = browser.steps.findIndex(step => step.run === 'yarn test:browser:source 2>&1 | tee refactor/.cache/ci/browser-source.log')
|
||||
const engineIndex = browser.steps.findIndex(step => step.run === 'yarn test:browser:installed 2>&1 | tee refactor/.cache/ci/browser-installed.log')
|
||||
assert(extraIndex > Math.max(consumerIndex, reactIndex, vueIndex) && extraIndex < engineIndex, 'Prepare installed Ambilight/Canvas/Document PiP/Ads after consumer probes and before browser checks')
|
||||
|
||||
+3
-1
@@ -766,7 +766,9 @@
|
||||
"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"
|
||||
"baselines/ci-subtitles-installed-validation.json",
|
||||
"changes/2026-09-15-CI-01-adaptive-installed.md",
|
||||
"baselines/ci-adaptive-installed-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -14,8 +14,8 @@ also retains explicit historical and committed-artifact cases; its name does not
|
||||
promise that every dependency is rebuilt from current source in every test.
|
||||
|
||||
`yarn test:browser:installed` requires ARTPLAYER_BROWSER_ARTIFACTS from
|
||||
`yarn test:package --include=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`.
|
||||
Both launcher and config validate the selected nine packages' installed hashes
|
||||
`yarn test:package --include=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`.
|
||||
Both launcher and config validate the selected twelve packages' installed hashes
|
||||
and source/build freshness. `scope.ts` lists the currently supported installed
|
||||
test files. This is a growing installed subset, not full ecosystem acceptance.
|
||||
Source checks remain complete when the installed list grows.
|
||||
@@ -74,3 +74,12 @@ not be counted as successful feature acceptance. Shared Node/type consumers reta
|
||||
the core/chapter scope. See ../../refactor/changes/2026-09-15-CI-01-subtitles-installed.md
|
||||
for the executed subset and results; extending collection does not revalidate the
|
||||
previous Chapter failure or establish a green complete matrix.
|
||||
|
||||
HLS Control, DASH Control and Auto Thumbnail add seven installed files. HLS/DASH
|
||||
real SDK cases retain frozen release and media hashes; controlled DASH DOM cases
|
||||
are separate from adaptive playback. DASH SDK capability probes do not load the
|
||||
plugin; dash-plugin-inputs identifies actual plugin integration. Installed mode
|
||||
rejects diagnostic SDK patches/debug replacements and synthetic recovery probes,
|
||||
while source diagnostics remain explicit. Auto Thumbnail uses native media/JPEG
|
||||
with a stub host and retains its presentation/fallback pixel limitations. See
|
||||
../../refactor/changes/2026-09-15-CI-01-adaptive-installed.md for executed results.
|
||||
@@ -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']
|
||||
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']
|
||||
export const installedTests = [
|
||||
'playback.spec.js',
|
||||
'lifecycle.spec.js',
|
||||
@@ -29,16 +29,27 @@ export const installedTests = [
|
||||
'multiple-subtitles-combinations.spec.js',
|
||||
'multiple-subtitles-ass.spec.js',
|
||||
'multiple-subtitles-switch.spec.js',
|
||||
'hls-control.spec.js',
|
||||
'hls-sdk.spec.js',
|
||||
'dash-control.spec.js',
|
||||
'dash-sdk.spec.js',
|
||||
'auto-thumbnail.spec.js',
|
||||
'auto-thumbnail-lifecycle.spec.js',
|
||||
'auto-thumbnail-pixels.spec.js',
|
||||
]
|
||||
|
||||
export function browserInvocation(scope: string, args: string[], environment: NodeJS.ProcessEnv) {
|
||||
assert(scope === 'source' || scope === 'installed', 'Choose source or installed browser scope')
|
||||
assert(!args.some(arg => /^(?:--(?:config|reporter|output|pass-with-no-tests)(?:=|$)|-c)/.test(arg)), 'Do not override browser scope configuration or evidence output')
|
||||
const env: NodeJS.ProcessEnv = { ...environment, ARTPLAYER_BROWSER_SCOPE: scope }
|
||||
if (scope === 'source')
|
||||
if (scope === 'source') {
|
||||
delete env.ARTPLAYER_BROWSER_ARTIFACTS
|
||||
else
|
||||
}
|
||||
else {
|
||||
assert(env.ARTPLAYER_BROWSER_ARTIFACTS, 'Installed browser checks require ARTPLAYER_BROWSER_ARTIFACTS')
|
||||
assert(!env.ARTPLAYER_DASH_DIAGNOSTIC_SDK || env.ARTPLAYER_DASH_DIAGNOSTIC_SDK === 'none', 'Installed browser checks require the unchanged DASH SDK')
|
||||
assert(!['ARTPLAYER_DASH_DIAGNOSE_STALL', 'ARTPLAYER_DASH_DIAGNOSE_GETTER', 'ARTPLAYER_DASH_DIAGNOSE_METRICS'].some(name => env[name] === '1'), 'Installed browser checks cannot use DASH recovery diagnostics')
|
||||
}
|
||||
return { scope, env, args: ['test', `--config=playwright.${scope}.config.js`, ...args], directory: `refactor/.cache/browser-${scope}` }
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,9 @@ export async function checkPackages({ release = false, include = [] } = {}) {
|
||||
'artplayer-proxy-canvas': async () => (await import('../refactor/scripts/canvas-contract.mjs')).verifyCanvasContract(),
|
||||
'artplayer-plugin-document-pip': async () => (await import('../refactor/scripts/dpip-contract.mjs')).verifyDpipContract(),
|
||||
'artplayer-plugin-ads': async () => (await import('../refactor/scripts/ads-contract.mjs')).verifyAdsContract(),
|
||||
'artplayer-plugin-hls-control': async () => (await import('../refactor/scripts/hls-contract.mjs')).verifyHlsContract(),
|
||||
'artplayer-plugin-dash-control': async () => (await import('../refactor/scripts/dash-contract.mjs')).verifyDashContract(),
|
||||
'artplayer-plugin-auto-thumbnail': async () => (await import('../refactor/scripts/auto-thumbnail-contract.mjs')).verifyAutoThumbnailContract(),
|
||||
'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(),
|
||||
|
||||
@@ -31,6 +31,18 @@ test('Browser invocation rejects ambiguous scopes and output/configuration overr
|
||||
assert.throws(() => browserInvocation('source', [flag], {}), /Do not override/)
|
||||
})
|
||||
|
||||
test('Installed validation rejects diagnostic SDK substitutions and recovery probes', () => {
|
||||
const base = { ARTPLAYER_BROWSER_ARTIFACTS: '/installed/map.json' }
|
||||
for (const mode of ['upstream4', 'bufferlevel4']) {
|
||||
const env = { ...base, ARTPLAYER_DASH_DIAGNOSTIC_SDK: mode }
|
||||
assert.throws(() => browserInvocation('installed', [], env), /unchanged DASH SDK/)
|
||||
assert.equal(browserInvocation('source', [], env).env.ARTPLAYER_DASH_DIAGNOSTIC_SDK, mode)
|
||||
}
|
||||
for (const name of ['ARTPLAYER_DASH_DIAGNOSE_STALL', 'ARTPLAYER_DASH_DIAGNOSE_GETTER', 'ARTPLAYER_DASH_DIAGNOSE_METRICS'])
|
||||
assert.throws(() => browserInvocation('installed', [], { ...base, [name]: '1' }), /recovery diagnostics/)
|
||||
assert.equal(browserInvocation('installed', [], { ...base, ARTPLAYER_DASH_DIAGNOSTIC_SDK: 'none' }).env.ARTPLAYER_DASH_DIAGNOSTIC_SDK, 'none')
|
||||
})
|
||||
|
||||
for (const code of [0, 17]) {
|
||||
test(`Browser runner preserves actual child exit ${code} and source input identity`, () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'artplayer-browser-runner-'))
|
||||
|
||||
@@ -108,7 +108,9 @@ for (const variant of ['destroy', 'restart', 'complete', 'frame-destroy', 'frame
|
||||
throw new Error('No owned encoding deadline')
|
||||
probe.encodingDeadline.callback()
|
||||
}
|
||||
else probe.art.emit(scenario.replace('frame-', ''))
|
||||
else {
|
||||
probe.art.emit(scenario.replace('frame-', ''))
|
||||
}
|
||||
if (probe.blobs[0]) {
|
||||
probe.blobs[0].callback(probe.blobs[0].blob)
|
||||
probe.blobs[0].callback(probe.blobs[0].blob)
|
||||
@@ -136,14 +138,16 @@ for (const variant of ['destroy', 'restart', 'complete', 'frame-destroy', 'frame
|
||||
probe.restore()
|
||||
return { before, after, video, canvasDimensions, publishedImage, final, blobs, pendingDeadlines: probe.timers.size, warnings: probe.warnings, heldFrames: probe.frames.length, frameSupport: probe.frameSupport, result: probe.result }
|
||||
}, scenario)
|
||||
await testInfo.attach('auto-thumbnail-candidate-native-lifecycle', { contentType: 'application/json', body: JSON.stringify({ scenario, useDefault, sha256: hash(implementation.code), scope: 'Actual HTTP decoding/seek/JPEG and held native presentation callback lifecycle with a stub player host. Frame scenarios use a held Blob fallback only when native frame callbacks are absent. Pixel acceptance is separate; AUTO-THUMB-PIXEL-01 remains open.', ...state }) })
|
||||
await testInfo.attach('auto-thumbnail-candidate-native-lifecycle', { contentType: 'application/json', body: JSON.stringify({ scenario, useDefault, sha256: hash(implementation.code), provenance: implementation.provenance, scope: 'Actual HTTP decoding/seek/JPEG and held native presentation callback lifecycle with a stub player host. Frame scenarios use a held Blob fallback only when native frame callbacks are absent. Pixel acceptance is separate; AUTO-THUMB-PIXEL-01 remains open.', ...state }) })
|
||||
expect(state.result).toEqual({ name: 'artplayerPluginAutoThumbnail' })
|
||||
expect(state.pendingDeadlines).toBe(0)
|
||||
if (scenario === 'encoding-timeout') {
|
||||
expect(state.warnings).toHaveLength(1)
|
||||
expect(state.warnings[0][1]).toContain('encoding timed out')
|
||||
}
|
||||
else expect(state.warnings).toEqual([])
|
||||
else {
|
||||
expect(state.warnings).toEqual([])
|
||||
}
|
||||
expect(state.before).toEqual(scenario === 'complete' ? { urls: 1, updates: 2 } : { urls: 0, updates: 0 })
|
||||
expect(state.after).toEqual(state.before)
|
||||
expect(state.video).toEqual({ connected: false, src: null, readyState: 0, paused: true, handlers: [true, true, true, true] })
|
||||
|
||||
@@ -91,6 +91,7 @@ for (const media of ['auto-thumbnail-timeline', 'pattern']) {
|
||||
})
|
||||
await testInfo.attach('auto-thumbnail-candidate-hidden-pixels', { contentType: 'application/json', body: JSON.stringify({
|
||||
sha256: hash(implementation.code),
|
||||
provenance: implementation.provenance,
|
||||
media,
|
||||
scope: 'All five cells are asserted where native frame presentation callbacks are available. Without that capability only cells 2-4 are asserted, with cells 0-1 recorded as unresolved diagnostics under AUTO-THUMB-PIXEL-01. Native HTTP/JPEG and a stub player host, not a core integration.',
|
||||
...state,
|
||||
|
||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
let publishedCode
|
||||
@@ -14,9 +14,9 @@ test.beforeAll(async () => {
|
||||
const bytes = readMember(await ensureArchive(release), member)
|
||||
assert.equal(hash(bytes), release.files[member])
|
||||
publishedCode = bytes.toString()
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Controlled DASH source tests do not represent installed SDK/package acceptance')
|
||||
sourceCode = process.env.ARTPLAYER_DASH_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_DASH_ARTIFACT, 'utf8') : await compilePackage(release.name, 'umd')
|
||||
evidence = { published: release, sourceSHA256: hash(sourceCode), candidate: process.env.ARTPLAYER_DASH_ARTIFACT || 'workspace source build', scope: 'Real ArtPlayer DOM and native MP4 with controlled SDK methods. No dash.js instance, MPD, ABR or adaptive media validation.' }
|
||||
const candidate = await browserCandidate(release.name, process.env.ARTPLAYER_DASH_ARTIFACT)
|
||||
sourceCode = candidate.code
|
||||
evidence = { published: release, sourceSHA256: hash(sourceCode), candidate: candidate.provenance, scope: 'Real ArtPlayer DOM and native MP4 with controlled SDK methods. No dash.js instance, MPD, ABR or adaptive media validation.' }
|
||||
})
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
const state = await page.evaluate(() => ({
|
||||
@@ -37,7 +37,7 @@ test.afterEach(async ({ page }, testInfo) => {
|
||||
}
|
||||
})
|
||||
async function openDash(page, core, plugin, sdk, testInfo) {
|
||||
await testInfo.attach('controlled-dash-inputs', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
||||
await testInfo.attach('controlled-dash-inputs', { contentType: 'application/json', body: JSON.stringify({ ...evidence, core, plugin, selected: plugin === 'published' ? { kind: 'published', sha256: hash(publishedCode) } : evidence.candidate }) })
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
await page.addScriptTag({ content: plugin === 'published' ? publishedCode : sourceCode })
|
||||
await page.evaluate((sdk) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { observeDashBuffers } from './dash-buffer-observer.js'
|
||||
import { probeBufferGetter, probeBufferMetric } from './dash-seek-diagnostics.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
@@ -10,6 +10,7 @@ import { expect, test } from './fixtures.js'
|
||||
const sdks = new Map()
|
||||
const media = new Map()
|
||||
let candidate
|
||||
let candidateProvenance
|
||||
let published
|
||||
let mediaManifest
|
||||
let pluginRelease
|
||||
@@ -18,6 +19,7 @@ assert(['none', 'upstream4', 'bufferlevel4'].includes(diagnosticSDK), 'Unknown d
|
||||
const recoveryModes = ['ARTPLAYER_DASH_DIAGNOSE_STALL', 'ARTPLAYER_DASH_DIAGNOSE_GETTER', 'ARTPLAYER_DASH_DIAGNOSE_METRICS'].filter(name => process.env[name] === '1')
|
||||
assert(recoveryModes.length <= 1, 'Choose only one DASH recovery diagnostic')
|
||||
assert(!recoveryModes.length || diagnosticSDK === 'none', 'Recovery diagnostics require the unchanged published SDK')
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS || (diagnosticSDK === 'none' && recoveryModes.length === 0), 'Installed DASH checks cannot use SDK or recovery diagnostics')
|
||||
|
||||
test.beforeAll(async () => {
|
||||
const baseline = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/dash-sdk.json', import.meta.url)))
|
||||
@@ -44,7 +46,9 @@ test.beforeAll(async () => {
|
||||
const bytes = readMember(await ensureArchive(pluginRelease), 'package/dist/artplayer-plugin-dash-control.js')
|
||||
assert.equal(hash(bytes), pluginRelease.files['package/dist/artplayer-plugin-dash-control.js'])
|
||||
published = bytes.toString()
|
||||
candidate = process.env.ARTPLAYER_DASH_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_DASH_ARTIFACT, 'utf8') : await compilePackage('artplayer-plugin-dash-control', 'umd')
|
||||
const input = await browserCandidate('artplayer-plugin-dash-control', process.env.ARTPLAYER_DASH_ARTIFACT)
|
||||
candidate = input.code
|
||||
candidateProvenance = input.provenance
|
||||
mediaManifest = JSON.parse(fs.readFileSync(new URL('./media/dash/manifest.json', import.meta.url)))
|
||||
for (const [name, expected] of Object.entries(mediaManifest.files)) {
|
||||
assert(/^[\w.-]+$/.test(name))
|
||||
@@ -116,7 +120,7 @@ async function loadSDK(page, version, core, testInfo) {
|
||||
await page.evaluate(observeDashBuffers)
|
||||
await page.addScriptTag({ content: sdk.code })
|
||||
const capability = await page.evaluate(() => ({ sdk: window.dashjs.supportsMediaSource(), mse: typeof window.MediaSource, managed: typeof window.ManagedMediaSource, avc: Boolean(window.MediaSource?.isTypeSupported('video/mp4; codecs="avc1.42c01e"')), aac: Boolean(window.MediaSource?.isTypeSupported('audio/mp4; codecs="mp4a.40.2"')) }))
|
||||
await testInfo.attach('dash-sdk-inputs', { contentType: 'application/json', body: JSON.stringify({ sdk: sdk.release, codeMember: sdk.diagnostic?.member || sdk.codeMember, diagnostic: sdk.diagnostic, pluginRelease, candidateSHA256: hash(candidate), candidate: process.env.ARTPLAYER_DASH_ARTIFACT || 'workspace source build', media: mediaManifest, capability }) })
|
||||
await testInfo.attach('dash-sdk-inputs', { contentType: 'application/json', body: JSON.stringify({ sdk: sdk.release, codeMember: sdk.diagnostic?.member || sdk.codeMember, diagnostic: sdk.diagnostic, pluginRelease, candidateSHA256: hash(candidate), availableCandidate: candidateProvenance, pluginLoaded: false, media: mediaManifest, capability }) })
|
||||
return capability
|
||||
}
|
||||
|
||||
@@ -124,6 +128,7 @@ async function openDash(page, version, core, plugin, testInfo) {
|
||||
const capability = await loadSDK(page, version, core, testInfo)
|
||||
test.skip(!capability.sdk, 'Actual SDK reports no MediaSource support; this engine has no DASH playback acceptance')
|
||||
await routeMedia(page)
|
||||
await testInfo.attach('dash-plugin-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, plugin, selected: plugin === 'published' ? { kind: 'published', sha256: hash(published) } : candidateProvenance }) })
|
||||
await page.addScriptTag({ content: plugin === 'published' ? published : candidate })
|
||||
await page.evaluate(() => {
|
||||
window.sdkErrors = []
|
||||
|
||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
let sdkCode
|
||||
@@ -38,11 +38,8 @@ test.beforeAll(async () => {
|
||||
}
|
||||
sdkCode = await code(sdk.release, 'package/dist/hls.min.js')
|
||||
publishedCode = await code(plugin.release, 'package/dist/artplayer-plugin-hls-control.js')
|
||||
// This task exercises source builds. Installed artifacts are a separate HLS-06 gate.
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'HLS source fixture cannot masquerade as an installed plugin')
|
||||
sourceCode = process.env.ARTPLAYER_HLS_ARTIFACT
|
||||
? fs.readFileSync(process.env.ARTPLAYER_HLS_ARTIFACT, 'utf8')
|
||||
: await compilePackage('artplayer-plugin-hls-control', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-hls-control', process.env.ARTPLAYER_HLS_ARTIFACT)
|
||||
sourceCode = candidate.code
|
||||
const manifest = JSON.parse(fs.readFileSync(new URL('./media/hls/manifest.json', import.meta.url)))
|
||||
media = new Map()
|
||||
for (const [name, expected] of Object.entries(manifest.files)) {
|
||||
@@ -52,11 +49,11 @@ test.beforeAll(async () => {
|
||||
assert.equal(bytes.length, expected.bytes)
|
||||
media.set(name, bytes)
|
||||
}
|
||||
evidence = { sdk: sdk.release, plugin: plugin.release, sourceSHA256: hash(sourceCode), candidate: process.env.ARTPLAYER_HLS_ARTIFACT || 'workspace source build', media: manifest, limitations: ['SDK worker disabled', 'local deterministic media', 'not an isolated installed package', 'no physical device certification'] }
|
||||
evidence = { sdk: sdk.release, plugin: plugin.release, sourceSHA256: hash(sourceCode), candidate: candidate.provenance, media: manifest, limitations: ['SDK worker disabled', 'local deterministic media', 'no physical device certification'] }
|
||||
})
|
||||
|
||||
async function openHls(page, core, plugin, testInfo, manifest = 'master.m3u8') {
|
||||
await testInfo.attach('hls-inputs', { contentType: 'application/json', body: JSON.stringify(evidence) })
|
||||
await testInfo.attach('hls-inputs', { contentType: 'application/json', body: JSON.stringify({ ...evidence, core, plugin, selected: plugin === 'published' ? { kind: 'published', sha256: hash(publishedCode) } : evidence.candidate }) })
|
||||
await page.route('**/hls-fixture/**', async (route) => {
|
||||
const name = new URL(route.request().url()).pathname.split('/').at(-1)
|
||||
const bytes = media.get(name)
|
||||
|
||||
@@ -3,22 +3,22 @@ import { Buffer } from 'node:buffer'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from '../helpers/load.js'
|
||||
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||
import { observeWorkers } from '../helpers/worker-observer.js'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
const matrix = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/hls-sdk-matrix.json', import.meta.url)))
|
||||
const grouped = fs.readFileSync(new URL('./fixtures/hls-grouped.m3u8', import.meta.url), 'utf8')
|
||||
let candidate
|
||||
let candidateProvenance
|
||||
let published
|
||||
const sdks = new Map()
|
||||
const media = new Map()
|
||||
|
||||
test.beforeAll(async () => {
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'HLS installed artifact map remains a separate HLS-06 gate')
|
||||
candidate = process.env.ARTPLAYER_HLS_ARTIFACT
|
||||
? fs.readFileSync(process.env.ARTPLAYER_HLS_ARTIFACT, 'utf8')
|
||||
: await compilePackage('artplayer-plugin-hls-control', 'umd')
|
||||
const input = await browserCandidate('artplayer-plugin-hls-control', process.env.ARTPLAYER_HLS_ARTIFACT)
|
||||
candidate = input.code
|
||||
candidateProvenance = input.provenance
|
||||
const baseline = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/hls-control-release.json', import.meta.url)))
|
||||
const bytes = readMember(await ensureArchive(baseline.release), 'package/dist/artplayer-plugin-hls-control.js')
|
||||
assert.equal(hash(bytes), baseline.release.files['package/dist/artplayer-plugin-hls-control.js'])
|
||||
@@ -55,7 +55,7 @@ test.afterEach(async ({ page }, testInfo) => {
|
||||
})
|
||||
|
||||
async function open(page, testInfo, release, core, plugin = 'candidate', manifest = 'master.m3u8') {
|
||||
await testInfo.attach('hls-sdk-inputs', { contentType: 'application/json', body: JSON.stringify({ sdk: release, core, plugin, pluginSHA256: hash(plugin === 'candidate' ? candidate : published), candidate: process.env.ARTPLAYER_HLS_ARTIFACT || 'workspace source build', media: Object.fromEntries([...media].map(([name, bytes]) => [name, hash(bytes)])), enableWorker: true }) })
|
||||
await testInfo.attach('hls-sdk-inputs', { contentType: 'application/json', body: JSON.stringify({ sdk: release, core, plugin, pluginSHA256: hash(plugin === 'candidate' ? candidate : published), selected: plugin === 'candidate' ? candidateProvenance : { kind: 'published', sha256: hash(published) }, media: Object.fromEntries([...media].map(([name, bytes]) => [name, hash(bytes)])), enableWorker: true }) })
|
||||
await page.route('**/hls-sdk-fixture/**', async (route) => {
|
||||
const name = new URL(route.request().url()).pathname.split('/').at(-1)
|
||||
const bytes = media.get(name)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import fs from 'node:fs'
|
||||
import assert from 'node:assert/strict'
|
||||
import process from 'node:process'
|
||||
import vm from 'node:vm'
|
||||
import { transform } from 'esbuild'
|
||||
import { verifyAutoThumbnailContract } from '../../refactor/scripts/auto-thumbnail-contract.mjs'
|
||||
import { readMember } from '../../refactor/scripts/releases.mjs'
|
||||
import { compilePackage } from './load.js'
|
||||
import { browserCandidate } from './browser-candidate.js'
|
||||
|
||||
export async function autoThumbnailHistorical() {
|
||||
const { baseline, archives, sources } = await verifyAutoThumbnailContract()
|
||||
@@ -26,9 +26,11 @@ export async function autoThumbnailHistorical() {
|
||||
}
|
||||
|
||||
export async function autoThumbnailCandidate() {
|
||||
if (process.env.ARTPLAYER_AUTO_THUMBNAIL_BASELINE === '1')
|
||||
if (process.env.ARTPLAYER_AUTO_THUMBNAIL_BASELINE === '1') {
|
||||
assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Installed auto-thumbnail checks cannot use the frozen workspace')
|
||||
return (await autoThumbnailHistorical()).find(item => item.name === 'frozen-workspace-js')
|
||||
return { name: 'candidate', code: process.env.ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT, 'utf8') : await compilePackage('artplayer-plugin-auto-thumbnail', 'umd') }
|
||||
}
|
||||
return { name: 'candidate', ...await browserCandidate('artplayer-plugin-auto-thumbnail', process.env.ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT) }
|
||||
}
|
||||
|
||||
// Controlled media events and deferred encodes are not evidence of native decoding.
|
||||
|
||||
@@ -8,6 +8,7 @@ import { checkFiles, checkPackages, publishedConsumer } from '../scripts/package
|
||||
import { removeConsumer, runtimeConsumer } from '../scripts/package-consumer.mjs'
|
||||
import { emitterContracts } from './contracts/emitter.js'
|
||||
import { ambilightCandidate } from './helpers/ambilight.js'
|
||||
import { autoThumbnailCandidate } from './helpers/auto-thumbnail.js'
|
||||
import { browserCandidate } from './helpers/browser-candidate.js'
|
||||
import { canvasCandidate } from './helpers/canvas.js'
|
||||
import { dpipCandidate } from './helpers/dpip.js'
|
||||
@@ -20,6 +21,7 @@ test('Additional browser packages cannot be mistaken for full release consumer a
|
||||
|
||||
test('Explicit installed plugin maps never fall back to source or frozen workspace', async () => {
|
||||
const keys = ['ARTPLAYER_BROWSER_ARTIFACTS', 'ARTPLAYER_AMBILIGHT_BASELINE', 'ARTPLAYER_CANVAS_BASELINE', 'ARTPLAYER_DPIP_BASELINE', 'ARTPLAYER_DPIP_ARTIFACT', 'ARTPLAYER_VTT_THUMBNAIL_BASELINE', 'ARTPLAYER_VTT_THUMBNAIL_ARTIFACT', 'ARTPLAYER_MULTIPLE_SUBTITLES_ARTIFACT']
|
||||
keys.push('ARTPLAYER_AUTO_THUMBNAIL_BASELINE', 'ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT')
|
||||
const previous = Object.fromEntries(keys.map(key => [key, process.env[key]]))
|
||||
try {
|
||||
process.env.ARTPLAYER_BROWSER_ARTIFACTS = path.resolve('refactor/.cache/absent-installed-plugin-map.json')
|
||||
@@ -31,6 +33,18 @@ test('Explicit installed plugin maps never fall back to source or frozen workspa
|
||||
delete process.env.ARTPLAYER_VTT_THUMBNAIL_BASELINE
|
||||
delete process.env.ARTPLAYER_VTT_THUMBNAIL_ARTIFACT
|
||||
delete process.env.ARTPLAYER_MULTIPLE_SUBTITLES_ARTIFACT
|
||||
delete process.env.ARTPLAYER_AUTO_THUMBNAIL_BASELINE
|
||||
delete process.env.ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT
|
||||
await assert.rejects(autoThumbnailCandidate(), { code: 'ENOENT' })
|
||||
process.env.ARTPLAYER_AUTO_THUMBNAIL_BASELINE = '1'
|
||||
await assert.rejects(autoThumbnailCandidate(), /cannot use the frozen workspace/)
|
||||
delete process.env.ARTPLAYER_AUTO_THUMBNAIL_BASELINE
|
||||
process.env.ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT = 'override.js'
|
||||
await assert.rejects(autoThumbnailCandidate(), /cannot override artplayer-plugin-auto-thumbnail artifact/)
|
||||
for (const name of ['artplayer-plugin-hls-control', 'artplayer-plugin-dash-control']) {
|
||||
await assert.rejects(browserCandidate(name), { code: 'ENOENT' })
|
||||
await assert.rejects(browserCandidate(name, 'override.js'), new RegExp(`cannot override ${name} artifact`))
|
||||
}
|
||||
await assert.rejects(ambilightCandidate(), { code: 'ENOENT' })
|
||||
await assert.rejects(canvasCandidate(), { code: 'ENOENT' })
|
||||
await assert.rejects(dpipCandidate(), { code: 'ENOENT' })
|
||||
|
||||
@@ -9,8 +9,8 @@ step through `ARTPLAYER_BROWSER_ARTIFACTS`. See
|
||||
browser scope and the remaining package-specific release gates.
|
||||
|
||||
Run `yarn test:package` with the pinned Node and Yarn after a frozen install. The
|
||||
default consumer scope is core and chapter. For Ambilight/Canvas/Document PiP/Ads/Audio Track/VTT Thumbnail/Multiple Subtitles browser work,
|
||||
run `yarn test:package --include=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`.
|
||||
default consumer scope is core and chapter. For Ambilight/Canvas/Document PiP/Ads/Audio Track/VTT Thumbnail/Multiple Subtitles/HLS Control/DASH Control/Auto Thumbnail browser work,
|
||||
run `yarn test:package --include=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`.
|
||||
These four additional packages have reviewed published contracts and use the same
|
||||
source snapshot/build/pack/offline-install/frozen-reinstall pipeline. Installed
|
||||
files are copied only after archive hash checks. The report explicitly separates
|
||||
|
||||
Reference in new issue
Block a user