From 22eea1ad74b0093c788e524d1dd317853fc80f93 Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 30 Jul 2026 09:34:04 +0200 Subject: [PATCH] fix(playback): preserve Video.js HTTP error context --- .../vjs-player/vjs-player.component.spec.ts | 35 ++++++++++++++++++- .../src/lib/vjs-player/vjs-player.types.ts | 3 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/libs/ui/playback/src/lib/vjs-player/vjs-player.component.spec.ts b/libs/ui/playback/src/lib/vjs-player/vjs-player.component.spec.ts index c05fc65b2..b6fdac918 100644 --- a/libs/ui/playback/src/lib/vjs-player/vjs-player.component.spec.ts +++ b/libs/ui/playback/src/lib/vjs-player/vjs-player.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import type { NativePlaybackErrorInput } from '../playback-diagnostics/playback-diagnostics.model'; import type { PlaybackDiagnostic } from '../playback-diagnostics/playback-diagnostics.util'; import type { VjsPlayerComponent as VjsPlayerComponentInstance } from './vjs-player.component'; import type { VideoJsPlayer } from './vjs-player.types'; @@ -200,6 +201,38 @@ describe('VjsPlayerComponent', () => { ); }); + it('preserves Video.js HTTP error context in a playback diagnostic', () => { + const issues: Array = []; + component.playbackIssue.subscribe((issue) => issues.push(issue)); + render({ + sources: [ + { + src: 'https://example.test/missing/playlist.m3u8', + type: 'application/x-mpegURL', + }, + ], + }); + harness.currentError = { + code: 4, + message: 'The media could not be loaded', + status: 404, + metadata: { errorType: 'networkrequestfailed' }, + }; + + harness.emit('error'); + + expect(issues.at(-1)).toEqual( + expect.objectContaining({ + code: 'network-error', + source: 'native', + sourceUrl: 'https://example.test/missing/playlist.m3u8', + httpStatus: 404, + nativeErrorType: 'networkrequestfailed', + externalFallbackRecommended: false, + }) + ); + }); + it('rebinds native ended handling after playerreset', () => { const events: string[] = []; component.playbackEnded.subscribe(() => events.push('ended')); @@ -278,7 +311,7 @@ function createPlayerHarness() { let volumeValue = 0.5; const harness = { currentVideo: document.createElement('video'), - currentError: null as { code?: number; message?: string } | null, + currentError: null as NativePlaybackErrorInput | null, paused: true, pauseCompletesImmediately: true, ready: () => undefined, diff --git a/libs/ui/playback/src/lib/vjs-player/vjs-player.types.ts b/libs/ui/playback/src/lib/vjs-player/vjs-player.types.ts index 5c4b64149..a6a2d25c3 100644 --- a/libs/ui/playback/src/lib/vjs-player/vjs-player.types.ts +++ b/libs/ui/playback/src/lib/vjs-player/vjs-player.types.ts @@ -1,4 +1,5 @@ import type videoJs from 'video.js'; +import type { NativePlaybackErrorInput } from '../playback-diagnostics/playback-diagnostics.model'; export type VideoPlayerSource = { src: string; @@ -83,7 +84,7 @@ export type VideoJsPlayer = Omit< textTracks: () => VideoJsTextTrackList | null; tech: (options?: unknown) => VideoJsTech | null; getChild: (name: string) => VideoJsControlChild | null; - error: () => { code?: number; message?: string } | null; + error: () => NativePlaybackErrorInput | null; }; export function getVideoJsTechVideo(