test(ci): [CI-01] checkpoint verified Ads installed browser coverage

This commit is contained in:
Harvey Zhao committed 2026-09-15 01:31:28 +08:00
1 parent 18215b97c0
commit a03e5acc50
18 files changed
+2939 -25

No files matched your search

+1 -1
View File
@@ -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;没有通过重复、增大超时或跳过
制造全绿。撤销本检查点可恢复旧五包范围,不涉及生产源码回退。未推送或发布。
+1 -1
View File
@@ -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
View File
@@ -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)
+9
View File
@@ -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
View File
@@ -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",
+2 -2
View File
@@ -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
View File
@@ -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"
] ]
}, },
{ {
+19 -2
View File
@@ -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
+3 -1
View File
@@ -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) {
+1
View File
@@ -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()
+6 -6
View File
@@ -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 })] })
+6 -5
View File
@@ -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({
+22
View File
@@ -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) } }
}
+3
View File
@@ -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'
+3 -3
View File
@@ -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;