diff --git a/package.json b/package.json index 722e878d1..34915226f 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,8 @@ "test:browser:source": "node scripts/browser-check.mjs source", "test:browser:installed": "node scripts/browser-check.mjs installed", "test:vast-types": "node --test refactor/scripts/vast-types.test.mjs", - "test:vast-types-package": "node refactor/scripts/vast-package-types.mjs" + "test:vast-types-package": "node refactor/scripts/vast-package-types.mjs", + "test:vast-native": "playwright test --config playwright.vast-native.config.js" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/packages/artplayer-plugin-vast/ARCHITECTURE.md b/packages/artplayer-plugin-vast/ARCHITECTURE.md index 4e73b2891..263705022 100644 --- a/packages/artplayer-plugin-vast/ARCHITECTURE.md +++ b/packages/artplayer-plugin-vast/ARCHITECTURE.md @@ -122,4 +122,10 @@ runtime consumers and editor generation in TS5.9.3/4.3.5. `yarn build:ts artplay regenerates the root-compatible editor global. Frozen workspace editor tests continue to exercise the SDK declaration bundler; they are labelled historical. Public migration is documented in [the accepted type decision](../../refactor/vast-type-decision.md). -Actual IMA/media/device validation remains05 and full distribution06. +`yarn test:vast-native` separately loads the real remote Google IMA SDK with local +VAST XML and video assets. It runs outside the default PR suite because SDK/network +availability is an explicit environment gate. No SDK boundary is substituted. +Reports include bundle/media hashes, XML, SDK/browser versions, event order, decoded +ad frames and resumed content state. See the validation record for actual results; +adding this command does not establish device or final distribution acceptance. +Physical device validation remains05 and full distribution06. diff --git a/playwright.vast-native.config.js b/playwright.vast-native.config.js new file mode 100644 index 000000000..874558ac8 --- /dev/null +++ b/playwright.vast-native.config.js @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict' +import process from 'node:process' +import { defineConfig } from '@playwright/test' +import base from './playwright.config.js' + +assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Native VAST source validation does not accept unrelated artifact maps') +export default defineConfig(base, { + testMatch: ['**/vast.native.js', '**/vast-recovery.native.js'], + timeout: 30000, + workers: 1, + outputDir: 'refactor/.cache/vast-native/results', + reporter: [ + ['list'], + ['html', { outputFolder: 'refactor/.cache/vast-native/html', open: 'never' }], + ['json', { outputFile: 'refactor/.cache/vast-native/report.json' }], + ], +}) diff --git a/refactor/baselines/vast-native-validation.json b/refactor/baselines/vast-native-validation.json new file mode 100644 index 000000000..3893da007 --- /dev/null +++ b/refactor/baselines/vast-native-validation.json @@ -0,0 +1,2717 @@ +{ + "task": "PKG-VAST-05", + "date": "2026-09-14T15:34:14.068Z", + "sourceCommit": "e5c73fa620d7d3bae4cf7e1e5f96b321e0178f44", + "status": "doing", + "sourceChanges": false, + "vpnExceptionUsed": false, + "nativeSdk": true, + "physicalDevicesVerified": false, + "reports": [ + { + "label": "preroll-probe", + "path": "refactor/.cache/vast05-native-first-report/report.json", + "sha256": "f1d5165f4ab514e837951a428c3b4610fa7c3f633bacdb5a7b140122d8dbd814", + "log": "refactor/.cache/vast05-native-first.log", + "stats": { + "startTime": "2026-09-14T15:13:07.114Z", + "duration": 24157.284, + "expected": 2, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "real IMA npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "compatibility": "workspace-1.2" + }, + "failures": [] + } + ] + }, + { + "label": "initial-matrix", + "path": "refactor/.cache/vast05-native-matrix-report/report.json", + "sha256": "e69862596a4b59bc8b73bc3721e7f0e28081c1a4e707542b91fce6ecac82261a", + "log": "refactor/.cache/vast05-native-matrix.log", + "stats": { + "startTime": "2026-09-14T15:21:39.283Z", + "duration": 315382.842, + "expected": 23, + "skipped": 0, + "unexpected": 4, + "flaky": 0 + }, + "cases": [ + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.897374, + "time": 2.776723, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.681354 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.904602, + "time": 4.881502, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.156485 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted" + ], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\n 78 | await expect(page.locator('[id^=\"art-\"]')).toBeVisible()\n 79 | const decodedAd = await page.evaluate(() => [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, width: video.videoWidth, height: video.videoHeight, time: video.currentTime })).filter(video => video.src.includes('/assets/vast/linear-video.mp4')))\n> 80 | expect(decodedAd.some(video => video.width > 0 && video.height > 0)).toBe(true)\n | ^\n 81 | expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(true)\n 82 | await testInfo.attach('native-vast-ad.png', { contentType: 'image/png', body: await page.screenshot() })\n 83 | await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdComplete'))).toBe(true)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:80:76" + ] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [ + { + "type": "AdError", + "at": 6983.799999952316, + "contentTime": 5.957516, + "contentPaused": false, + "error": { + "code": 9000, + "message": "No adsManagerLoadedEvent within 5000ms." + } + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 13\n\n- Array []\n+ Array [\n+ Object {\n+ \"at\": 6983.799999952316,\n+ \"contentPaused\": false,\n+ \"contentTime\": 5.957516,\n+ \"error\": Object {\n+ \"code\": 9000,\n+ \"message\": \"No adsManagerLoadedEvent within 5000ms.\",\n+ \"vastCode\": undefined,\n+ },\n+ \"type\": \"AdError\",\n+ },\n+ ]\n\n 85 | await expect(page.locator('[id^=\"art-\"]')).toBeHidden()\n 86 | await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.2)\n> 87 | expect(await page.evaluate(() => window.nativeVastEvents.filter(event => event.type === 'AdError'))).toEqual([])\n | ^\n 88 | const resumed = await page.evaluate(() => ({ time: window.art.currentTime, paused: window.art.template.$video.paused, width: window.art.template.$video.videoWidth, events: window.nativeVastEvents }))\n 89 | expect(resumed.paused).toBe(false)\n 90 | expect(resumed.width).toBeGreaterThan(0)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:87:108" + ] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.897208, + "time": 2.765664, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.004736 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.907591, + "time": 2.824634, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.723093 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.91135, + "time": 2.866513, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.913665 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.896495, + "time": 4.83376, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.709939 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.897708, + "time": 3.86561, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.434095 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.86901, + "time": 1.919814, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.042307 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.908315, + "time": 4.961703, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.000021 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.867686, + "time": 3.893953, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.73809 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [ + { + "type": "AdError", + "at": 8121, + "contentTime": 5.943896, + "contentPaused": false, + "error": { + "code": 9000, + "message": "No adsManagerLoadedEvent within 5000ms." + } + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 13\n\n- Array []\n+ Array [\n+ Object {\n+ \"at\": 8121,\n+ \"contentPaused\": false,\n+ \"contentTime\": 5.943896,\n+ \"error\": Object {\n+ \"code\": 9000,\n+ \"message\": \"No adsManagerLoadedEvent within 5000ms.\",\n+ \"vastCode\": undefined,\n+ },\n+ \"type\": \"AdError\",\n+ },\n+ ]\n\n 85 | await expect(page.locator('[id^=\"art-\"]')).toBeHidden()\n 86 | await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.2)\n> 87 | expect(await page.evaluate(() => window.nativeVastEvents.filter(event => event.type === 'AdError'))).toEqual([])\n | ^\n 88 | const resumed = await page.evaluate(() => ({ time: window.art.currentTime, paused: window.art.template.$video.paused, width: window.art.template.$video.videoWidth, events: window.nativeVastEvents }))\n 89 | expect(resumed.paused).toBe(false)\n 90 | expect(resumed.width).toBeGreaterThan(0)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:87:108" + ] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.909597, + "time": 5.041666, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.527236 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.908554, + "time": 1.902568, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.124256 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.90797, + "time": 5.999999, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.779049 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.909382, + "time": 6.134017, + "paused": false, + "width": 320, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.94065 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [ + { + "type": "AdError", + "at": 9146, + "contentTime": 5.958332, + "contentPaused": false, + "error": { + "code": 9000, + "message": "No adsManagerLoadedEvent within 5000ms." + } + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 13\n\n- Array []\n+ Array [\n+ Object {\n+ \"at\": 9146,\n+ \"contentPaused\": false,\n+ \"contentTime\": 5.958332,\n+ \"error\": Object {\n+ \"code\": 9000,\n+ \"message\": \"No adsManagerLoadedEvent within 5000ms.\",\n+ \"vastCode\": undefined,\n+ },\n+ \"type\": \"AdError\",\n+ },\n+ ]\n\n 85 | await expect(page.locator('[id^=\"art-\"]')).toBeHidden()\n 86 | await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.2)\n> 87 | expect(await page.evaluate(() => window.nativeVastEvents.filter(event => event.type === 'AdError'))).toEqual([])\n | ^\n 88 | const resumed = await page.evaluate(() => ({ time: window.art.currentTime, paused: window.art.template.$video.paused, width: window.art.template.$video.videoWidth, events: window.nativeVastEvents }))\n 89 | expect(resumed.paused).toBe(false)\n 90 | expect(resumed.width).toBeGreaterThan(0)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:87:108" + ] + }, + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.0304101, + "time": 2.380182, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3523536 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9141934, + "time": 2.250795, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.1451665 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.0341836, + "time": 2.3719817, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3378745 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.015981, + "time": 2.3183036, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.4530201 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.99099, + "time": 2.3244034, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.2849579 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9739866, + "time": 5.4267348, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.4561451 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9745353, + "time": 2.3783896, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.4513118 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.0019655, + "time": 2.6032765, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3312287 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.0534144, + "time": 2.354392, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3161037 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + } + ] + }, + { + "label": "recovery", + "path": "refactor/.cache/vast05-native-recovery-report/report.json", + "sha256": "7ed66a523ab5139b6802ada8e8e1668deb420de29daa396555b7a420b0c6300d", + "log": "refactor/.cache/vast05-native-recovery.log", + "stats": { + "startTime": "2026-09-14T15:27:27.856Z", + "duration": 51781.987, + "expected": 6, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "real IMA npm-default recovers from empty VAST, recreates and destroys an active ad", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 7084.600000023842, + "time": 2.92128, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + }, + { + "title": "real IMA workspace-1.2 recovers from empty VAST, recreates and destroys an active ad", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 4870.400000035763, + "time": 3.877603, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + }, + { + "title": "real IMA npm-default recovers from empty VAST, recreates and destroys an active ad", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 9579, + "time": 5.105752, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + }, + { + "title": "real IMA workspace-1.2 recovers from empty VAST, recreates and destroys an active ad", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 7018, + "time": 3.117498, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + }, + { + "title": "real IMA npm-default recovers from empty VAST, recreates and destroys an active ad", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 2909, + "time": 1.5242293, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + }, + { + "title": "real IMA workspace-1.2 recovers from empty VAST, recreates and destroys an active ad", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "adErrors": [ + { + "type": "AdError", + "at": 2428, + "time": 1.5236252, + "paused": false, + "code": 303, + "message": "No Ads VAST response after one or more Wrappers" + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "recovery": { + "oldConnected": false, + "activeConnected": false, + "container": null, + "terminalInit": null + }, + "failures": [] + } + ] + }, + { + "label": "final-matrix", + "path": "refactor/.cache/vast05-native-final-report/report.json", + "sha256": "2bd4ad38f94e3e049b1a90ddd593c5d8c5a2d19afa98140aa4be09953807dee8", + "log": "refactor/.cache/vast05-native-matrix-final.log", + "stats": { + "startTime": "2026-09-14T15:28:56.120Z", + "duration": 303085.342, + "expected": 22, + "skipped": 0, + "unexpected": 5, + "flaky": 0 + }, + "cases": [ + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.853235, + "time": 2.784407, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.96896 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.865628, + "time": 2.841791, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.40451 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.866214, + "time": 3.820738, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.648334 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.854443, + "time": 5.877028, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.927872 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.869022, + "time": 2.818159, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.053054 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.84804, + "time": 1.763653, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.196356 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.86013, + "time": 2.816695, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.365087 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.856434, + "time": 5.810493, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.684688 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "chromium", + "browserVersion": "153.0.8010.12", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.84931, + "time": 4.891783, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.30101 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.912643, + "time": 2.984949, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.162108 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.909023, + "time": 5.012808, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.974626 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).not.toBe(expected) // Object.is equality\n\nExpected: not \"pending\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 60 | })\n 61 | }, { compatibility, historical })\n> 62 | await expect.poll(() => page.evaluate(() => window.nativeVastRegistration)).not.toBe('pending')\n | ^\n 63 | expect(await page.evaluate(() => window.nativeVastRegistration)).toBe('ready')\n 64 | await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)\n 65 | await page.locator('#play').click()\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:62:87" + ] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [ + { + "type": "AdError", + "at": 8456, + "contentTime": 5.956163, + "contentPaused": false, + "error": { + "code": 9000, + "message": "No adsManagerLoadedEvent within 5000ms." + } + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 13\n\n- Array []\n+ Array [\n+ Object {\n+ \"at\": 8456,\n+ \"contentPaused\": false,\n+ \"contentTime\": 5.956163,\n+ \"error\": Object {\n+ \"code\": 9000,\n+ \"message\": \"No adsManagerLoadedEvent within 5000ms.\",\n+ \"vastCode\": undefined,\n+ },\n+ \"type\": \"AdError\",\n+ },\n+ ]\n\n 91 | await expect(page.locator('[id^=\"art-\"]')).toBeHidden()\n 92 | await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.2)\n> 93 | expect(await page.evaluate(() => window.nativeVastEvents.filter(event => event.type === 'AdError'))).toEqual([])\n | ^\n 94 | const resumed = await page.evaluate(() => ({ time: window.art.currentTime, paused: window.art.template.$video.paused, width: window.art.template.$video.videoWidth, events: window.nativeVastEvents }))\n 95 | expect(resumed.paused).toBe(false)\n 96 | expect(resumed.width).toBeGreaterThan(0)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:93:108" + ] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.876017, + "time": 6.025975, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.2425 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "coreVersion": "5.4.0", + "registration": "pending", + "adErrors": [], + "events": [], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).not.toBe(expected) // Object.is equality\n\nExpected: not \"pending\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 60 | })\n 61 | }, { compatibility, historical })\n> 62 | await expect.poll(() => page.evaluate(() => window.nativeVastRegistration)).not.toBe('pending')\n | ^\n 63 | expect(await page.evaluate(() => window.nativeVastRegistration)).toBe('ready')\n 64 | await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)\n 65 | await page.locator('#play').click()\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:62:87" + ] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.911674, + "time": 1.961297, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.161427 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.910985, + "time": 4.98142, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 1280, + "height": 720, + "time": 0.202045 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "firefox", + "browserVersion": "155.0", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [ + { + "type": "AdError", + "at": 7170, + "contentTime": 5.965294, + "contentPaused": false, + "error": { + "code": 9000, + "message": "No adsManagerLoadedEvent within 5000ms." + } + } + ], + "events": [ + "AdError", + "MediaResumed", + "AdContentPauseRequested", + "AdStarted" + ], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 80 | await testInfo.attach('native-vast-response.xml', { contentType: 'application/xml', body: await page.evaluate(() => window.nativeVastXml) })\n 81 | await page.locator('#play').click()\n> 82 | await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdStarted'))).toBe(true)\n | ^\n 83 | await expect(page.locator('[id^=\"art-\"]')).toBeVisible()\n 84 | await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/assets/vast/linear-video.mp4') && video.videoWidth > 0 && video.videoHeight > 0 && video.currentTime > 0))).toBe(true)\n 85 | const decodedAd = await page.evaluate(() => [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, width: video.videoWidth, height: video.videoHeight, time: video.currentTime })).filter(video => video.src.includes('/assets/vast/linear-video.mp4')))\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:82:119" + ] + }, + { + "title": "real IMA published-5.1.7 / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 1.0288126, + "time": 2.4805628, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3623745 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9384167, + "time": 2.3601878, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.238708 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published-5.1.7", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published-5.1.7 / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.1.7", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9122084, + "time": 3.3623755, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.8189154 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published-5.1.7", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9974792, + "time": 2.0946669, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.119729 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA published / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9799584, + "time": 1.9602294, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.1246873 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "published", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA published / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.0", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9783126, + "time": 2.613417, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.3901661 + } + ] + }, + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "published", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / npm-default plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9186875, + "time": 1.8972086, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.1316248 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "npm-default", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [] + }, + { + "title": "real IMA candidate / workspace-1.2 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "passed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "resumed": { + "beforeAd": 0.9802917, + "time": 2.4788753, + "paused": false, + "width": 640, + "decodedAd": [ + { + "src": "http://127.0.0.1:8084/assets/vast/linear-video.mp4", + "width": 640, + "height": 360, + "time": 0.4932284 + } + ] + }, + "input": { + "sourceSha256": "d934b7735b59d6689b0481c60ea673c9ea282e6697322a669b5fef9b0ad61d34", + "sdk": "@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "workspace-1.2", + "core": "candidate", + "compatibility": "workspace-1.2" + }, + "failures": [] + }, + { + "title": "real IMA candidate / published-1.0.0 plays local VAST media and resumes content", + "browser": "webkit", + "browserVersion": "26.6", + "status": "failed", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "registration": "ready", + "adErrors": [], + "events": [ + "AdContentPauseRequested", + "AdStarted", + "AdComplete", + "MediaResumed", + "AdContentResumeRequested", + "AdAllAdsCompleted" + ], + "input": { + "sourceSha256": "bf3429ca7650fdedc03a7e3e92abc192c4eac87a97c0895e3a0f82921aa361d0", + "sdk": "immutable npm1.0.0 bundled SDK; real remote Google IMA", + "media": { + "file": "docs/assets/vast/linear-video.mp4", + "sha256": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "contentFile": "docs/assets/sample/video.mp4", + "contentSha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980" + }, + "implementation": "published-1.0.0", + "core": "candidate", + "compatibility": "npm-default" + }, + "failures": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 82 | await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdStarted'))).toBe(true)\n 83 | await expect(page.locator('[id^=\"art-\"]')).toBeVisible()\n> 84 | await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/assets/vast/linear-video.mp4') && video.videoWidth > 0 && video.videoHeight > 0 && video.currentTime > 0))).toBe(true)\n | ^\n 85 | const decodedAd = await page.evaluate(() => [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, width: video.videoWidth, height: video.videoHeight, time: video.currentTime })).filter(video => video.src.includes('/assets/vast/linear-video.mp4')))\n 86 | expect(decodedAd.some(video => video.width > 0 && video.height > 0)).toBe(true)\n 87 | expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(true)\n at D:\\github\\ArtPlayer\\test\\browser\\vast.native.js:84:241" + ] + } + ] + } + ], + "files": { + "test/browser/vast.native.js": "8d9cebabf6e9f0d45e272fb7752c1db24cb71eca2a30f4bb6dee117bd45f0a6f", + "test/browser/vast-recovery.native.js": "83267bc848acadf99daf0289161c6d3abfd1fb51d657b9ac2bcd87a91463e693", + "playwright.vast-native.config.js": "3e41ec927e5a6f0f0f08908f918e205428bdbd1f5b7d45e068d7f9b20e3de831", + "docs/assets/vast/linear-video.mp4": "ea5399b4ff701a7f69f09b6197593067bac1adfaa416fc693021a593472c3591", + "docs/assets/sample/video.mp4": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980", + "packages/artplayer-plugin-vast/src/index.ts": "4221668a9e96cc7feef0f98f6276261c174431ef24b9b8c81d0f5d84261a6cd1", + "packages/artplayer-plugin-vast/src/session.ts": "08ad97deaa386d26034711e17fba001f326c842960efb83cb858db3a2bd09e48", + "packages/artplayer-plugin-vast/src/sdk.ts": "aaff7c1e4a31ff99261b045648663caa46f66b5a25ad129e5fc929facaf1ff89", + "packages/artplayer-plugin-vast/src/view.ts": "15e5b186bdcb8f9f60379e726eedec4b31ca61df27efe1891effccb1e56db491", + "packages/artplayer-plugin-vast/src/types.ts": "b97b291d14bddf7fcc307b173f28677935f34bfa6e99ceb46a2bdef6cf335c5b" + }, + "iab": { + "browser": "Codex in-app browser", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36", + "exactBrowserVersion": "unavailable: Browser.getVersion unsupported", + "url": "http://localhost:8082/?libs=./compiled/artplayer-plugin-vast.js&example=vast", + "imaVersion": "3.789.0", + "coreVersion": "5.4.1", + "mainVideo": { + "width": 640, + "observedTime": 29.745651, + "paused": false + }, + "script": { + "url": "https://imasdk.googleapis.com/js/sdkloader/ima3.js", + "status": 200 + }, + "blockedBridge": { + "url": "http://imasdk.googleapis.com/js/core/bridge3.789.0_en.html", + "error": "net::ERR_BLOCKED_BY_CLIENT", + "type": "Document" + }, + "limitation": "CDP event buffer reported truncated=true. Bridge request and failure IDs matched; do not infer all network activity or VPN root cause. No ad playback accepted; tab paused then closed." + }, + "remaining": [ + "Resolve or precisely qualify native SDK loading/9000 late-manager failures; no timeout widening/retry-to-green.", + "Physical iOS/Android ad/content lifecycle evidence.", + "Native skip and playUrl coverage plus full package/distribution task06.", + "Remote CI and release reviews remain separately gated." + ] +} diff --git a/refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md b/refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md new file mode 100644 index 000000000..61aea4455 --- /dev/null +++ b/refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md @@ -0,0 +1,67 @@ +# PKG-VAST-05:真实 IMA 桌面验证检查点 + +任务仍为doing,本次不是完成提交。前置HEAD为e5c73fa62;已批准的VAST运行时和 +类型方案保持不变,没有修改生产源码、公开声明、依赖或分发产物。 + +## 实际交付 + +- 增加`yarn test:vast-native`,使用已有Playwright、固定Node/Yarn与8084隔离服务。 + 不增加依赖;独立config避免默认PR受控测试隐式依赖外部SDK,单worker、零重试。 +- `vast.native.js`用实际npm1.0.0完整bundle和候选两种模式,在npm核心5.1.7、 + npm5.4.0、候选5.4.1上执行广告插播。历史bundle先校验归档,候选使用正常构建配置。 + 断言主片暂停、真实广告首帧/时间推进、完成/恢复事件、主片续播及容器移除。 +- `vast-recovery.native.js`让真实IMA处理空VAST响应,核验303错误后的主片恢复, + 显式销毁/重建广告会话,第二次广告实际解码后核心销毁,检查容器与终止状态。 +- XML只控制测试输入和本地媒体/跟踪图片;没有替换SDK、广告事件或video。 + 包架构、测试维护说明、环境矩阵、任务与风险台账同步。 + +## 终止进程后的结果 + +完整摘要、原报告SHA256、测试/源码/媒体指纹和逐例结果见 +[vast-native-validation.json](../baselines/vast-native-validation.json)。Windows上实测 +Chromium153.0.8010.12、Firefox155.0、WebKit26.6,远端IMA均观测为3.789.0。 + +| 批次 | 结果 | 边界 | +| --- | --- | --- | +| Chromium候选两模式前贴片探针 | 2通过 | 真实广告解码/完成,主片从起点播放 | +| 首轮插播27组合 | 23通过、4失败 | 1项首帧断言竞态,3项SDK9000超时;完整保留 | +| 错误恢复/重建/活动广告销毁 | 6通过 | 三引擎、候选核心、两模式;真实303及第二段广告解码 | +| 修正夹具后27组合 | 22通过、5失败 | Chromium9/9、Firefox5/9、WebKit8/9;不是全绿 | + +最终5项失败:Firefox旧插件+5.1.7和5.4.0核心在7秒注册等待内未就绪;其中一项 +在失败后采集状态时才ready,不能倒算通过。Firefox候选默认+5.4.0核心收到SDK9000 +后广告仍迟到播放;旧插件+候选核心收到9000但未在等待窗口开始广告。WebKit旧插件+ +候选核心已收到AdStarted,却未在首帧等待中取得有尺寸且时间推进的广告video。 +这些失败需要后续分层取证,不能笼统归为VPN,也不能凭其他轮通过把它们关闭。 + +初次插播夹具直接new Artplayer却点击了只在createPlayer中绑定的按钮,2项失败后 +中断(exit1),报告/日志保留在`vast05-native-unwired-play-report`和 +`vast05-native-matrix-first.log`。修正为使用现有createPlayer。首帧检查改为等待 +实际尺寸和时间推进,未提高7秒断言预算;主片改用90秒本地样本,使冷加载和插播 +不会混入短片自然结束路径。未改变SDK自身5秒/10秒预算,也没有新增重试或skip。 +一次进度消息误用未完整读取的尾部计数报24/27,已当场更正;本记录使用最终JSON。 + +## 内置浏览器的真实示例 + +Chrome库存连接失败后使用已授权iab fallback,打开8082编译VAST示例并点击播放。 +UA报告Chrome152.0.0.0,Browser.getVersion不受此接口支持,不能捏造更精确版本。 +主片画面实际解码640宽、播放至29.745651秒;页面插件注册且IMA3.789.0已加载。 +Network证据中`https://imasdk.googleapis.com/js/sdkloader/ima3.js`返回200, +`http://imasdk.googleapis.com/js/core/bridge3.789.0_en.html`文档请求被 +`net::ERR_BLOCKED_BY_CLIENT`拦截,请求/失败ID匹配。因此原线上标签的广告播放 +不计通过。事件缓冲报告truncated,不能宣称捕获全部请求或据此确认VPN根因。 +没有禁用保护、修改用户网络设置或使用VAST VPN例外;测试页暂停后关闭。 + +## 剩余门槛与回退 + +专项只读lint、plan生成/检查、risk-register生成/检查通过,风险台账和浏览器验证 +runner的6项工程测试通过。严格工具链检查通过Node24.21.0/Yarn1.22.22及22个 +workspace;首次直接node调用被正确拒绝(缺Yarn调用上下文),改用固定Yarn +入口验证通过。git diff --check通过;生产源码、dist、docs编译副本及锁文件无差异。 + +SDK-07和VAST-LIFE-01保持open;05保持doing,06尚待完整分发。下一步针对实际 +超时、迟到广告和WebKit旧插件首帧问题取证,补playUrl/skip与物理iOS/Android +生命周期验证。远端CI、版本与三轮发布复盘是独立门槛。桌面WebKit不代替Apple真机。 + +本次仅新增可重跑验证与记录,可单独回退本检查点;前两个已批准兼容性提交不受影响。 +未push、未发布npm。提交后继续运行每任务提交审计;不把该检查点算为新增完成任务。 diff --git a/refactor/environment-matrix.md b/refactor/environment-matrix.md index f085a6966..dca34b57d 100644 --- a/refactor/environment-matrix.md +++ b/refactor/environment-matrix.md @@ -56,7 +56,7 @@ Node10 是 TS 模块解析模式名,不代表支持 Node.js 10。现代 es2020 | artplayer-plugin-hls-control / 1.1.0 | hls.js 清晰度/音轨自动手动切换;主/子列表与拓扑变化 | 1.5.17 在 Chromium/Firefox 本地双档位/音轨基线通过;Windows WebKit 无 MSE,14 播放用例 skipped;Safari/native/worker 仍待验,见 hls-validation.md | PKG-HLS-01/02/05/06、EX-03 | | artplayer-plugin-jassub / 1.1.0 | ASS、worker/WASM/font 加载、切源/销毁;短 ASS+明确来源字体 | 内嵌资源哈希已有;版本对应、跨源/worker 限制、实际渲染待 | PKG-JASSUB-01/02/05/06 | | artplayer-plugin-multiple-subtitles / 1.2.0 | VTT 合并/排序/解析错误、URL 回收;双语言/空/坏 VTT | parser 来源头已观察;特有行为和浏览器字幕待 | PKG-MULTI-SUB-01/02/05/06 | -| artplayer-plugin-vast / 1.2.0 | Glomex/Google IMA、广告错误/恢复、重复初始化;供应商测试广告标签 | 依赖版本已记录;实际 IMA 网络/广告流程待,PR 用受控 adapter | PKG-VAST-01/02/05/06 | +| artplayer-plugin-vast / npm1.0.0、工作区1.2.0未发布 | Glomex/Google IMA、广告错误/恢复、重复初始化;本地VAST与真实IMA3.789.0 | 三引擎最终27组合22通过5失败,错误恢复/重建/活动广告销毁6通过;iab桥接文档被拦截、主片正常。物理设备及SDK/历史失败仍待,详见vast-native-validation.json | PKG-VAST-01/02/05/06 | | artplayer-plugin-vtt-thumbnail / 1.1.0 | WebVTT 时间和 sprite xywh、图片失败/跨源;本地 VTT+sprite | 05 检查点已有五核心桌面像素/Chapter/原生和网页全屏、切源及模拟触摸;1.0.1 控件重名历史失败和真机/分发仍开放,见 vtt-thumbnail-combinations.json | PKG-VTT-THUMB-01/02/05/06 | | artplayer-proxy-canvas / 1.1.0 | video-like 属性/事件、Canvas 绘制、seek/销毁;MP4 | shim 与实际媒体顺序、跨源/移动待 | PKG-CANVAS-01/02/05/06 | | artplayer-proxy-mediabunny / 1.2.0 | Mediabunny 1.56.1 当前解析;WebCodecs/AudioContext、HLS/轨道拓扑、AV 同步 | 库依赖不等于 codec 可用;准确 codec/profile、设备能力、长播放待 | PKG-MB-01/02/07/08/09/10 | diff --git a/refactor/plan.md b/refactor/plan.md index 466562fa4..64452b02f 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 262 项,范围 22 个包及工作区/示例。 -状态:todo 47 / doing 20 / blocked 0 / done 195 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 46 / doing 21 / blocked 0 / done 195 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -298,7 +298,7 @@ | PKG-VAST-02 | artplayer-plugin-vast
建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态;发布 id/$container/eager 与工作区 lazy/config 覆盖、callback拒绝、加载中销毁、同毫秒多实例与晚到事件 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | | PKG-VAST-03 | artplayer-plugin-vast
整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done | | PKG-VAST-04 | artplayer-plugin-vast
迁移自有源码和公开类型 | PKG-VAST-03, ENG-04, ENG-06, CORE-07, PKG-VAST-07 | IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done | -| PKG-VAST-05 | artplayer-plugin-vast
验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 官方测试广告或受控 SDK 环境,错误后主视频状态恢复;核验真实5.1.7/5.4.1/候选核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-VAST-05 | artplayer-plugin-vast
验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 真实IMA广告播放、错误后主视频恢复、会话重建与销毁;核验npm5.1.7/npm5.4.0/候选5.4.1核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | doing | | PKG-VAST-06 | artplayer-plugin-vast
验证分发并同步文档 | PKG-VAST-05, ENG-07 | vast.js、SDK 资源、声明消费和独立版本记录;核验实际发布 namespace default、历史深路径、ESM和准确声明,版本按政策2.0.0由REL-09统一处理 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | | PKG-VAST-07 | artplayer-plugin-vast
恢复旧发布VAST工厂default调用入口 | PKG-VAST-01, PKG-VAST-02 | 保留当前直接工厂并增加default自身别名,验证四类分发调用及异步注册,初始化决策独立保留 | 旧产物default用例失败,新源码/实际main/legacy/ESM通过;真实核心三浏览器控制SDK注册验证、模块文档/构建/测试入口同步;不冒充namespace反射、声明和IMA验收 | M | done | @@ -602,6 +602,7 @@ - PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md) - PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md) [记录](changes/2026-09-14-PKG-VAST-03-compatibility.md) [记录](baselines/vast-compatibility-validation.json) - PKG-VAST-04: [记录](changes/2026-09-14-PKG-VAST-04-types.md) [记录](baselines/vast-types-validation.json) [记录](vast-type-decision.md) [记录](vast-validation.md) +- PKG-VAST-05: [记录](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md) [记录](baselines/vast-native-validation.json) - PKG-CAST-01: [记录](baselines/chromecast-release.json) [记录](baselines/chromecast-contract.md) [记录](baselines/chromecast-contract-validation.json) [记录](changes/2026-09-13-PKG-CAST-01-contracts.md) - PKG-CAST-02: [记录](changes/2026-09-13-PKG-CAST-02-failures.md) [记录](baselines/chromecast-failures-validation.json) - PKG-CAST-03: [记录](changes/2026-09-13-PKG-CAST-03-runtime.md) [记录](baselines/chromecast-runtime-validation.json) diff --git a/refactor/progress.md b/refactor/progress.md index 456cde1e0..8b325ab7e 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,18 @@ # 进度与证据 +## PKG-VAST-05 真实 IMA 桌面验证检查点,仍进行中 + +新增独立`test:vast-native`,真实远端IMA3.789.0与本地广告媒体,不替换SDK。 +两模式Chromium前贴片2通过;首轮27组合23通过4失败,修正夹具后的27组合22通过 +5失败;另外三引擎错误303恢复、会话重建及活动广告销毁6通过。完整失败均保留, +没有放宽断言/SDK超时或重复直到全绿。候选最终18项中17通过,历史9项中5通过。 + +iab真实示例主片解码播放正常,IMA主脚本200,但bridge文档被ERR_BLOCKED_BY_CLIENT +拦截,广告播放不计通过,也不推断VPN原因。物理设备、playUrl/skip、SDK迟到/超时 +及WebKit历史首帧仍需验证,05/SDK-07/LIFE保持开放;262项为195 done、21 doing、 +46 todo。详见[检查点](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md)和 +[逐例证据](baselines/vast-native-validation.json)。本地检查点提交不代表完成或发布。 + ## PKG-VAST-04 公开类型协调及安装消费者完成 用户单独确认保留npm1.0.0根类型、工作区TS用法迁移/runtime。根/legacy声明原文 diff --git a/refactor/risks.json b/refactor/risks.json index 11b2531e1..af8b0da85 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -775,11 +775,13 @@ "refactor/changes/2026-09-12-PKG-VAST-01-contract.md", "refactor/baselines/vast-contract-validation.json", "refactor/vast-validation.md", - "refactor/baselines/vast-behavior-validation.json" + "refactor/baselines/vast-behavior-validation.json", + "refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md", + "refactor/baselines/vast-native-validation.json" ], "compatibleResolution": "@glomex/vast-ima-player loadImaSdk loads external IMA; preserve event/content/ad state and teardown, do not equate mocks with vendor service acceptance.", "closureCriteria": "固定 SDK/外部资源版本和环境;成功/失败/切换/销毁有真实证据,设备和网络限制逐项记录。", - "workspaceState": "VAST 1.0.0 and SDK 1.21.0/1.21.2 archives verified; Google IMA remote execution remains unverified. User allows recording/skipping only persistent VAST script loading failures caused by VPN rules, not Ads or other VAST code/type failures. This exception has not been used." + "workspaceState": "Real IMA3.789.0 executes with immutable npm1.0.0/candidate bundles: final27 desktop combinations22 passed5 failed; error303 recovery/recreation/active-ad destruction6 passed. Initial27 were23 passed4 failed and are preserved. SDK9000/late loading and historical WebKit ad-frame failures remain open. IAB SDK200 but bridge document ERR_BLOCKED_BY_CLIENT; physical devices/playUrl/skip not accepted. No VPN exception or timeout widening/retry-to-green." }, { "id": "SDK-08", @@ -3331,11 +3333,13 @@ "refactor/baselines/vast-lifecycle-validation.json", "refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md", "refactor/changes/2026-09-14-PKG-VAST-03-compatibility.md", - "refactor/baselines/vast-compatibility-validation.json" + "refactor/baselines/vast-compatibility-validation.json", + "refactor/changes/2026-09-14-PKG-VAST-05-native-checkpoint.md", + "refactor/baselines/vast-native-validation.json" ], "compatibleResolution": "Reproduce pending SDK/callback destruction, errors, duplicate IDs and stale ad events before adding compatible cleanup and state ownership.", "closureCriteria": "Tests prove cleanup during load/callback rejection/core destruction and distinguish explicit plugin recreation from terminal core destruction; vendor media restoration is separately verified.", - "workspaceState": "Task03 runtime ownership and both approved modes pass82 Node and162 real-browser wrapper checks (99 candidate,63 historical), with controlled SDK only. Eager callback errors/cancellation, rollback and explicit recreation are covered. Risk remains open for actual vendor media restoration in task05; no VPN exception was used." + "workspaceState": "Task03 controlled82 Node/162 browser checks remain valid; task05 adds6 real IMA303 recovery/recreation/active-ad core destruction passes across three engines/two modes. Native full combination failures, devices and remaining ad lifecycle paths keep this risk open; no claim of complete vendor/device acceptance." }, { "id": "VAST-DIST-01", diff --git a/refactor/tasks.json b/refactor/tasks.json index 77b946b88..4af82baf5 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -3134,11 +3134,14 @@ "PKG-VAST-04", "CORE-22" ], - "status": "todo", + "status": "doing", "risk": "H", - "deliverable": "官方测试广告或受控 SDK 环境,错误后主视频状态恢复;核验真实5.1.7/5.4.1/候选核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收", + "deliverable": "真实IMA广告播放、错误后主视频恢复、会话重建与销毁;核验npm5.1.7/npm5.4.0/候选5.4.1核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收", "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", - "evidence": [] + "evidence": [ + "changes/2026-09-14-PKG-VAST-05-native-checkpoint.md", + "baselines/vast-native-validation.json" + ] }, { "id": "PKG-VAST-06", diff --git a/refactor/vast-validation.md b/refactor/vast-validation.md index ef6fff5d3..8bb1d348d 100644 --- a/refactor/vast-validation.md +++ b/refactor/vast-validation.md @@ -94,3 +94,26 @@ VAST-LIFE-01由源码观察提升为受控运行复现,问题如下: 只有实际VAST外部脚本持续因VPN无法加载时,可按用户授权记录并跳过该网络验证; 它不豁免类型、生命周期或其他包。本次未用该例外。05/06和SDK-07继续开放。 + +## 真实 Google IMA 专项入口 + +固定工具链运行 `yarn test:vast-native`;可使用 `--project=chromium` 缩小复现。 +`playwright.vast-native.config.js` 复用8084隔离服务、单worker、零重试,输出 +`refactor/.cache/vast-native/`。此目录在进程终止后归档,再开始下一轮。`.native.js` +命名避免在默认PR受控测试中隐式请求远端SDK;后续CI/发布环境需明确执行此命令。 + +测试保留实际Glomex打包代码,由其正常加载Google IMA;手写本地VAST响应仅指定 +测试广告媒体和本地跟踪图片,不替换AdsLoader、AdsManager、事件或媒体实现。 +Google的[AdsRequest接口](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/interface/google.ima.AdsRequestInterface) +提供adsResponse作为广告输入。每项附件记录真实执行的输入、SDK版本、浏览器版本、 +广告解码截图、主片播放位置及事件;远端SDK版本会变,结果仅代表对应运行环境。 + +三核心固定为npm5.1.7、npm5.4.0、候选5.4.1;实际npm1.0.0插件完整bundle通过 +归档校验后直接加载,候选两种模式使用同一生产构建配置的内存bundle。历史插件的 +SDK清理由夹具在证据后显式补做,不能据DOM被核心移除就认为旧插件拥有SDK清理。 +源代码组合通过不等于最终tarball通过,也不等于iOS/Android物理设备通过。 + +`vast-recovery.native.js`补充候选核心两模式的真实303错误恢复、显式会话重建及 +广告播放中核心销毁。当前结果见[05检查点](changes/2026-09-14-PKG-VAST-05-native-checkpoint.md): +最终组合22/27,恢复6/6;SDK超时/迟到、旧插件首帧及真机未关闭。独立入口失败应 +保留为失败,不能用默认受控套件通过抵消,也不能为稳定CI添加宽泛skip。 diff --git a/test/browser/README.md b/test/browser/README.md index de3b7659a..cfd7411f3 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -1,5 +1,11 @@ # Browser regression entry +`yarn test:vast-native` is the explicit external Google IMA suite; it is separate +from default `*.spec.js` PR checks. It uses local VAST/media inputs and real SDK +loading, playback, content restoration and destruction. See +[VAST validation](../../refactor/vast-validation.md) for reports and outstanding +network/device failures; the current matrix is not fully passing. + `canvas-dpip.spec.js` tests actual native windows with the Canvas video and subtitle track, continued playback, paused cue seeking and close/native-close/destroy. Chromium/Firefox native outcomes and WebKit API-unavailable outcomes must be diff --git a/test/browser/vast-recovery.native.js b/test/browser/vast-recovery.native.js new file mode 100644 index 000000000..05eb626fa --- /dev/null +++ b/test/browser/vast-recovery.native.js @@ -0,0 +1,77 @@ +import { hash } from '../../refactor/scripts/releases.mjs' +import { compilePackage } from '../helpers/load.js' +import { expect, test } from './fixtures.js' + +// eslint-disable-next-line antfu/no-top-level-await -- Bundle the real SDK once before test discovery. +const code = await compilePackage('artplayer-plugin-vast', 'umd') + +for (const compatibility of [undefined, 'workspace-1.2']) { + test(`real IMA ${compatibility || 'npm-default'} recovers from empty VAST, recreates and destroys an active ad`, async ({ page }, testInfo) => { + await page.goto('/test/player.html?core=candidate') + await page.addScriptTag({ content: code }) + await page.evaluate(async (compatibility) => { + window.createPlayer('/assets/sample/video.mp4') + window.recoveryEvents = [] + window.observeRecoveryPlayer = (player) => { + for (const type of ['AdError', 'AdStarted', 'AdContentPauseRequested', 'AdContentResumeRequested', 'MediaResumed']) { + player.addEventListener(type, event => window.recoveryEvents.push({ type, at: performance.now(), time: window.art.currentTime, paused: window.art.template.$video.paused, code: event.detail?.error?.errorCode, message: event.detail?.error?.message })) + } + } + await window.art.plugins.add(window.artplayerPluginVast((context) => { + window.recoveryContext = context + window.observeRecoveryPlayer(context.init()) + }, compatibility ? { compatibility } : undefined)) + }, compatibility) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.5) + await page.evaluate(() => { + document.querySelector('#play').onclick = () => window.recoveryContext.playRes('') + }) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.recoveryEvents.filter(event => event.type === 'AdError').length)).toBe(1) + const failure = await page.evaluate(() => ({ events: window.recoveryEvents, time: window.art.currentTime })) + expect(failure.events.find(event => event.type === 'AdError').code).toBe(303) + await expect(page.locator('[id^="art-"]')).toBeHidden() + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(failure.time + 0.2) + expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(false) + await page.evaluate(() => { + const context = window.recoveryContext + window.firstRecoveryContainer = context.container + window.art.plugins.artplayerPluginVast.destroy() + window.observeRecoveryPlayer(context.init()) + const origin = location.origin + window.recoveryXml = ` +ArtPlayer test fixtureRecovery validation + +00:00:04 + +` + document.querySelector('#play').onclick = () => context.playRes(window.recoveryXml) + }) + expect(await page.evaluate(() => window.firstRecoveryContainer.isConnected)).toBe(false) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.recoveryEvents.filter(event => event.type === 'AdStarted').length)).toBe(1) + await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/assets/vast/linear-video.mp4') && video.videoWidth > 0 && video.currentTime > 0))).toBe(true) + await expect(page.locator('[id^="art-"]')).toBeVisible() + await testInfo.attach('native-vast-recovery-ad.png', { contentType: 'image/png', body: await page.screenshot() }) + const state = await page.evaluate(() => { + const container = window.recoveryContext.container + window.art.destroy() + return { oldConnected: window.firstRecoveryContainer.isConnected, activeConnected: container.isConnected, container: window.recoveryContext.container, terminalInit: window.recoveryContext.init(), events: window.recoveryEvents, imaVersion: window.google.ima.VERSION } + }) + expect(state.oldConnected).toBe(false) + expect(state.activeConnected).toBe(false) + expect(state.container).toBeNull() + expect(state.terminalInit).toBeNull() + expect(state.events.filter(event => event.type === 'AdError')).toHaveLength(1) + await expect(page.locator('[id^="art-"]')).toHaveCount(0) + await testInfo.attach('native-vast-recovery', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(code), compatibility: compatibility || 'npm-default', failure, ...state }) }) + await testInfo.attach('native-vast-recovery.xml', { contentType: 'application/xml', body: await page.evaluate(() => window.recoveryXml) }) + }) +} + +test.afterEach(async ({ page }, testInfo) => { + const state = await page.evaluate(() => ({ events: window.recoveryEvents, imaVersion: window.google?.ima?.VERSION, time: window.art?.currentTime, paused: window.art?.template.$video.paused })) + await testInfo.attach('native-vast-recovery-final', { contentType: 'application/json', body: JSON.stringify(state) }) + await page.evaluate(() => window.art?.destroy()) +}) diff --git a/test/browser/vast.native.js b/test/browser/vast.native.js new file mode 100644 index 000000000..7536d888e --- /dev/null +++ b/test/browser/vast.native.js @@ -0,0 +1,105 @@ +import fs from 'node:fs' +import { hash, readMember } from '../../refactor/scripts/releases.mjs' +import { verifyVastContract } from '../../refactor/scripts/vast-contract.mjs' +import { compilePackage } from '../helpers/load.js' +import { expect, test } from './fixtures.js' + +// eslint-disable-next-line antfu/no-top-level-await -- Compile the real bundled SDK before test discovery. +const code = await compilePackage('artplayer-plugin-vast', 'umd') +// eslint-disable-next-line antfu/no-top-level-await -- Verify immutable published bytes before native test discovery. +const contract = await verifyVastContract() +const historicalCode = readMember(contract.archives.get('artplayer-plugin-vast@1.0.0'), 'package/dist/artplayer-plugin-vast.js').toString() +const mediaFile = 'docs/assets/vast/linear-video.mp4' + +test.afterEach(async ({ page }, testInfo) => { + const state = await page.evaluate(() => ({ + registration: window.nativeVastRegistration, + error: window.nativeVastError, + imaVersion: window.google?.ima?.VERSION, + events: window.nativeVastEvents, + videos: [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, time: video.currentTime, duration: video.duration, width: video.videoWidth, height: video.videoHeight, paused: video.paused, ended: video.ended })), + containerConnected: window.nativeVastContext?.container?.isConnected, + coreVersion: window.Artplayer?.version, + })) + await testInfo.attach('native-vast-state', { contentType: 'application/json', body: JSON.stringify(state) }) + await page.evaluate(() => window.art?.destroy()) + await page.evaluate(() => { + if (window.nativeVastHistorical) + window.nativeVastContext?.imaPlayer?.destroy() + }) +}) + +for (const core of ['published-5.1.7', 'published', 'candidate']) { + for (const implementation of ['npm-default', 'workspace-1.2', 'published-1.0.0']) { + const compatibility = implementation === 'workspace-1.2' ? implementation : undefined + const historical = implementation === 'published-1.0.0' + const bundle = historical ? historicalCode : code + test(`real IMA ${core} / ${implementation} plays local VAST media and resumes content`, async ({ page }, testInfo) => { + await page.goto(`/test/player.html?core=${core}`) + await page.addScriptTag({ content: bundle }) + await testInfo.attach('native-vast-inputs', { contentType: 'application/json', body: JSON.stringify({ sourceSha256: hash(bundle), sdk: historical ? 'immutable npm1.0.0 bundled SDK; real remote Google IMA' : '@glomex/vast-ima-player@1.21.2 bundled; real remote Google IMA', media: { file: mediaFile, sha256: hash(fs.readFileSync(mediaFile)), contentFile: 'docs/assets/sample/video.mp4', contentSha256: hash(fs.readFileSync('docs/assets/sample/video.mp4')) }, implementation, core, compatibility: compatibility || 'npm-default' }) }) + await page.evaluate(({ compatibility, historical }) => { + window.nativeVastHistorical = historical + window.nativeVastEvents = [] + window.nativeVastRegistration = 'pending' + window.createPlayer('/assets/sample/video.mp4') + const factory = window.artplayerPluginVast.default || window.artplayerPluginVast + window.art.plugins.add(factory((context) => { + window.nativeVastContext = context + const player = context.init?.() || context.imaPlayer + for (const type of ['AdStarted', 'AdComplete', 'AdAllAdsCompleted', 'AdContentPauseRequested', 'AdContentResumeRequested', 'AdError', 'MediaResumed']) { + player.addEventListener(type, (event) => { + window.nativeVastEvents.push({ type, at: performance.now(), contentTime: window.art.currentTime, contentPaused: window.art.template.$video.paused, error: event.detail?.error && { code: event.detail.error.errorCode, vastCode: event.detail.error.vastErrorCode, message: event.detail.error.message } }) + }) + } + }, compatibility ? { compatibility } : undefined)).then(() => { + window.nativeVastRegistration = 'ready' + }).catch((error) => { + window.nativeVastRegistration = 'failed' + window.nativeVastError = String(error) + }) + }, { compatibility, historical }) + await expect.poll(() => page.evaluate(() => window.nativeVastRegistration)).not.toBe('pending') + expect(await page.evaluate(() => window.nativeVastRegistration)).toBe('ready') + await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.5) + await page.evaluate(() => { + const origin = location.origin + const xml = ` + +ArtPlayer test fixtureLocal SDK validation + +00:00:04 + +` + window.nativeVastXml = xml + document.querySelector('#play').onclick = () => window.nativeVastContext.playRes(xml) + }) + const beforeAd = await page.evaluate(() => window.art.currentTime) + await testInfo.attach('native-vast-response.xml', { contentType: 'application/xml', body: await page.evaluate(() => window.nativeVastXml) }) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdStarted'))).toBe(true) + await expect(page.locator('[id^="art-"]')).toBeVisible() + await expect.poll(() => page.evaluate(() => [...document.querySelectorAll('video')].some(video => video.currentSrc.includes('/assets/vast/linear-video.mp4') && video.videoWidth > 0 && video.videoHeight > 0 && video.currentTime > 0))).toBe(true) + const decodedAd = await page.evaluate(() => [...document.querySelectorAll('video')].map(video => ({ src: video.currentSrc, width: video.videoWidth, height: video.videoHeight, time: video.currentTime })).filter(video => video.src.includes('/assets/vast/linear-video.mp4'))) + expect(decodedAd.some(video => video.width > 0 && video.height > 0)).toBe(true) + expect(await page.evaluate(() => window.art.template.$video.paused)).toBe(true) + await testInfo.attach('native-vast-ad.png', { contentType: 'image/png', body: await page.screenshot() }) + await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdComplete'))).toBe(true) + await expect.poll(() => page.evaluate(() => window.nativeVastEvents.some(event => event.type === 'AdContentResumeRequested'))).toBe(true) + await expect(page.locator('[id^="art-"]')).toBeHidden() + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(beforeAd + 0.2) + expect(await page.evaluate(() => window.nativeVastEvents.filter(event => event.type === 'AdError'))).toEqual([]) + const resumed = await page.evaluate(() => ({ time: window.art.currentTime, paused: window.art.template.$video.paused, width: window.art.template.$video.videoWidth, events: window.nativeVastEvents })) + expect(resumed.paused).toBe(false) + expect(resumed.width).toBeGreaterThan(0) + expect(resumed.events.filter(event => event.type === 'AdStarted')).toHaveLength(1) + expect(resumed.events.filter(event => event.type === 'AdComplete')).toHaveLength(1) + expect(resumed.events.findIndex(event => event.type === 'AdStarted')).toBeLessThan(resumed.events.findIndex(event => event.type === 'AdComplete')) + await testInfo.attach('native-vast-resumed', { contentType: 'application/json', body: JSON.stringify({ beforeAd, decodedAd, ...resumed }) }) + await page.evaluate(() => window.art.destroy()) + await expect(page.locator('[id^="art-"]')).toHaveCount(0) + }) + } +}