mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-23 05:41:20 -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
@@ -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