mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
test(ci): [CI-01] centralize installed roster and cover ASR and Cast
This commit is contained in:
1 parent
b90de99bc2
commit
8379ac7bbf
30 files changed
+3028
-58
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,artplayer-plugin-hls-control,artplayer-plugin-dash-control,artplayer-plugin-auto-thumbnail 2>&1 | tee refactor/.cache/ci/browser-packages.log
|
||||
yarn test:package --browser 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() }}
|
||||
|
||||
@@ -110,7 +110,7 @@ ARTPLAYER_BROWSER_ARTIFACTS is set; it rejects ARTPLAYER_ADS_ARTIFACT overrides
|
||||
and never falls back to source on an invalid installation. Each candidate case
|
||||
attaches its installed file/archive identity. Without a map, existing explicit
|
||||
artifact or source-build selection remains available. See the repository
|
||||
scripts/browser-validation/README.md for the six-package preparation command.
|
||||
scripts/browser-validation/README.md for the shared `yarn test:package --browser` command.
|
||||
This integration does not complete the separate Ads type, visibility or device gates.
|
||||
|
||||
Tests distinguish actual media decoding from injected errors/controlled clocks. Baseline and
|
||||
|
||||
@@ -159,3 +159,13 @@ Safari and physical devices remain PKG-ASR-05 acceptance work. CORS restrictions
|
||||
and main-video-only capture are explicit integration boundaries, not a claim
|
||||
that every media source can be recognized. Do not use the demo's external
|
||||
recognizer service as a prerequisite for local audio verification.
|
||||
|
||||
## Shared installed browser validation
|
||||
|
||||
Six browser files select verified installed ASR bytes through browser-candidate.js. The Audio Track combination independently verifies both installed plugins. Published ASR controls retain their frozen archives; attachments distinguish selected published, installed and source inputs. Tests cover native local PCM, direct/capture routing, CORS, volume/mute and ownership. Deliberately forced Firefox binding rejection remains labeled; no recognition service or physical speaker output is claimed.
|
||||
|
||||
Use `yarn test:package --browser`, then `yarn test:browser:installed`. The common
|
||||
roster in scripts/browser-validation/scope.ts drives both preparation and required
|
||||
inputs. Explicit artifact overrides are rejected when an installed map is present;
|
||||
missing or stale inputs fail without source fallback. Source mode retains deliberate
|
||||
artifact selection. See ../../refactor/changes/2026-09-15-CI-01-asr-cast-installed.md.
|
||||
@@ -95,7 +95,7 @@ demo still belong to Audio-06. See refactor/baselines/audio-types-validation.jso
|
||||
audio-fixture.js records the selected published or candidate input. The older test label "source audio" means the candidate slot; consult audio-inputs.selected for its actual origin. Native WAV capability controls remain separate from decoded AAC acceptance.
|
||||
|
||||
The shared `yarn test:browser:installed` roster includes this package after preparing
|
||||
the nine-package tarballs with `yarn test:package --include=...`; use the exact command
|
||||
the checked tarballs with `yarn test:package --browser`; see the scope rules
|
||||
in ../../scripts/browser-validation/README.md. Attachments identify candidate file,
|
||||
archive and source hashes. Missing or stale maps fail without source fallback.
|
||||
Without a map, source and deliberate artifact checks retain their existing behavior.
|
||||
|
||||
@@ -232,7 +232,7 @@ require the host's existing getter to have every generated-sheet field.
|
||||
|
||||
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
|
||||
Use `yarn test:package --browser` and the shared 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.
|
||||
|
||||
@@ -156,3 +156,13 @@ The installed consumer verifier compares both actual historical tarballs and an
|
||||
isolated candidate package, validates individual negative statement diagnostics,
|
||||
and checks runtime entry identity. The editor declaration is generated semantically
|
||||
from the root declaration. Keep internal `tsconfig.json` and source out of npm packs.
|
||||
|
||||
## Shared installed browser validation
|
||||
|
||||
chromecast-lifecycle.spec.js selects the verified installed bundle. It uses a controlled Cast SDK with real core DOM, clicks and local video; receiver discovery, actual Cast SDK and remote playback remain PKG-CAST-05. The artifact map must not be interpreted as physical device acceptance.
|
||||
|
||||
Use `yarn test:package --browser`, then `yarn test:browser:installed`. The common
|
||||
roster in scripts/browser-validation/scope.ts drives both preparation and required
|
||||
inputs. Explicit artifact overrides are rejected when an installed map is present;
|
||||
missing or stale inputs fail without source fallback. Source mode retains deliberate
|
||||
artifact selection. See ../../refactor/changes/2026-09-15-CI-01-asr-cast-installed.md.
|
||||
@@ -218,7 +218,7 @@ limitations, physical devices and full release acceptance remain separately trac
|
||||
|
||||
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
|
||||
Use `yarn test:package --browser` and the shared 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.
|
||||
|
||||
@@ -147,7 +147,7 @@ See ../../refactor/changes/2026-09-15-PKG-HLS-PACK-01-config.md.
|
||||
|
||||
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
|
||||
Use `yarn test:package --browser` and the shared 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.
|
||||
|
||||
@@ -189,7 +189,7 @@ See `../../refactor/baselines/multiple-subtitles-contract.md` for exact historic
|
||||
multipleSubtitlesCandidate uses browser-candidate.js for verified installed bytes. An installed map rejects ARTPLAYER_MULTIPLE_SUBTITLES_ARTIFACT overrides. Actual historical plugins and no-plugin controls retain their original inputs.
|
||||
|
||||
The shared `yarn test:browser:installed` roster includes this package after preparing
|
||||
the nine-package tarballs with `yarn test:package --include=...`; use the exact command
|
||||
the checked tarballs with `yarn test:package --browser`; see the scope rules
|
||||
in ../../scripts/browser-validation/README.md. Attachments identify candidate file,
|
||||
archive and source hashes. Missing or stale maps fail without source fallback.
|
||||
Without a map, source and deliberate artifact checks retain their existing behavior.
|
||||
|
||||
@@ -165,7 +165,7 @@ historical evidence and outstanding acceptance work.
|
||||
vttThumbnailCandidate uses browser-candidate.js for verified installed bytes. An installed map rejects ARTPLAYER_VTT_THUMBNAIL_BASELINE and ARTPLAYER_VTT_THUMBNAIL_ARTIFACT overrides. Frozen published control inputs and their cue-format differences remain explicit.
|
||||
|
||||
The shared `yarn test:browser:installed` roster includes this package after preparing
|
||||
the nine-package tarballs with `yarn test:package --include=...`; use the exact command
|
||||
the checked tarballs with `yarn test:package --browser`; see the scope rules
|
||||
in ../../scripts/browser-validation/README.md. Attachments identify candidate file,
|
||||
archive and source hashes. Missing or stale maps fail without source fallback.
|
||||
Without a map, source and deliberate artifact checks retain their existing behavior.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,57 @@
|
||||
# CI-01 统一包清单并接入 ASR、Chromecast 安装验证
|
||||
|
||||
## 工程与加载边界
|
||||
|
||||
新增 yarn test:package --browser,从 browser-validation/scope.ts 的 installedPackages
|
||||
生成额外包清单,与安装浏览器预检使用同一数据来源。默认 core/chapter 与显式
|
||||
--include 保留;未知/重复/空选项及 --browser 与 --include/--release 混用被拒绝。
|
||||
工作流、契约负例和维护文档同步,不能在 CI 偷换为手写部分包列表。
|
||||
此 CLI 属于固定 Node 24 工程工具,不改变消费者运行环境或公开播放器接口。
|
||||
|
||||
新增 ASR 六文件与 Chromecast 一文件。ASR 使用实际 WebAudio/Worklet、本地媒体、
|
||||
原生或明确强制的 capture fallback、音量/CORS/Audio Track 组合;组合分别核验
|
||||
ASR 和 Audio Track 安装身份。Chromecast 使用真实核心 DOM/点击/本地视频及受控
|
||||
SDK,不验证接收设备、发现或远端媒体。其余未知真实环境保持各自任务门槛。
|
||||
候选加载器拒绝安装 map 与显式 artifact 同时使用;已发布输入仍按冻结归档加载。
|
||||
|
||||
VAST 主测试 externalize 后替换 wrapper 依赖,不能直接换为完整 bundle 并冒充
|
||||
真实安装验收,因此未纳入这个范围;实际 IMA 路径继续独立验证。没有修改生产
|
||||
源码、公开 API、超时、业务断言、依赖或锁文件。历史包内说明中的硬编码清单
|
||||
改为指向 --browser 与共同清单,防止未来列表和文档漂移。
|
||||
|
||||
## 已验证的工程范围
|
||||
|
||||
Windows x64,Node 24.21.0、Yarn 1.22.22。--browser 实际创建十四包 run-N2u2Kr,
|
||||
正常构建/pack/独立安装/冻结复装与完整文件核验通过。通用消费者依然仅验证
|
||||
core/chapter 的 36 运行时、5 旧类型模式和 8 精确类型模式。
|
||||
|
||||
相关单元 357/357、工程 48/48、scoped lint、library 类型、严格工具链、工作流
|
||||
契约和 actionlint 1.7.12 通过(未调用 shellcheck/pyflakes)。初始未使用 import/
|
||||
顺序及既有测试行格式错误已改正;旧工作流负例依赖手写包名,修改为禁止手写
|
||||
部分名单后通过。中间失败日志保留,最终结果明确区分。
|
||||
|
||||
完整 installed collection 为 39 文件/1308 项;本轮实际执行新增七文件的 171 项,
|
||||
三引擎、workers=2、retries=0。结果、实际输入指纹与能力限制见机器证据。
|
||||
这不代表完整十四包矩阵或远端 CI 全绿;之前 Chapter/Audio/DASH 失败继续保留。
|
||||
部分既有包的文档措辞在准备快照后更新,发布前仍需重新打包绑定最终内容。
|
||||
|
||||
CI-01 仍 doing,ASR/CAST 真机门槛未关闭,没有推送或发布。回退此检查点恢复
|
||||
十二包名单和手写准备命令,不涉及生产代码回退。
|
||||
|
||||
## 实测结果
|
||||
|
||||
Chromium 153.0.8010.12 与 Firefox 155.0 各 57/57 通过;WebKit 26.6 为 15 通过、
|
||||
42 WebAudio 能力跳过。合计 129 通过、42 跳过、0 失败,耗时 173.947 秒,
|
||||
实际退出 0、无重试;这是新增范围的结果,不覆盖完整 1308 项安装清单。
|
||||
Chromecast 45 项均为受控 SDK 生命周期;ASR 84 项通过中 48 项选择候选,
|
||||
其余保留旧包控制。候选 ASR/Audio Track 的八项组合分别记录两个安装身份,
|
||||
不能把身份条数重复算作测试条数;在 skip 前记录的候选身份不计处理能力通过。
|
||||
|
||||
故意继承安装 map 后,source 入口清除它,三个 Chromium 定向用例 3/3 通过:
|
||||
ASR 原生 Worklet、ASR/Audio Track 组合、Cast 注册点击。四个实际选包身份均为
|
||||
source-build(组合包含两个包)。源码回归仍是定向范围,不代表全量源码矩阵。
|
||||
所有输入、命令、统计和 skip 注解见
|
||||
[机器证据](../baselines/ci-asr-cast-installed-validation.json)。归档目录为
|
||||
ci01-asr-cast-installed-report 与 ci01-asr-cast-source-report;原始日志和实际退出
|
||||
状态均保留。无新增运行失败,但 ASR 真机/物理输出、Cast 接收设备和整体发布
|
||||
门槛继续开放。
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
浏览器CI现在分别执行 `yarn test:browser:source` 和
|
||||
`yarn test:browser:installed`。前者清除继承的安装map并保留全部spec;后者要求已
|
||||
核验的core/chapter/Ambilight/Canvas/Document PiP/Ads/Audio Track/VTT Thumbnail/Multiple Subtitles/HLS Control/DASH Control/Auto Thumbnail安装,执行明确列出的installed子集。两步不
|
||||
核验的统一包清单,执行明确列出的 installed 子集;清单维护在
|
||||
`scripts/browser-validation/scope.ts`。两步不
|
||||
吞失败,普通失败后仍保存另一范围的证据,分别上传browser-source/browser-installed。
|
||||
入口与报告规则见[维护说明](../scripts/browser-validation/README.md)。source全量
|
||||
耗时/60分钟预算、其余插件安装矩阵与远端运行仍待CI-01/CI-04,不计为已通过。
|
||||
@@ -165,3 +166,7 @@ common.js/bootstrap.js 由 browser 下的 TS 生成,源代码进入 typecheck:
|
||||
和根 lint,产物由 check:site-assets 比较;不再对生成 common.js 应用源码 lint。
|
||||
build:ts 生成声明 URL 清单后重建站点浏览器产物,check:editor-types 保持只读。
|
||||
新增 test:site-editor 并接入 test:node,新增真实 Monaco 交互测试走现有三引擎矩阵。
|
||||
|
||||
安装准备使用 `yarn test:package --browser`,从 browser-validation/scope.ts 的同一
|
||||
包清单生成,不再在工作流复制列表。默认 core/chapter 消费者及显式 --include 保留;
|
||||
此选项不表示全生态类型、SDK 或发布准入。
|
||||
+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) [记录](changes/2026-09-15-CI-01-adaptive-installed.md) [记录](baselines/ci-adaptive-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)
|
||||
- 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,14 @@
|
||||
# 进度与证据
|
||||
|
||||
## CI-01 统一安装包清单并接入 ASR / Chromecast
|
||||
|
||||
新增 --browser 从同一清单准备十四包,实际安装核验通过;消除 CI 手写列表并
|
||||
保留默认/显式子集方式。新增七文件三引擎 171 项:129 通过、42 WebAudio 能力
|
||||
跳过;Cast 仅受控 SDK,设备门槛不变。源码定向 3/3、单元 357/357、工程 48/48
|
||||
通过,见[记录](changes/2026-09-15-CI-01-asr-cast-installed.md)。完整清单为
|
||||
39 文件/1308 项,本轮未全跑。197/263 完成,CI-01 继续 doing;下一步处理其余
|
||||
包的完整产物/资源映射,VAST 的依赖替换测试不能冒充已安装完整 bundle。
|
||||
|
||||
## CI-01 自适应控制和自动缩略图接入安装矩阵
|
||||
|
||||
十二包实际安装通过,清单扩展到 32 文件/1137 项。新增七文件三引擎实跑
|
||||
|
||||
@@ -90,10 +90,10 @@ 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,artplayer-plugin-hls-control,artplayer-plugin-dash-control,artplayer-plugin-auto-thumbnail '))
|
||||
const extraIndex = browser.steps.findIndex(step => step.run?.startsWith('yarn test:package --browser '))
|
||||
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')
|
||||
assert(extraIndex > Math.max(consumerIndex, reactIndex, vueIndex) && extraIndex < engineIndex, 'Prepare the shared installed browser roster after consumer probes and before browser checks')
|
||||
assert(!Object.hasOwn(browser.steps[extraIndex], 'if') && browser.steps[extraIndex].run.includes('GITHUB_ENV') && browser.steps[extraIndex].run.includes('ARTPLAYER_BROWSER_ARTIFACTS='), 'Always select the additional installed browser artifact map')
|
||||
assert(sourceEngineIndex > extraIndex && sourceEngineIndex < engineIndex, 'Retain complete source checks before the additional installed suite')
|
||||
for (const index of [sourceEngineIndex, engineIndex]) {
|
||||
|
||||
@@ -33,17 +33,20 @@ for (const [name, mutate] of [
|
||||
['conditional Node setup', w => w.jobs.checks.steps.find(s => s.uses?.startsWith('actions/setup-node@')).if = 'false'],
|
||||
['wrong consumer Node version', w => w.jobs['browser-smoke'].steps.find(s => s.id === 'consumer-node-20').with['node-version'] = '24'],
|
||||
['skipped installed consumer', w => w.jobs['browser-smoke'].steps.find(s => s.run?.includes('--expected-node 22.12.0')).if = 'false'],
|
||||
['missing browser plugin installation', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --include=')).run = 'echo omitted'],
|
||||
['missing Document PiP browser installation', (w) => {
|
||||
const step = w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --include='))
|
||||
step.run = step.run.replace(',artplayer-plugin-document-pip', '')
|
||||
['missing browser plugin installation', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --browser')).run = 'echo omitted'],
|
||||
['manual partial browser package roster', (w) => {
|
||||
const step = w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --browser'))
|
||||
step.run = step.run.replace('--browser', '--include=artplayer-plugin-ambilight')
|
||||
}],
|
||||
['skipped browser plugin installation', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --include=')).if = 'false'],
|
||||
['skipped browser plugin installation', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:package --browser')).if = 'false'],
|
||||
['missing source browser checks', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:browser:source ')).run = 'echo omitted'],
|
||||
['filtered source browser checks', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:browser:source ')).run += ' --grep subset'],
|
||||
['source failure prevents installed evidence', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:browser:installed ')).if = 'success()'],
|
||||
['ignored installed failure', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:browser:installed '))['continue-on-error'] = true],
|
||||
['missing separate source evidence', w => { const upload = w.jobs['browser-smoke'].steps.find(s => s.uses?.startsWith('actions/upload-artifact@')); upload.with.path = upload.with.path.replace('refactor/.cache/browser-source/\n', '') }],
|
||||
['missing separate source evidence', (w) => {
|
||||
const upload = w.jobs['browser-smoke'].steps.find(s => s.uses?.startsWith('actions/upload-artifact@'))
|
||||
upload.with.path = upload.with.path.replace('refactor/.cache/browser-source/\n', '')
|
||||
}],
|
||||
['browser runtime not restored', w => w.jobs['browser-smoke'].steps.find(s => s.id === 'restore-canonical-node').with = { 'node-version': '22.12.0', 'package-manager-cache': false }],
|
||||
['skipped React consumer', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:react-consumer')).if = 'false'],
|
||||
['removed React consumer', w => w.jobs['browser-smoke'].steps = w.jobs['browser-smoke'].steps.filter(s => !s.run?.startsWith('yarn test:react-consumer'))],
|
||||
|
||||
+3
-1
@@ -768,7 +768,9 @@
|
||||
"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"
|
||||
"baselines/ci-adaptive-installed-validation.json",
|
||||
"changes/2026-09-15-CI-01-asr-cast-installed.md",
|
||||
"baselines/ci-asr-cast-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,artplayer-plugin-hls-control,artplayer-plugin-dash-control,artplayer-plugin-auto-thumbnail`.
|
||||
Both launcher and config validate the selected twelve packages' installed hashes
|
||||
`yarn test:package --browser`.
|
||||
Both launcher and config validate the selected 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.
|
||||
@@ -83,3 +83,17 @@ 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.
|
||||
|
||||
`yarn test:package --browser` derives additional packages from installedPackages
|
||||
in scope.ts, so CI preparation and browser preflight share one roster. The default
|
||||
command still prepares core/chapter; --include retains explicit subsets. Unknown,
|
||||
duplicate, empty or conflicting --browser/--release/--include options fail before
|
||||
building. --browser is preparation, never full release acceptance.
|
||||
|
||||
ASR adds six native audio/routing/CORS files, including a composition that checks
|
||||
ASR and Audio Track identities separately. Historical inputs, unsupported WebAudio
|
||||
and deliberately forced fallback branches remain labeled. Chromecast adds its
|
||||
controlled SDK lifecycle file with actual core DOM/local media; it does not run
|
||||
a Cast receiver. VAST controlled tests externalize and replace a dependency, so
|
||||
they are not advertised as installed bundle coverage. Its real IMA suite retains
|
||||
its independent gate. See ../../refactor/changes/2026-09-15-CI-01-asr-cast-installed.md.
|
||||
@@ -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']
|
||||
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']
|
||||
export const installedTests = [
|
||||
'playback.spec.js',
|
||||
'lifecycle.spec.js',
|
||||
@@ -36,6 +36,13 @@ export const installedTests = [
|
||||
'auto-thumbnail.spec.js',
|
||||
'auto-thumbnail-lifecycle.spec.js',
|
||||
'auto-thumbnail-pixels.spec.js',
|
||||
'asr-audio.spec.js',
|
||||
'asr-playback.spec.js',
|
||||
'asr-fallback.spec.js',
|
||||
'asr-cors.spec.js',
|
||||
'asr-capture-cors.spec.js',
|
||||
'asr-audio-track.spec.js',
|
||||
'chromecast-lifecycle.spec.js',
|
||||
]
|
||||
|
||||
export function browserInvocation(scope: string, args: string[], environment: NodeJS.ProcessEnv) {
|
||||
|
||||
@@ -5,8 +5,21 @@ import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { ensureArchive, hash, readMember } from '../refactor/scripts/releases.mjs'
|
||||
import { installedPackages } from './browser-validation/scope.ts'
|
||||
import { consumerDirectory, names as defaultNames, readJson, removeConsumer, run, runtimeConsumer, typeConsumers, workspace, writeJson } from './package-consumer.mjs'
|
||||
|
||||
export function packageOptions(args) {
|
||||
assert(args.every(arg => ['--release', '--browser'].includes(arg) || arg.startsWith('--include=')), 'Unknown package-check option')
|
||||
const includes = args.filter(arg => arg.startsWith('--include='))
|
||||
assert(includes.length <= 1 && new Set(args).size === args.length, 'Duplicate package-check option')
|
||||
const browser = args.includes('--browser')
|
||||
const release = args.includes('--release')
|
||||
assert(!browser || (!release && includes.length === 0), 'Browser preparation cannot be combined with release or explicit includes')
|
||||
const include = browser ? installedPackages.filter(name => !defaultNames.includes(name)) : includes[0]?.slice('--include='.length).split(',') || []
|
||||
assert(include.every(Boolean) && new Set(include).size === include.length, 'Empty or duplicate additional package')
|
||||
return { release, include }
|
||||
}
|
||||
|
||||
export function checkFiles(manifest, files, historical = []) {
|
||||
for (const field of ['main', 'module', 'types', 'legacy']) {
|
||||
assert(typeof manifest[field] === 'string', `Missing ${field}: ${manifest.name}`)
|
||||
@@ -80,6 +93,8 @@ export async function checkPackages({ release = false, include = [] } = {}) {
|
||||
'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-asr': async () => (await import('../refactor/scripts/asr-contract.mjs')).verifyAsrContract(),
|
||||
'artplayer-plugin-chromecast': async () => (await import('../refactor/scripts/chromecast-contract.mjs')).verifyChromecastContract(),
|
||||
'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(),
|
||||
@@ -164,8 +179,7 @@ export async function checkPackages({ release = false, include = [] } = {}) {
|
||||
}
|
||||
|
||||
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
const include = process.argv.find(arg => arg.startsWith('--include='))?.slice('--include='.length).split(',') || []
|
||||
checkPackages({ release: process.argv.includes('--release'), include }).catch((error) => {
|
||||
checkPackages(packageOptions(process.argv.slice(2))).catch((error) => {
|
||||
console.error(error)
|
||||
process.exitCode = 1
|
||||
})
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
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'
|
||||
|
||||
let asrCode
|
||||
let audioCode
|
||||
let inputs
|
||||
test.beforeAll(async () => {
|
||||
expect(process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'These source/explicit artifact checks do not represent isolated installed packages').toBeFalsy()
|
||||
asrCode = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT, 'utf8') : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
audioCode = process.env.ARTPLAYER_AUDIO_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_AUDIO_ARTIFACT, 'utf8') : await compilePackage('artplayer-plugin-audio-track', 'umd')
|
||||
const asr = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
asrCode = asr.code
|
||||
const audio = await browserCandidate('artplayer-plugin-audio-track', process.env.ARTPLAYER_AUDIO_ARTIFACT)
|
||||
audioCode = audio.code
|
||||
const media = fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))
|
||||
const manifest = JSON.parse(fs.readFileSync(new URL('./media/audio-tone.json', import.meta.url)))
|
||||
expect(hash(media)).toBe(manifest.sha256)
|
||||
inputs = {
|
||||
asr: { input: process.env.ARTPLAYER_ASR_ARTIFACT || 'workspace source', sha256: hash(asrCode) },
|
||||
audioTrack: { input: process.env.ARTPLAYER_AUDIO_ARTIFACT || 'workspace source', sha256: hash(audioCode) },
|
||||
asr: { provenance: asr.provenance, sha256: hash(asrCode) },
|
||||
audioTrack: { provenance: audio.provenance, sha256: hash(audioCode) },
|
||||
media: { file: 'test/browser/media/audio-tone.m4a', sha256: hash(media), bytes: media.length },
|
||||
recognitionService: false,
|
||||
scope: 'Native media/WebAudio composition; not physical speaker, device, or isolated package acceptance',
|
||||
scope: 'Native media/WebAudio composition; not physical speaker or device acceptance',
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -2,14 +2,17 @@ import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { verifyAsrContract } from '../../refactor/scripts/asr-contract.mjs'
|
||||
import { 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 contract
|
||||
let candidateProvenance
|
||||
let candidateCode
|
||||
test.beforeAll(async () => {
|
||||
contract = await verifyAsrContract()
|
||||
candidateCode = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT) : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
candidateCode = candidate.code
|
||||
candidateProvenance = candidate.provenance
|
||||
})
|
||||
|
||||
for (const version of ['2.0.0', '2.1.0', 'candidate']) {
|
||||
@@ -18,7 +21,7 @@ for (const version of ['2.0.0', '2.1.0', 'candidate']) {
|
||||
const release = [contract.baseline.release, ...contract.baseline.previous].find(release => release.version === version)
|
||||
const code = version === 'candidate' ? candidateCode : readMember(contract.archives.get(version), 'package/dist/artplayer-plugin-asr.js')
|
||||
const media = fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))
|
||||
await testInfo.attach('asr-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, pluginSha256: hash(code), integrity: release?.integrity || null, candidate: process.env.ARTPLAYER_ASR_ARTIFACT || 'workspace source', mediaSha256: hash(media), media: 'local mono AAC 440 Hz tone', networkService: false }) })
|
||||
await testInfo.attach('asr-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, pluginSha256: hash(code), selected: version === 'candidate' ? candidateProvenance : { kind: 'published', version, sha256: hash(code) }, integrity: release?.integrity || null, mediaSha256: hash(media), media: 'local mono AAC 440 Hz tone', networkService: false }) })
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
const capabilities = await page.evaluate(() => ({ AudioContext: typeof window.AudioContext, webkitAudioContext: typeof window.webkitAudioContext, AudioWorkletNode: typeof window.AudioWorkletNode }))
|
||||
await testInfo.attach('asr-audio-capabilities', { contentType: 'application/json', body: JSON.stringify(capabilities) })
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
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'
|
||||
|
||||
let provenance
|
||||
let code
|
||||
test.beforeAll(async () => {
|
||||
expect(process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Explicit source/artifact tests do not represent installed packages').toBeFalsy()
|
||||
code = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT, 'utf8') : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
code = candidate.code
|
||||
provenance = candidate.provenance
|
||||
})
|
||||
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
@@ -33,7 +35,7 @@ for (const core of ['published', 'candidate']) {
|
||||
})
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
const capabilities = await page.evaluate(() => ({ context: typeof (window.AudioContext || window.webkitAudioContext), worklet: typeof window.AudioWorkletNode, capture: typeof HTMLMediaElement.prototype.captureStream, mozCapture: typeof HTMLMediaElement.prototype.mozCaptureStream }))
|
||||
await testInfo.attach('capture-cors-inputs', { contentType: 'application/json', body: JSON.stringify({ core, capabilities, plugin: process.env.ARTPLAYER_ASR_ARTIFACT || 'workspace source', pluginSha256: hash(code), mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), nativeCapture: true, forcedException: false, analyserBinding: false, physicalAudioOutput: false, scope: 'Zero direct bindings and native media clock progression preserve routing; no claim about physical speaker output' }) })
|
||||
await testInfo.attach('capture-cors-inputs', { contentType: 'application/json', body: JSON.stringify({ core, capabilities, provenance, pluginSha256: hash(code), mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), nativeCapture: true, forcedException: false, analyserBinding: false, physicalAudioOutput: false, scope: 'Zero direct bindings and native media clock progression preserve routing; no claim about physical speaker output' }) })
|
||||
if (capabilities.context === 'undefined') {
|
||||
expect(process.platform).toBe('win32')
|
||||
expect(testInfo.project.name).toBe('webkit')
|
||||
|
||||
@@ -2,14 +2,17 @@ import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { verifyAsrContract } from '../../refactor/scripts/asr-contract.mjs'
|
||||
import { 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 contract
|
||||
let candidateProvenance
|
||||
let candidateCode
|
||||
test.beforeAll(async () => {
|
||||
contract = await verifyAsrContract()
|
||||
candidateCode = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT) : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
candidateCode = candidate.code
|
||||
candidateProvenance = candidate.provenance
|
||||
})
|
||||
|
||||
for (const version of ['2.1.0', 'candidate']) {
|
||||
@@ -26,7 +29,7 @@ for (const version of ['2.1.0', 'candidate']) {
|
||||
test.skip(true, 'Windows WebKit lacks native WebAudio; this is not Safari CORS acceptance')
|
||||
}
|
||||
const code = version === 'candidate' ? candidateCode : readMember(contract.archives.get(version), 'package/dist/artplayer-plugin-asr.js')
|
||||
await testInfo.attach('asr-cors-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, scenario, pluginSha256: hash(code), mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), physicalAudioOutput: false, securityBypass: false }) })
|
||||
await testInfo.attach('asr-cors-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, scenario, pluginSha256: hash(code), selected: version === 'candidate' ? candidateProvenance : { kind: 'published', version, sha256: hash(code) }, mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), physicalAudioOutput: false, securityBypass: false }) })
|
||||
const responses = []
|
||||
page.on('response', (response) => {
|
||||
if (/\/test\/(?:asr-cors\.m4a|audio-tone\.m4a|asr-opaque-redirect)(?:\?|$)/u.test(response.url()))
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { verifyAsrContract } from '../../refactor/scripts/asr-contract.mjs'
|
||||
import { 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 contract
|
||||
let candidateProvenance
|
||||
let candidateCode
|
||||
test.beforeAll(async () => {
|
||||
contract = await verifyAsrContract()
|
||||
candidateCode = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT) : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
candidateCode = candidate.code
|
||||
candidateProvenance = candidate.provenance
|
||||
})
|
||||
|
||||
for (const { version, captureOnly } of [{ version: '2.1.0', captureOnly: false }, { version: 'candidate', captureOnly: false }, { version: 'candidate', captureOnly: true }]) {
|
||||
@@ -19,7 +21,7 @@ for (const { version, captureOnly } of [{ version: '2.1.0', captureOnly: false }
|
||||
await page.goto(`/test/player.html?core=${core}`)
|
||||
const capabilities = await page.evaluate(() => ({ context: typeof AudioContext, worklet: typeof AudioWorkletNode, capture: typeof HTMLMediaElement.prototype.captureStream, mozCapture: typeof HTMLMediaElement.prototype.mozCaptureStream }))
|
||||
const forceRejection = testInfo.project.name === 'firefox' && !captureOnly
|
||||
await testInfo.attach('asr-fallback-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, captureOnly, pluginSha256: hash(code), capabilities, forcedException: forceRejection, reason: captureOnly ? 'Explicit capture mode never binds the element; no forced exceptions' : forceRejection ? 'Firefox permits a second native media source; force only binding rejection to reach real captureStream/Worklet' : 'Native duplicate binding rejection', externalContext: 'Native media-element source remains owned and running', physicalOutput: false }) })
|
||||
await testInfo.attach('asr-fallback-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, captureOnly, pluginSha256: hash(code), selected: version === 'candidate' ? candidateProvenance : { kind: 'published', version, sha256: hash(code) }, capabilities, forcedException: forceRejection, reason: captureOnly ? 'Explicit capture mode never binds the element; no forced exceptions' : forceRejection ? 'Firefox permits a second native media source; force only binding rejection to reach real captureStream/Worklet' : 'Native duplicate binding rejection', externalContext: 'Native media-element source remains owned and running', physicalOutput: false }) })
|
||||
if (capabilities.context !== 'function') {
|
||||
expect(process.platform).toBe('win32')
|
||||
expect(testInfo.project.name).toBe('webkit')
|
||||
|
||||
@@ -2,14 +2,17 @@ import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { verifyAsrContract } from '../../refactor/scripts/asr-contract.mjs'
|
||||
import { 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 contract
|
||||
let candidateProvenance
|
||||
let candidateCode
|
||||
test.beforeAll(async () => {
|
||||
contract = await verifyAsrContract()
|
||||
candidateCode = process.env.ARTPLAYER_ASR_ARTIFACT ? fs.readFileSync(process.env.ARTPLAYER_ASR_ARTIFACT) : await compilePackage('artplayer-plugin-asr', 'umd')
|
||||
const candidate = await browserCandidate('artplayer-plugin-asr', process.env.ARTPLAYER_ASR_ARTIFACT)
|
||||
candidateCode = candidate.code
|
||||
candidateProvenance = candidate.provenance
|
||||
})
|
||||
|
||||
for (const version of ['2.1.0', 'candidate']) {
|
||||
@@ -23,7 +26,7 @@ for (const version of ['2.1.0', 'candidate']) {
|
||||
expect(testInfo.project.name).toBe('webkit')
|
||||
test.skip(true, 'Windows WebKit lacks native AudioContext/AudioWorkletNode')
|
||||
}
|
||||
await testInfo.attach('asr-playback-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, pluginSha256: hash(code), mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), meter: 'Native unity analyser inserted between plugin gain and destination', physicalAudioOutput: false }) })
|
||||
await testInfo.attach('asr-playback-inputs', { contentType: 'application/json', body: JSON.stringify({ version, core, pluginSha256: hash(code), selected: version === 'candidate' ? candidateProvenance : { kind: 'published', version, sha256: hash(code) }, mediaSha256: hash(fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url))), meter: 'Native unity analyser inserted between plugin gain and destination', physicalAudioOutput: false }) })
|
||||
await page.addScriptTag({ content: code.toString() })
|
||||
await page.evaluate(() => {
|
||||
const NativeContext = window.AudioContext
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
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'
|
||||
|
||||
let provenance
|
||||
let candidate
|
||||
test.beforeAll(async () => {
|
||||
candidate = process.env.ARTPLAYER_CHROMECAST_ARTIFACT
|
||||
? fs.readFileSync(process.env.ARTPLAYER_CHROMECAST_ARTIFACT, 'utf8')
|
||||
: await compilePackage('artplayer-plugin-chromecast', 'umd')
|
||||
const input = await browserCandidate('artplayer-plugin-chromecast', process.env.ARTPLAYER_CHROMECAST_ARTIFACT)
|
||||
candidate = input.code
|
||||
provenance = input.provenance
|
||||
})
|
||||
|
||||
async function setup(page, core, testInfo, loaded = true) {
|
||||
@@ -112,7 +112,7 @@ async function setup(page, core, testInfo, loaded = true) {
|
||||
}
|
||||
}, loaded)
|
||||
await expect.poll(() => page.evaluate(() => window.castPlayers.every(art => art.isReady))).toBe(true)
|
||||
await testInfo.attach('chromecast-controlled-browser-inputs', { contentType: 'application/json', body: JSON.stringify({ core, artifact: process.env.ARTPLAYER_CHROMECAST_ARTIFACT || 'candidate source', sha256: hash(candidate), sdk: 'controlled stub; no receiver, discovery, real SDK or Cast media playback acceptance', native: 'ArtPlayer core, DOM controls, browser click dispatch and local video' }) })
|
||||
await testInfo.attach('chromecast-controlled-browser-inputs', { contentType: 'application/json', body: JSON.stringify({ core, provenance, sha256: hash(candidate), sdk: 'controlled stub; no receiver, discovery, real SDK or Cast media playback acceptance', native: 'ArtPlayer core, DOM controls, browser click dispatch and local video' }) })
|
||||
return external
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
// eslint-disable-next-line test/no-import-node-test -- This fixture exercises the repository's Node test runner.
|
||||
import { test } from 'node:test'
|
||||
import { checkFiles, checkPackages, publishedConsumer } from '../scripts/package-check.mjs'
|
||||
import { installedPackages } from '../scripts/browser-validation/scope.ts'
|
||||
import { checkFiles, checkPackages, packageOptions, publishedConsumer } from '../scripts/package-check.mjs'
|
||||
import { removeConsumer, runtimeConsumer } from '../scripts/package-consumer.mjs'
|
||||
import { emitterContracts } from './contracts/emitter.js'
|
||||
import { ambilightCandidate } from './helpers/ambilight.js'
|
||||
@@ -15,6 +16,15 @@ import { dpipCandidate } from './helpers/dpip.js'
|
||||
import { multipleSubtitlesCandidate } from './helpers/multiple-subtitles.js'
|
||||
import { vttThumbnailCandidate } from './helpers/vtt-thumbnail.js'
|
||||
|
||||
test('Package CLI keeps legacy defaults and prepares the same roster the browser requires', () => {
|
||||
assert.deepEqual(packageOptions([]), { release: false, include: [] })
|
||||
assert.deepEqual(packageOptions(['--release']), { release: true, include: [] })
|
||||
assert.deepEqual(packageOptions(['--include=artplayer-plugin-asr']), { release: false, include: ['artplayer-plugin-asr'] })
|
||||
assert.deepEqual(['artplayer', 'artplayer-plugin-chapter', ...packageOptions(['--browser']).include], installedPackages)
|
||||
for (const args of [['--browser', '--release'], ['--browser', '--include=artplayer-plugin-asr'], ['--broser'], ['--include='], ['--include=x,x'], ['--include=x', '--include=y'], ['--browser', '--browser']])
|
||||
assert.throws(() => packageOptions(args))
|
||||
})
|
||||
|
||||
test('Additional browser packages cannot be mistaken for full release consumer acceptance', async () => {
|
||||
await assert.rejects(checkPackages({ release: true, include: ['artplayer-plugin-ambilight'] }), /not full release acceptance/)
|
||||
})
|
||||
@@ -41,7 +51,7 @@ test('Explicit installed plugin maps never fall back to source or frozen workspa
|
||||
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']) {
|
||||
for (const name of ['artplayer-plugin-hls-control', 'artplayer-plugin-dash-control', 'artplayer-plugin-asr', 'artplayer-plugin-chromecast']) {
|
||||
await assert.rejects(browserCandidate(name), { code: 'ENOENT' })
|
||||
await assert.rejects(browserCandidate(name, 'override.js'), new RegExp(`cannot override ${name} artifact`))
|
||||
}
|
||||
|
||||
@@ -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/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`.
|
||||
default consumer scope is core and chapter. For the shared installed browser scope,
|
||||
run `yarn test:package --browser`.
|
||||
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
|
||||
@@ -97,3 +97,7 @@ bundles or contradictory frozen-workspace flags fail instead of rebuilding sourc
|
||||
removed historical files, then deliberately removes an actual published default
|
||||
export and required entry in an isolated consumer to prove runtime failures are
|
||||
detected. It is part of `yarn test:node`.
|
||||
|
||||
The --browser option follows the shared installed browser roster automatically;
|
||||
do not copy a manual package list into CI. Explicit --include remains supported
|
||||
for a deliberate subset. --browser cannot combine with --include or --release.
|
||||
Reference in new issue
Block a user