mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-25 16:11:20 -08:00
test(ci): [CI-01] checkpoint verified Ads installed browser coverage
This commit is contained in:
1 parent
18215b97c0
commit
a03e5acc50
18 files changed
+2939
-25
No files matched your search
@@ -140,7 +140,7 @@ jobs:
|
|||||||
# These extra installed packages are required by the browser helpers.
|
# These extra installed packages are required by the browser helpers.
|
||||||
# Other ecosystem installation/SDK gates remain tracked by CI-01.
|
# Other ecosystem installation/SDK gates remain tracked by CI-01.
|
||||||
run: |
|
run: |
|
||||||
yarn test:package --include=artplayer-plugin-ambilight,artplayer-proxy-canvas,artplayer-plugin-document-pip 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 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`);'
|
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
|
- name: Run all source browser checks
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ regressions; `yarn test:browser test/browser/ads.spec.js` covers real local medi
|
|||||||
cores. `yarn typecheck` checks the strict package configuration. `yarn build artplayer-plugin-ads`
|
cores. `yarn typecheck` checks the strict package configuration. `yarn build artplayer-plugin-ads`
|
||||||
generates main/legacy/ESM through the repository build. Do not hand-edit dist or copied docs assets.
|
generates main/legacy/ESM through the repository build. Do not hand-edit dist or copied docs assets.
|
||||||
|
|
||||||
|
The CI installed browser subset also runs ads.spec.js and ads-ui.spec.js. Their
|
||||||
|
shared browser-candidate helper requires a fresh, hash-verified Ads tarball when
|
||||||
|
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.
|
||||||
|
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
|
Tests distinguish actual media decoding from injected errors/controlled clocks. Baseline and
|
||||||
open release gates live in [Ads validation](../../refactor/ads-validation.md). Public declaration
|
open release gates live in [Ads validation](../../refactor/ads-validation.md). Public declaration
|
||||||
reconciliation is recorded in PKG-ADS-04; complete historical distribution and demo validation
|
reconciliation is recorded in PKG-ADS-04; complete historical distribution and demo validation
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,55 @@
|
|||||||
|
# CI-01 接入 Ads 安装产物与完整六包回归
|
||||||
|
|
||||||
|
安装范围由五包扩展到六包,新增 Ads 的真实媒体和 UI 用例。整个 installed 入口
|
||||||
|
运行 426 项,425 通过、1 项 WebKit 章节清晰度切换失败,退出码 1;不是绿色 CI。
|
||||||
|
Ads 两文件在三个引擎中共 171 项全部通过,其中 108 项使用已校验的候选安装包,
|
||||||
|
其余保留真实旧版 Ads 对照。CI-01 与各包最终设备/分发门槛继续开放。
|
||||||
|
|
||||||
|
## 实现与边界
|
||||||
|
|
||||||
|
- package-check 的额外包名单接入 Ads 已有冻结契约,先核验五份历史归档、30 个
|
||||||
|
成员及来源,再按现有独立源码构建、pack、安装、冻结复装和完整成员校验流程执行。
|
||||||
|
- browser-validation 的统一名单、两个 Ads spec、CI 准备命令和工作流校验同步。
|
||||||
|
Node/类型通用消费者仍只覆盖 core/chapter,不把浏览器扩展冒充全包类型验收。
|
||||||
|
- 新增 test/helpers/browser-candidate.js:安装 map 存在时验证来源/产物并读取实际
|
||||||
|
安装文件,拒绝同时指定单包路径,失败不退回源码。无 map 时保留显式产物与
|
||||||
|
源码构建入口。候选附件记录文件、tarball、源码指纹;旧版附件保留原发布输入。
|
||||||
|
- 缺失 map 和冲突覆盖的 Node 反例已加入现有测试。没有修改 Ads/核心生产代码、
|
||||||
|
packageManager、锁文件、测试超时或断言。没有新增依赖。
|
||||||
|
|
||||||
|
维护入口为 [浏览器范围说明](../../scripts/browser-validation/README.md)、
|
||||||
|
[安装检查](../../test/package/README.md) 和 Ads ARCHITECTURE.md。
|
||||||
|
|
||||||
|
## 实测结果
|
||||||
|
|
||||||
|
Windows x64,Node 24.21.0、Yarn 1.22.22;Chromium 153.0.8010.12、Firefox
|
||||||
|
155.0、WebKit 26.6。包源码 HEAD 为 18215b97c0674667a5c451b341e922ed39f6b872,
|
||||||
|
本轮未提交的测试/工具差异另以指纹绑定。run-s8MkZT 的六包安装通过,通用
|
||||||
|
core/chapter 36 运行时、5 旧类型模式、8 精确类型模式通过。
|
||||||
|
|
||||||
|
`yarn test:browser:installed --workers=2` 无文件、引擎或 grep 过滤,无重试,
|
||||||
|
Playwright 耗时 432.371 秒。13 文件共 426 项:425 通过、1 失败、0 跳过。
|
||||||
|
Canvas/PiP 包含 12 项原生窗口播放及 6 项 WebKit 不支持记录;不能把后者算成
|
||||||
|
原生能力通过。Ads 解码、静音、倒计时、恢复主片、失败/拒绝、原生全屏、多实例
|
||||||
|
和真实 popup 用例均通过。没有执行移动后台/最小化或 IMA/VAST 验收。
|
||||||
|
|
||||||
|
源码入口另定向执行 Chromium 的 candidate core/candidate Ads 真实视频用例:
|
||||||
|
1/1 通过。启动时故意继承 installed map,source 入口清除它;附件确认为
|
||||||
|
source-build。这证明本次修改保留该开发路径,不代表重跑全部 source 测试。
|
||||||
|
|
||||||
|
Node 工程测试 46/46、scoped ESLint、library 严格类型、工作流契约、actionlint
|
||||||
|
1.7.12(未调用 shellcheck/pyflakes)与严格工具链通过。远端 Actions 尚未运行。
|
||||||
|
结果、输入附件、命令与日志摘要见 [机器证据](../baselines/ci-ads-installed-validation.json)。
|
||||||
|
|
||||||
|
## 保留的章节失败
|
||||||
|
|
||||||
|
失败是 WebKit 的 candidate core/candidate chapter 清晰度切换,在等待
|
||||||
|
`!video.seeking && video.readyState >= 2` 时超时。restart 在页面 3552 ms 已触发,
|
||||||
|
第一轮 seeked 在 3597 ms;trace 中第一次读取返回 false,第二次调用耗时
|
||||||
|
9939.104 ms 后仍返回 false。之后状态附件记录第二轮 seeking、canplay,媒体没有
|
||||||
|
error。它不同于之前“没及时观察到 restart”的具体阶段,不能据此直接断言同一
|
||||||
|
根因、网络失败或 Ads 回归。调用延迟及底层媒体/渲染原因仍待 PKG-CHAPTER-05
|
||||||
|
调查,补入 CHAPTER-TIMING-01,保持 open。
|
||||||
|
|
||||||
|
原始报告/trace 保存在 ci01-ads-installed-report;没有通过重复、增大超时或跳过
|
||||||
|
制造全绿。撤销本检查点可恢复旧五包范围,不涉及生产源码回退。未推送或发布。
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
浏览器CI现在分别执行 `yarn test:browser:source` 和
|
浏览器CI现在分别执行 `yarn test:browser:source` 和
|
||||||
`yarn test:browser:installed`。前者清除继承的安装map并保留全部spec;后者要求已
|
`yarn test:browser:installed`。前者清除继承的安装map并保留全部spec;后者要求已
|
||||||
核验的core/chapter/Ambilight/Canvas/Document PiP安装,执行明确列出的installed子集。两步不
|
核验的core/chapter/Ambilight/Canvas/Document PiP/Ads安装,执行明确列出的installed子集。两步不
|
||||||
吞失败,普通失败后仍保存另一范围的证据,分别上传browser-source/browser-installed。
|
吞失败,普通失败后仍保存另一范围的证据,分别上传browser-source/browser-installed。
|
||||||
入口与报告规则见[维护说明](../scripts/browser-validation/README.md)。source全量
|
入口与报告规则见[维护说明](../scripts/browser-validation/README.md)。source全量
|
||||||
耗时/60分钟预算、其余插件安装矩阵与远端运行仍待CI-01/CI-04,不计为已通过。
|
耗时/60分钟预算、其余插件安装矩阵与远端运行仍待CI-01/CI-04,不计为已通过。
|
||||||
|
|||||||
+1
-1
@@ -508,7 +508,7 @@
|
|||||||
- ENG-09: [记录](changes/2026-09-12-ENG-09-integration.md) [记录](baselines/engineering-integration.json)
|
- 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-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)
|
- 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)
|
- 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)
|
||||||
- CI-02: [记录](changes/2026-09-14-CI-02-pages-artifact.md) [记录](baselines/pages-artifact-validation.json) [记录](pages-deployment.md)
|
- 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)
|
- 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)
|
- CORE-01: [记录](changes/2026-09-10-CORE-01-typed-utils.md) [记录](baselines/core-utils-validation.json)
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# 进度与证据
|
# 进度与证据
|
||||||
|
|
||||||
|
## CI-01 Ads 接入安装矩阵,完整回归保留章节失败
|
||||||
|
|
||||||
|
六包统一 installed 范围实测 426 项:425 通过、1 项 WebKit 章节切画质等待失败;
|
||||||
|
新增 Ads 171 项全过,108 项确认加载已验证候选 tarball。源码模式定向真实播放
|
||||||
|
1/1、Node 工程 46/46、类型/CI 静态检查通过。失败 trace 的媒体状态读取耗时
|
||||||
|
9.94 秒,原因未确认,CHAPTER-TIMING-01 保持 open;没有扩大超时或重跑覆盖。
|
||||||
|
详见[记录](changes/2026-09-15-CI-01-ads-installed.md)。CI-01 继续 doing,
|
||||||
|
完成数保持 196/262;下一步调查章节读取延迟并继续其余包安装覆盖。
|
||||||
|
|
||||||
## MOD-01 Bun 隔离安装评估完成,保留 Yarn
|
## MOD-01 Bun 隔离安装评估完成,保留 Yarn
|
||||||
|
|
||||||
固定 Bun 1.4.2 与 Yarn 1.22.22 在仓库外同提交安装。Bun 初次冻结迁移失败,
|
固定 Bun 1.4.2 与 Yarn 1.22.22 在仓库外同提交安装。Bun 初次冻结迁移失败,
|
||||||
|
|||||||
+5
-2
@@ -2916,10 +2916,13 @@
|
|||||||
"test/browser/chapter-combinations.spec.js",
|
"test/browser/chapter-combinations.spec.js",
|
||||||
"refactor/changes/2026-09-12-PKG-CHAPTER-05-combinations.md",
|
"refactor/changes/2026-09-12-PKG-CHAPTER-05-combinations.md",
|
||||||
"refactor/changes/2026-09-14-PKG-CHAPTER-05-timing.md",
|
"refactor/changes/2026-09-14-PKG-CHAPTER-05-timing.md",
|
||||||
"refactor/baselines/chapter-timing-observations.json"
|
"refactor/baselines/chapter-timing-observations.json",
|
||||||
|
"refactor/baselines/ci-ads-installed-validation.json",
|
||||||
|
"refactor/changes/2026-09-15-CI-01-ads-installed.md"
|
||||||
],
|
],
|
||||||
"compatibleResolution": "记录原生事件和绝对/相对时序,进一步区分媒体驱动耗时、夹具和核心源操作;未证明原因前不改核心、不扩大超时或重复到绿灯。",
|
"compatibleResolution": "记录原生事件和绝对/相对时序,进一步区分媒体驱动耗时、夹具和核心源操作;未证明原因前不改核心、不扩大超时或重复到绿灯。",
|
||||||
"closureCriteria": "确认先前超时的来源并有对应可靠回归;后续单次通过不足以关闭。"
|
"closureCriteria": "确认先前超时的来源并有对应可靠回归;后续单次通过不足以关闭。",
|
||||||
|
"workspaceState": "Six-package installed run: WebKit candidate/core Chapter failed after restart while waiting for non-seeking readyState>=2. A trace evaluation took 9939.104 ms and returned false; initial seeked had already fired, followed later by another seeking/canplay. This is a different observed phase from the previous restart timeout; common root cause remains unconfirmed. Keep both failures and investigate without relaxing timeouts."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "DASH-SDK-01",
|
"id": "DASH-SDK-01",
|
||||||
|
|||||||
@@ -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')
|
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(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')
|
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 '))
|
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 '))
|
||||||
const sourceEngineIndex = browser.steps.findIndex(step => step.run === 'yarn test:browser:source 2>&1 | tee refactor/.cache/ci/browser-source.log')
|
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')
|
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 after consumer probes and before browser checks')
|
assert(extraIndex > Math.max(consumerIndex, reactIndex, vueIndex) && extraIndex < engineIndex, 'Prepare installed Ambilight/Canvas/Document PiP/Ads 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(!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')
|
assert(sourceEngineIndex > extraIndex && sourceEngineIndex < engineIndex, 'Retain complete source checks before the additional installed suite')
|
||||||
for (const index of [sourceEngineIndex, engineIndex]) {
|
for (const index of [sourceEngineIndex, engineIndex]) {
|
||||||
|
|||||||
+3
-1
@@ -762,7 +762,9 @@
|
|||||||
"changes/2026-09-14-CI-01-installed-full.md",
|
"changes/2026-09-14-CI-01-installed-full.md",
|
||||||
"baselines/ci-installed-full-validation.json",
|
"baselines/ci-installed-full-validation.json",
|
||||||
"changes/2026-09-14-CI-01-source-chromium.md",
|
"changes/2026-09-14-CI-01-source-chromium.md",
|
||||||
"baselines/ci-source-chromium-validation.json"
|
"baselines/ci-source-chromium-validation.json",
|
||||||
|
"changes/2026-09-15-CI-01-ads-installed.md",
|
||||||
|
"baselines/ci-ads-installed-validation.json"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,12 +14,21 @@ also retains explicit historical and committed-artifact cases; its name does not
|
|||||||
promise that every dependency is rebuilt from current source in every test.
|
promise that every dependency is rebuilt from current source in every test.
|
||||||
|
|
||||||
`yarn test:browser:installed` requires ARTPLAYER_BROWSER_ARTIFACTS from
|
`yarn test:browser:installed` requires ARTPLAYER_BROWSER_ARTIFACTS from
|
||||||
`yarn test:package --include=artplayer-plugin-ambilight,artplayer-proxy-canvas,artplayer-plugin-document-pip`.
|
`yarn test:package --include=artplayer-plugin-ambilight,artplayer-proxy-canvas,artplayer-plugin-document-pip,artplayer-plugin-ads`.
|
||||||
Both launcher and config validate the selected five packages' installed hashes
|
Both launcher and config validate the selected six packages' installed hashes
|
||||||
and source/build freshness. `scope.ts` lists the currently supported installed
|
and source/build freshness. `scope.ts` lists the currently supported installed
|
||||||
test files. This is a growing installed subset, not full ecosystem acceptance.
|
test files. This is a growing installed subset, not full ecosystem acceptance.
|
||||||
Source checks remain complete when the installed list grows.
|
Source checks remain complete when the installed list grows.
|
||||||
|
|
||||||
|
Ads media/lifecycle and UI files use `test/helpers/browser-candidate.js` to select
|
||||||
|
the verified installed plugin whenever an artifact map is present. An additional
|
||||||
|
ARTPLAYER_ADS_ARTIFACT override is rejected instead of mixing candidates. Missing,
|
||||||
|
stale or changed installations fail before source compilation; each candidate
|
||||||
|
case attaches installed file, archive and source identities. Explicit published
|
||||||
|
Ads/core controls still use their frozen old inputs. Without a map the same files
|
||||||
|
keep source or explicitly selected artifact behavior. This does not cover VAST,
|
||||||
|
Ads editor types, the separate native-visibility suite or physical devices.
|
||||||
|
|
||||||
`scope.ts` owns the typed scope, package/test roster, argument policy and report
|
`scope.ts` owns the typed scope, package/test roster, argument policy and report
|
||||||
paths. The two thin Playwright configs preserve the base engine, retry, timeout
|
paths. The two thin Playwright configs preserve the base engine, retry, timeout
|
||||||
and server settings. `../browser-check.mjs` owns preflight, child environment,
|
and server settings. `../browser-check.mjs` owns preflight, child environment,
|
||||||
@@ -40,6 +49,14 @@ per-engine/file counts and limitations; this is not full ecosystem or remote CI.
|
|||||||
Local `--grep`, file names, workers and project options are supported for diagnosis;
|
Local `--grep`, file names, workers and project options are supported for diagnosis;
|
||||||
config/output/report overrides and passing with zero tests are rejected.
|
config/output/report overrides and passing with zero tests are rejected.
|
||||||
|
|
||||||
|
The six-package Ads expansion ran 426 cases across 13 files: 425 passed and one
|
||||||
|
WebKit candidate Chapter quality-readiness check failed. All 171 Ads cases passed,
|
||||||
|
including 108 with verified candidate tarballs; this is not a green full suite.
|
||||||
|
The trace includes a 9.94-second media-state evaluation and remains open under
|
||||||
|
CHAPTER-TIMING-01. A separate targeted Chromium source-build Ads case passed.
|
||||||
|
See `../../refactor/baselines/ci-ads-installed-validation.json`; old reports and
|
||||||
|
the actual exit 1 remain intact, without retries or increased timeouts.
|
||||||
|
|
||||||
CI executes both scopes with `if: !cancelled()` and no continue-on-error. An
|
CI executes both scopes with `if: !cancelled()` and no continue-on-error. An
|
||||||
ordinary source failure still permits installed evidence, while the failed step
|
ordinary source failure still permits installed evidence, while the failed step
|
||||||
keeps the job failed. Both report directories upload with always(). Node/runtime
|
keeps the job failed. Both report directories upload with always(). Node/runtime
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { PlaywrightTestConfig } from '@playwright/test'
|
|||||||
import assert from 'node:assert/strict'
|
import assert from 'node:assert/strict'
|
||||||
|
|
||||||
export type BrowserScope = 'source' | 'installed'
|
export type BrowserScope = 'source' | 'installed'
|
||||||
export const installedPackages = ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-ambilight', 'artplayer-proxy-canvas', 'artplayer-plugin-document-pip']
|
export const installedPackages = ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-ambilight', 'artplayer-proxy-canvas', 'artplayer-plugin-document-pip', 'artplayer-plugin-ads']
|
||||||
export const installedTests = [
|
export const installedTests = [
|
||||||
'playback.spec.js',
|
'playback.spec.js',
|
||||||
'lifecycle.spec.js',
|
'lifecycle.spec.js',
|
||||||
@@ -15,6 +15,8 @@ export const installedTests = [
|
|||||||
'canvas-lifecycle.spec.js',
|
'canvas-lifecycle.spec.js',
|
||||||
'canvas-subtitles.spec.js',
|
'canvas-subtitles.spec.js',
|
||||||
'canvas-dpip.spec.js',
|
'canvas-dpip.spec.js',
|
||||||
|
'ads.spec.js',
|
||||||
|
'ads-ui.spec.js',
|
||||||
]
|
]
|
||||||
|
|
||||||
export function browserInvocation(scope: string, args: string[], environment: NodeJS.ProcessEnv) {
|
export function browserInvocation(scope: string, args: string[], environment: NodeJS.ProcessEnv) {
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export async function checkPackages({ release = false, include = [] } = {}) {
|
|||||||
'artplayer-plugin-ambilight': async () => (await import('../refactor/scripts/ambilight-contract.mjs')).verifyAmbilightContract(),
|
'artplayer-plugin-ambilight': async () => (await import('../refactor/scripts/ambilight-contract.mjs')).verifyAmbilightContract(),
|
||||||
'artplayer-proxy-canvas': async () => (await import('../refactor/scripts/canvas-contract.mjs')).verifyCanvasContract(),
|
'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-document-pip': async () => (await import('../refactor/scripts/dpip-contract.mjs')).verifyDpipContract(),
|
||||||
|
'artplayer-plugin-ads': async () => (await import('../refactor/scripts/ads-contract.mjs')).verifyAdsContract(),
|
||||||
}
|
}
|
||||||
assert(new Set(include).size === include.length, 'Duplicate additional package')
|
assert(new Set(include).size === include.length, 'Duplicate additional package')
|
||||||
const historicalFiles = new Map()
|
const historicalFiles = new Map()
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import fs from 'node:fs'
|
|
||||||
import process from 'node:process'
|
import process from 'node:process'
|
||||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||||
import { compilePackage } from '../helpers/load.js'
|
import { browserCandidate } from '../helpers/browser-candidate.js'
|
||||||
import { expect, test } from './fixtures.js'
|
import { expect, test } from './fixtures.js'
|
||||||
|
|
||||||
let candidate
|
let candidate
|
||||||
|
let provenance
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
candidate = process.env.ARTPLAYER_ADS_ARTIFACT
|
const input = await browserCandidate('artplayer-plugin-ads', process.env.ARTPLAYER_ADS_ARTIFACT)
|
||||||
? fs.readFileSync(process.env.ARTPLAYER_ADS_ARTIFACT, 'utf8')
|
candidate = input.code
|
||||||
: await compilePackage('artplayer-plugin-ads', 'umd')
|
provenance = input.provenance
|
||||||
})
|
})
|
||||||
|
|
||||||
async function setup(page, core, testInfo, option = {}) {
|
async function setup(page, core, testInfo, option = {}) {
|
||||||
await page.goto(`/test/player.html?core=${core}`)
|
await page.goto(`/test/player.html?core=${core}`)
|
||||||
await page.addScriptTag({ content: candidate })
|
await page.addScriptTag({ content: candidate })
|
||||||
await testInfo.attach('ads-ui-inputs', { contentType: 'application/json', body: JSON.stringify({ core, artifact: process.env.ARTPLAYER_ADS_ARTIFACT || 'workspace source build', sha256: hash(candidate) }) })
|
await testInfo.attach('ads-ui-inputs', { contentType: 'application/json', body: JSON.stringify({ core, artifact: provenance, sha256: hash(candidate) }) })
|
||||||
await page.evaluate((option) => {
|
await page.evaluate((option) => {
|
||||||
window.adsEvents = []
|
window.adsEvents = []
|
||||||
window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true, mutex: false, plugins: [window.artplayerPluginAds({ html: 'ad', totalDuration: 60, playDuration: 0, ...option })] })
|
window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true, mutex: false, plugins: [window.artplayerPluginAds({ html: 'ad', totalDuration: 60, playDuration: 0, ...option })] })
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import assert from 'node:assert/strict'
|
|||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import process from 'node:process'
|
import process from 'node:process'
|
||||||
import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs'
|
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'
|
import { expect, test } from './fixtures.js'
|
||||||
|
|
||||||
let published
|
let published
|
||||||
let candidate
|
let candidate
|
||||||
let release
|
let release
|
||||||
|
let provenance
|
||||||
|
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
release = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/ads-release.json', import.meta.url))).release
|
release = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/ads-release.json', import.meta.url))).release
|
||||||
@@ -15,9 +16,9 @@ test.beforeAll(async () => {
|
|||||||
const bytes = readMember(await ensureArchive(release), member)
|
const bytes = readMember(await ensureArchive(release), member)
|
||||||
assert.equal(hash(bytes), release.files[member])
|
assert.equal(hash(bytes), release.files[member])
|
||||||
published = bytes.toString()
|
published = bytes.toString()
|
||||||
candidate = process.env.ARTPLAYER_ADS_ARTIFACT
|
const input = await browserCandidate('artplayer-plugin-ads', process.env.ARTPLAYER_ADS_ARTIFACT)
|
||||||
? fs.readFileSync(process.env.ARTPLAYER_ADS_ARTIFACT, 'utf8')
|
candidate = input.code
|
||||||
: await compilePackage('artplayer-plugin-ads', 'umd')
|
provenance = input.provenance
|
||||||
})
|
})
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
test.afterEach(async ({ page }, testInfo) => {
|
||||||
@@ -45,7 +46,7 @@ async function openAds(page, core, plugin, option, testInfo, start = true) {
|
|||||||
await page.goto(`/test/player.html?core=${core}`)
|
await page.goto(`/test/player.html?core=${core}`)
|
||||||
const code = plugin === 'published' ? published : candidate
|
const code = plugin === 'published' ? published : candidate
|
||||||
await page.addScriptTag({ content: code })
|
await page.addScriptTag({ content: code })
|
||||||
await testInfo.attach('ads-inputs', { contentType: 'application/json', body: JSON.stringify({ core, plugin, release: plugin === 'published' ? release : undefined, sha256: hash(code), artifact: plugin === 'candidate' ? process.env.ARTPLAYER_ADS_ARTIFACT || 'workspace source build' : undefined }) })
|
await testInfo.attach('ads-inputs', { contentType: 'application/json', body: JSON.stringify({ core, plugin, release: plugin === 'published' ? release : undefined, sha256: hash(code), artifact: plugin === 'candidate' ? provenance : undefined }) })
|
||||||
await page.evaluate((option) => {
|
await page.evaluate((option) => {
|
||||||
window.adsEvents = []
|
window.adsEvents = []
|
||||||
window.art = new window.Artplayer({
|
window.art = new window.Artplayer({
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import process from 'node:process'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||||
|
import { verifyInstalledArtifacts } from '../../scripts/installed-artifacts.mjs'
|
||||||
|
import { compilePackage } from './load.js'
|
||||||
|
|
||||||
|
const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||||
|
|
||||||
|
export async function browserCandidate(name, artifact) {
|
||||||
|
const map = process.env.ARTPLAYER_BROWSER_ARTIFACTS
|
||||||
|
if (map) {
|
||||||
|
assert(!artifact, `Installed browser checks cannot override ${name} artifact`)
|
||||||
|
const { inputs } = verifyInstalledArtifacts(root, map, ['artplayer', 'artplayer-plugin-chapter', name])
|
||||||
|
const input = inputs.find(input => input.name === name)
|
||||||
|
const code = fs.readFileSync(input.file, 'utf8')
|
||||||
|
return { code, provenance: { kind: 'installed', ...input } }
|
||||||
|
}
|
||||||
|
const code = artifact ? fs.readFileSync(artifact, 'utf8') : await compilePackage(name, 'umd')
|
||||||
|
return { code, provenance: { kind: artifact ? 'explicit-artifact' : 'source-build', file: artifact || null, sha256: hash(code) } }
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { checkFiles, checkPackages, publishedConsumer } from '../scripts/package
|
|||||||
import { removeConsumer, runtimeConsumer } from '../scripts/package-consumer.mjs'
|
import { removeConsumer, runtimeConsumer } from '../scripts/package-consumer.mjs'
|
||||||
import { emitterContracts } from './contracts/emitter.js'
|
import { emitterContracts } from './contracts/emitter.js'
|
||||||
import { ambilightCandidate } from './helpers/ambilight.js'
|
import { ambilightCandidate } from './helpers/ambilight.js'
|
||||||
|
import { browserCandidate } from './helpers/browser-candidate.js'
|
||||||
import { canvasCandidate } from './helpers/canvas.js'
|
import { canvasCandidate } from './helpers/canvas.js'
|
||||||
import { dpipCandidate } from './helpers/dpip.js'
|
import { dpipCandidate } from './helpers/dpip.js'
|
||||||
|
|
||||||
@@ -28,6 +29,8 @@ test('Explicit installed plugin maps never fall back to source or frozen workspa
|
|||||||
await assert.rejects(ambilightCandidate(), { code: 'ENOENT' })
|
await assert.rejects(ambilightCandidate(), { code: 'ENOENT' })
|
||||||
await assert.rejects(canvasCandidate(), { code: 'ENOENT' })
|
await assert.rejects(canvasCandidate(), { code: 'ENOENT' })
|
||||||
await assert.rejects(dpipCandidate(), { code: 'ENOENT' })
|
await assert.rejects(dpipCandidate(), { code: 'ENOENT' })
|
||||||
|
await assert.rejects(browserCandidate('artplayer-plugin-ads'), { code: 'ENOENT' })
|
||||||
|
await assert.rejects(browserCandidate('artplayer-plugin-ads', 'override.js'), /cannot override artplayer-plugin-ads artifact/)
|
||||||
process.env.ARTPLAYER_AMBILIGHT_BASELINE = '1'
|
process.env.ARTPLAYER_AMBILIGHT_BASELINE = '1'
|
||||||
process.env.ARTPLAYER_CANVAS_BASELINE = '1'
|
process.env.ARTPLAYER_CANVAS_BASELINE = '1'
|
||||||
process.env.ARTPLAYER_DPIP_BASELINE = '1'
|
process.env.ARTPLAYER_DPIP_BASELINE = '1'
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ step through `ARTPLAYER_BROWSER_ARTIFACTS`. See
|
|||||||
browser scope and the remaining package-specific release gates.
|
browser scope and the remaining package-specific release gates.
|
||||||
|
|
||||||
Run `yarn test:package` with the pinned Node and Yarn after a frozen install. The
|
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 browser work,
|
default consumer scope is core and chapter. For Ambilight/Canvas/Document PiP/Ads browser work,
|
||||||
run `yarn test:package --include=artplayer-plugin-ambilight,artplayer-proxy-canvas,artplayer-plugin-document-pip`.
|
run `yarn test:package --include=artplayer-plugin-ambilight,artplayer-proxy-canvas,artplayer-plugin-document-pip,artplayer-plugin-ads`.
|
||||||
These three additional packages have reviewed published contracts and use the same
|
These four additional packages have reviewed published contracts and use the same
|
||||||
source snapshot/build/pack/offline-install/frozen-reinstall pipeline. Installed
|
source snapshot/build/pack/offline-install/frozen-reinstall pipeline. Installed
|
||||||
files are copied only after archive hash checks. The report explicitly separates
|
files are copied only after archive hash checks. The report explicitly separates
|
||||||
the core/chapter runtime/type scope from the additional browser package scope;
|
the core/chapter runtime/type scope from the additional browser package scope;
|
||||||
|
|||||||
Reference in new issue
Block a user