@npo/player 1.27.7 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -7
- package/lib/js/markers/updateLiveMarkers.d.ts +7 -2
- package/lib/js/markers/updateLiveMarkers.js +11 -4
- package/lib/js/markers/updateLiveMarkers.test.js +13 -3
- package/lib/js/playeractions/handlers/handleoffsets.test.js +1 -1
- package/lib/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
- package/lib/js/playeractions/handlers/mediasessionactions.js +7 -7
- package/lib/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
- package/lib/js/playeractions/handlers/processplayerconfig.js +1 -1
- package/lib/js/playeractions/handlers/processplayerconfig.test.js +1 -1
- package/lib/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
- package/lib/js/playeractions/handlers/processsourceconfig.js +35 -18
- package/lib/js/playeractions/handlers/removereplayclass.d.ts +1 -1
- package/lib/js/playeractions/handlers/removereplayclass.js +1 -1
- package/lib/js/playeractions/handlers/removereplayclass.test.js +1 -1
- package/lib/js/settings/localization.d.ts +1 -0
- package/lib/js/utilities/utilities.jwt.d.ts +2 -0
- package/lib/js/utilities/utilities.jwt.js +22 -0
- package/lib/js/utilities/utilities.stream.js +11 -2
- package/lib/js/utilities/utilities.url.js +2 -2
- package/lib/js/utilities/utilities.version.js +1 -1
- package/lib/js/utilities/utilities.version.test.js +1 -1
- package/lib/lang/nl.json +2 -1
- package/lib/npoplayer.d.ts +6 -5
- package/lib/npoplayer.js +81 -28
- package/lib/package.json +7 -9
- package/lib/services/a11y/setup.test.js +2 -4
- package/lib/services/advertHandlers/handlePreRolls.js +3 -4
- package/lib/services/advertHandlers/handlePrerolls.test.js +2 -3
- package/lib/services/chapterHandlers/chapterHandler.d.ts +35 -0
- package/lib/services/chapterHandlers/chapterHandler.js +230 -0
- package/lib/services/errors/errorBackground.test.js +1 -1
- package/lib/services/errors/errorHandler.d.ts +4 -2
- package/lib/services/errors/errorHandler.js +27 -14
- package/lib/services/errors/errorHandler.test.js +148 -0
- package/lib/services/errors/errorRetryHandler.d.ts +2 -0
- package/lib/services/errors/errorRetryHandler.js +14 -0
- package/lib/services/errors/errorRetryHandler.test.d.ts +1 -0
- package/lib/services/errors/errorRetryHandler.test.js +62 -0
- package/lib/services/errors/errorText.js +8 -5
- package/lib/services/errors/errorText.test.js +3 -3
- package/lib/services/infoPanel/infoPanel.d.ts +3 -0
- package/lib/services/infoPanel/infoPanel.js +35 -0
- package/lib/services/infoPanel/infoPanel.test.d.ts +1 -0
- package/lib/services/infoPanel/infoPanel.test.js +70 -0
- package/lib/services/keyboardHandlers/resolvekeypress.js +11 -1
- package/lib/services/keyboardHandlers/resolvekeypress.test.js +6 -2
- package/lib/services/nicamHandlers/nicamhandler.d.ts +1 -0
- package/lib/services/nicamHandlers/nicamhandler.js +2 -1
- package/lib/services/nicamHandlers/nicamhandler.test.js +2 -2
- package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
- package/lib/services/npoPlayerAPI/npoPlayerAPI.js +25 -12
- package/lib/services/npoPlayerAPI/playerModules.d.ts +1 -0
- package/lib/services/npoPlayerAPI/playerModules.js +46 -0
- package/lib/services/preferences/handlePreferences.js +9 -4
- package/lib/services/preferences/handlePreferences.test.js +53 -17
- package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
- package/lib/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
- package/lib/services/segmentHandlers/isSegmentInBounds.js +5 -0
- package/lib/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
- package/lib/services/segmentHandlers/isSegmentInBounds.test.js +27 -0
- package/lib/services/services.d.ts +5 -2
- package/lib/services/services.js +15 -2
- package/lib/services/streamFetchHandler/fetchStream.js +5 -4
- package/lib/services/streamFetchHandler/fetchstream.test.js +25 -3
- package/lib/services/streamoptionsHandlers/streamOptionsHandler.js +11 -9
- package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +14 -2
- package/lib/services/trackingHandlers/eventBinding.js +48 -33
- package/lib/services/trackingHandlers/eventBinding.test.js +57 -1
- package/lib/services/trackingHandlers/playerTrackerStart.js +1 -1
- package/lib/services/uiHandlers/uiVisiblityHandler.js +6 -0
- package/lib/services/verticalVideoHandlers/handleVerticalVideoSettings.test.js +0 -9
- package/lib/src/js/markers/updateLiveMarkers.d.ts +7 -2
- package/lib/src/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
- package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
- package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
- package/lib/src/js/playeractions/handlers/removereplayclass.d.ts +1 -1
- package/lib/src/js/settings/localization.d.ts +1 -0
- package/lib/src/js/utilities/utilities.jwt.d.ts +2 -0
- package/lib/src/npoplayer.d.ts +6 -5
- package/lib/src/services/chapterHandlers/chapterHandler.d.ts +35 -0
- package/lib/src/services/errors/errorHandler.d.ts +4 -2
- package/lib/src/services/errors/errorRetryHandler.d.ts +2 -0
- package/lib/src/services/errors/errorRetryHandler.test.d.ts +1 -0
- package/lib/src/services/infoPanel/infoPanel.d.ts +3 -0
- package/lib/src/services/infoPanel/infoPanel.test.d.ts +1 -0
- package/lib/src/services/nicamHandlers/nicamhandler.d.ts +1 -0
- package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
- package/lib/src/services/npoPlayerAPI/playerModules.d.ts +1 -0
- package/lib/src/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
- package/lib/src/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
- package/lib/src/services/services.d.ts +5 -2
- package/lib/src/types/events.d.ts +1 -1
- package/lib/src/types/interfaces.d.ts +39 -43
- package/lib/src/ui/components/adbutton.d.ts +3 -6
- package/lib/src/ui/components/adlabel.d.ts +3 -6
- package/lib/src/ui/components/audio/controlbar.d.ts +2 -2
- package/lib/src/ui/components/buttons.d.ts +18 -11
- package/lib/src/ui/components/ctabar.d.ts +4 -10
- package/lib/src/ui/components/infopanel/infopanel.d.ts +3 -0
- package/lib/src/ui/components/infopanel/togglebutton.d.ts +3 -0
- package/lib/src/ui/components/playnext.d.ts +3 -9
- package/lib/src/ui/components/seekbar.d.ts +2 -3
- package/lib/src/ui/components/settingspanel.d.ts +2 -3
- package/lib/src/ui/components/titlebar.d.ts +2 -2
- package/lib/src/ui/handlers/domhandlers.d.ts +2 -2
- package/lib/src/ui/handlers/listboxhandlers.d.ts +18 -4
- package/lib/src/ui/handlers/playnextscreen.d.ts +6 -2
- package/lib/src/ui/uicontainer.d.ts +1 -2
- package/lib/tests/jest.setup-files-after-env.d.ts +0 -0
- package/lib/tests/jest.setup-files-after-env.js +6 -0
- package/lib/tests/jest.setup-tests.d.ts +1 -0
- package/lib/tests/jest.setup-tests.js +2 -0
- package/lib/tests/mocks/mockNpoplayer.js +27 -44
- package/lib/tests/mocks/mockPlayerAPI.d.ts +1 -1
- package/lib/tests/mocks/mockPlayerAPI.js +15 -1
- package/lib/tests/mocks/mockPlayerUi.d.ts +64 -0
- package/lib/tests/mocks/mockPlayerUi.js +251 -0
- package/lib/tests/mocks/playerContextMock.d.ts +3 -66
- package/lib/tests/mocks/playerContextMock.js +34 -7
- package/lib/types/events.d.ts +1 -1
- package/lib/types/events.js +1 -1
- package/lib/types/interfaces.d.ts +39 -43
- package/lib/types/interfaces.js +0 -27
- package/lib/ui/components/adbutton.d.ts +3 -6
- package/lib/ui/components/adbutton.js +2 -1
- package/lib/ui/components/adlabel.d.ts +3 -6
- package/lib/ui/components/adlabel.js +2 -1
- package/lib/ui/components/audio/controlbar.d.ts +2 -2
- package/lib/ui/components/audio/controlbar.js +6 -6
- package/lib/ui/components/buttons.d.ts +18 -11
- package/lib/ui/components/buttons.js +44 -26
- package/lib/ui/components/controlbar.js +13 -9
- package/lib/ui/components/ctabar.d.ts +4 -10
- package/lib/ui/components/ctabar.js +8 -7
- package/lib/ui/components/infopanel/infopanel.d.ts +3 -0
- package/lib/ui/components/infopanel/infopanel.js +40 -0
- package/lib/ui/components/infopanel/togglebutton.d.ts +3 -0
- package/lib/ui/components/infopanel/togglebutton.js +18 -0
- package/lib/ui/components/playnext.d.ts +3 -9
- package/lib/ui/components/playnext.js +3 -3
- package/lib/ui/components/seekbar.d.ts +2 -3
- package/lib/ui/components/seekbar.js +7 -3
- package/lib/ui/components/settingspanel.d.ts +2 -3
- package/lib/ui/components/settingspanel.js +79 -53
- package/lib/ui/components/titlebar.d.ts +2 -2
- package/lib/ui/components/titlebar.js +2 -1
- package/lib/ui/components/topbar.js +8 -5
- package/lib/ui/components/verticalvideo/controlbar.js +5 -2
- package/lib/ui/components/verticalvideo/settingspanel.js +9 -5
- package/lib/ui/handlers/accessibilityhandler.js +11 -22
- package/lib/ui/handlers/accessibilityhandler.test.js +25 -34
- package/lib/ui/handlers/domhandlers.d.ts +2 -2
- package/lib/ui/handlers/listboxhandlers.d.ts +18 -4
- package/lib/ui/handlers/listboxhandlers.js +5 -3
- package/lib/ui/handlers/playnextscreen.d.ts +6 -2
- package/lib/ui/handlers/playnextscreen.js +4 -4
- package/lib/ui/handlers/playnextscreen.test.js +15 -3
- package/lib/ui/uicontainer.d.ts +1 -2
- package/lib/ui/uicontainer.js +24 -8
- package/lib/ui/uicontainer.test.js +6 -5
- package/package.json +7 -9
- package/src/style/components/_advert.scss +0 -4
- package/src/style/components/_buffering.scss +18 -22
- package/src/style/components/_controlbars.scss +0 -4
- package/src/style/components/_icons.scss +18 -4
- package/src/style/components/_infopanel.scss +99 -0
- package/src/style/components/_nicam.scss +6 -2
- package/src/style/components/_seekbarthumbnail.scss +5 -0
- package/src/style/components/_settingspanel.scss +1 -1
- package/src/style/components/_subtitles.scss +0 -1
- package/src/style/components/_textbuttons.scss +30 -1
- package/src/style/components/_volumeslider.scss +0 -1
- package/src/style/components/audio/_bottombar.scss +6 -0
- package/src/style/components/audio/_metadata.scss +25 -9
- package/src/style/components/audio/_topbar.scss +6 -1
- package/src/style/npoplayer.css +166 -83
- package/src/style/npoplayer.scss +10 -2
- package/src/style/variants/_player-audio-only.scss +32 -0
- package/src/style/variants/_player-base.scss +5 -1
- package/src/style/variants/_player-large.scss +3 -3
- package/src/style/variants/_player-medium.scss +5 -1
- package/src/style/variants/_player-small.scss +6 -1
- package/src/style/vars/_colors.scss +1 -1
- package/src/style/vars/_icons.scss +5 -4
- package/src/style/vars/_z-index.scss +1 -1
- package/lib/npoplayer-bridge.test.js +0 -24
- package/lib/src/ui/components/nativemobile/buttons.d.ts +0 -30
- package/lib/src/ui/components/nativemobile/controlbar.d.ts +0 -3
- package/lib/src/ui/components/nativemobile/ctabar.d.ts +0 -11
- package/lib/src/ui/components/nativemobile/titlebar.d.ts +0 -2
- package/lib/src/ui/components/nativemobile/topbar.d.ts +0 -3
- package/lib/src/ui/nativemobileuicontainer.d.ts +0 -5
- package/lib/src/ui/nativemobileuifactory.d.ts +0 -3
- package/lib/src/ui/nativemobileuifactory.test.d.ts +0 -1
- package/lib/ui/components/nativemobile/buttons.d.ts +0 -30
- package/lib/ui/components/nativemobile/buttons.js +0 -233
- package/lib/ui/components/nativemobile/controlbar.d.ts +0 -3
- package/lib/ui/components/nativemobile/controlbar.js +0 -43
- package/lib/ui/components/nativemobile/ctabar.d.ts +0 -11
- package/lib/ui/components/nativemobile/ctabar.js +0 -10
- package/lib/ui/components/nativemobile/titlebar.d.ts +0 -2
- package/lib/ui/components/nativemobile/titlebar.js +0 -7
- package/lib/ui/components/nativemobile/topbar.d.ts +0 -3
- package/lib/ui/components/nativemobile/topbar.js +0 -23
- package/lib/ui/nativemobileuicontainer.d.ts +0 -5
- package/lib/ui/nativemobileuicontainer.js +0 -42
- package/lib/ui/nativemobileuifactory.d.ts +0 -3
- package/lib/ui/nativemobileuifactory.js +0 -112
- package/lib/ui/nativemobileuifactory.test.d.ts +0 -1
- package/lib/ui/nativemobileuifactory.test.js +0 -64
- package/src/style/variants/_player-native-mobile.scss +0 -13
- /package/lib/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
- /package/lib/src/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
|
@@ -1,46 +1,59 @@
|
|
|
1
1
|
import { customSpecificErrorMessageOverlayConfig, npoBusinessErrors } from './errorText';
|
|
2
|
-
|
|
2
|
+
import { isJwtFresh } from '../../js/utilities/utilities.jwt';
|
|
3
|
+
export async function handlePlayerError({ playerContext, status, context }) {
|
|
3
4
|
const { player, npoPlayer } = playerContext;
|
|
5
|
+
const { jwt, streamOptions: { retryCallback } } = npoPlayer;
|
|
4
6
|
const uiComponents = npoPlayer.uiComponents;
|
|
5
7
|
const errorContainerClass = 'npo-player-error';
|
|
6
|
-
|
|
8
|
+
let shouldRetry = false;
|
|
9
|
+
if (isJwtFresh(jwt) || retryCallback !== undefined) {
|
|
10
|
+
shouldRetry = status >= 1000;
|
|
11
|
+
}
|
|
7
12
|
const message = generateErrorMessage(status, shouldRetry);
|
|
8
|
-
npoPlayer.logEmitter.emit('logError', status);
|
|
13
|
+
npoPlayer.logEmitter.emit('logError', status, context);
|
|
9
14
|
await player.unload();
|
|
10
|
-
uiComponents.controlBar?.hide();
|
|
11
15
|
const errorMessageOverlay = uiComponents.errorMessageOverlay;
|
|
12
16
|
if (!errorMessageOverlay)
|
|
13
17
|
return;
|
|
14
18
|
player.addClassToNpoPlayerElement(errorContainerClass);
|
|
19
|
+
const containerEl = player.getNpoPlayerElement();
|
|
20
|
+
if (containerEl instanceof HTMLElement) {
|
|
21
|
+
containerEl.classList.add(errorContainerClass);
|
|
22
|
+
}
|
|
15
23
|
setErrorBackground(playerContext);
|
|
16
24
|
errorMessageOverlay.display(message);
|
|
17
25
|
if (shouldRetry) {
|
|
18
26
|
setupRetryHandler(playerContext, errorContainerClass);
|
|
19
27
|
}
|
|
20
28
|
}
|
|
21
|
-
function generateErrorMessage(status, shouldRetry) {
|
|
22
|
-
const baseMessage = npoBusinessErrors[status]
|
|
29
|
+
export function generateErrorMessage(status, shouldRetry) {
|
|
30
|
+
const baseMessage = npoBusinessErrors[status] || customSpecificErrorMessageOverlayConfig[status] || 'De video kan niet worden geladen';
|
|
23
31
|
const retryMessage = shouldRetry
|
|
24
32
|
? '<br>Klik om het opnieuw te proberen.<br><br><button class="retry-button">Opnieuw proberen</button>'
|
|
25
33
|
: '';
|
|
26
34
|
return `<span class="errorcode">Foutcode ${status}</span>\n${baseMessage}${retryMessage}`;
|
|
27
35
|
}
|
|
28
|
-
function setupRetryHandler(playerContext, errorContainerClass) {
|
|
36
|
+
export function setupRetryHandler(playerContext, errorContainerClass) {
|
|
29
37
|
const playerContainer = playerContext.player.getNpoPlayerElement();
|
|
30
38
|
playerContainer.addEventListener('click', (event) => {
|
|
31
39
|
const target = event.target;
|
|
32
40
|
if (target.classList.contains('retry-button') && playerContainer.classList.contains(errorContainerClass)) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
;
|
|
42
|
+
(async () => {
|
|
43
|
+
target.style.visibility = 'hidden';
|
|
44
|
+
await playerContext.player.handleErrorRetry(playerContext);
|
|
45
|
+
playerContext.player.removeClassFromNpoPlayerElement(errorContainerClass);
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
target.style.visibility = 'visible';
|
|
48
|
+
}, 200);
|
|
49
|
+
})().catch((error) => {
|
|
50
|
+
console.error('Retry handler failed:', error);
|
|
51
|
+
});
|
|
39
52
|
}
|
|
40
53
|
});
|
|
41
54
|
}
|
|
42
55
|
export function setErrorBackground(playerContext) {
|
|
43
56
|
const playerContainer = playerContext.player.getNpoPlayerElement();
|
|
44
57
|
const posterImage = playerContext.npoPlayer.sourceConfig.poster;
|
|
45
|
-
playerContainer?.style.setProperty('--npo-player-errormessage-background-image', posterImage
|
|
58
|
+
playerContainer?.style.setProperty('--npo-player-errormessage-background-image', posterImage ? `url(${posterImage})` : 'none');
|
|
46
59
|
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { handlePlayerError, generateErrorMessage, setupRetryHandler, setErrorBackground } from './errorHandler';
|
|
4
|
+
import * as jwtUtils from '../../js/utilities/utilities.jwt';
|
|
5
|
+
import { npoBusinessErrors, customSpecificErrorMessageOverlayConfig } from './errorText';
|
|
6
|
+
const retryButtonClass = 'retry-button';
|
|
7
|
+
describe('generateErrorMessage', () => {
|
|
8
|
+
it('falls back to default message and no retry button when shouldRetry is false', () => {
|
|
9
|
+
const status = 999;
|
|
10
|
+
const html = generateErrorMessage(status, false);
|
|
11
|
+
expect(html).toContain(`Foutcode ${status}`);
|
|
12
|
+
expect(html).toContain('De video kan niet worden geladen');
|
|
13
|
+
expect(html).not.toContain(retryButtonClass);
|
|
14
|
+
});
|
|
15
|
+
it('includes retry button when shouldRetry is true', () => {
|
|
16
|
+
const status = 1234;
|
|
17
|
+
const html = generateErrorMessage(status, true);
|
|
18
|
+
expect(html).toContain(`Foutcode ${status}`);
|
|
19
|
+
expect(html).toMatch(/<button class="retry-button">Opnieuw proberen<\/button>/);
|
|
20
|
+
});
|
|
21
|
+
it('uses business mapping if present', () => {
|
|
22
|
+
const codes = Object.keys(npoBusinessErrors).map(Number);
|
|
23
|
+
if (codes.length > 0) {
|
|
24
|
+
const code = codes[0];
|
|
25
|
+
const mapped = npoBusinessErrors[code];
|
|
26
|
+
expect(generateErrorMessage(code, false)).toContain(mapped);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
it('uses custom overlay mapping if present', () => {
|
|
30
|
+
const codes = Object.keys(customSpecificErrorMessageOverlayConfig).map(Number);
|
|
31
|
+
if (codes.length > 0) {
|
|
32
|
+
const code = codes[0];
|
|
33
|
+
const mapped = customSpecificErrorMessageOverlayConfig[code];
|
|
34
|
+
expect(generateErrorMessage(code, false)).toContain(mapped);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('setErrorBackground', () => {
|
|
39
|
+
let playerContext;
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
const container = document.createElement('div');
|
|
42
|
+
playerContext = {
|
|
43
|
+
player: { getNpoPlayerElement: () => container },
|
|
44
|
+
npoPlayer: { sourceConfig: { poster: 'http://example.com/poster.jpg' } }
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
it('sets CSS var to the poster URL', () => {
|
|
48
|
+
const el = playerContext.player.getNpoPlayerElement();
|
|
49
|
+
setErrorBackground(playerContext);
|
|
50
|
+
expect(el.style.getPropertyValue('--npo-player-errormessage-background-image')).toBe('url(http://example.com/poster.jpg)');
|
|
51
|
+
});
|
|
52
|
+
it('falls back to "none" when poster is empty', () => {
|
|
53
|
+
playerContext.npoPlayer.sourceConfig.poster = '';
|
|
54
|
+
const el = playerContext.player.getNpoPlayerElement();
|
|
55
|
+
setErrorBackground(playerContext);
|
|
56
|
+
expect(el.style.getPropertyValue('--npo-player-errormessage-background-image')).toBe('none');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('setupRetryHandler', () => {
|
|
60
|
+
const ERROR_CLASS = 'npo-player-error';
|
|
61
|
+
let playerContext;
|
|
62
|
+
let container;
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
jest.useFakeTimers();
|
|
65
|
+
container = document.createElement('div');
|
|
66
|
+
container.classList.add(ERROR_CLASS);
|
|
67
|
+
const btn = document.createElement('button');
|
|
68
|
+
btn.classList.add('retry-button');
|
|
69
|
+
container.appendChild(btn);
|
|
70
|
+
playerContext = {
|
|
71
|
+
player: {
|
|
72
|
+
getNpoPlayerElement: () => container,
|
|
73
|
+
handleErrorRetry: jest.fn().mockImplementation(() => Promise.resolve()),
|
|
74
|
+
removeClassFromNpoPlayerElement: jest.fn()
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
setupRetryHandler(playerContext, ERROR_CLASS);
|
|
78
|
+
});
|
|
79
|
+
afterEach(() => {
|
|
80
|
+
jest.runOnlyPendingTimers();
|
|
81
|
+
jest.useRealTimers();
|
|
82
|
+
});
|
|
83
|
+
it('invokes handleErrorRetry and restores button visibility', async () => {
|
|
84
|
+
const btn = container.querySelector('.retry-button');
|
|
85
|
+
btn.click();
|
|
86
|
+
expect(btn).toHaveStyle({ visibility: 'hidden' });
|
|
87
|
+
await Promise.resolve();
|
|
88
|
+
expect(playerContext.player.handleErrorRetry).toHaveBeenCalled();
|
|
89
|
+
expect(playerContext.player.removeClassFromNpoPlayerElement).toHaveBeenCalledWith(ERROR_CLASS);
|
|
90
|
+
jest.advanceTimersByTime(200);
|
|
91
|
+
expect(btn).toHaveStyle({ visibility: 'visible' });
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('handlePlayerError', () => {
|
|
95
|
+
let playerContext;
|
|
96
|
+
let emitLog;
|
|
97
|
+
let unload;
|
|
98
|
+
let display;
|
|
99
|
+
let addClass;
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
jest.spyOn(jwtUtils, 'isJwtFresh').mockReturnValue(true);
|
|
102
|
+
emitLog = jest.fn();
|
|
103
|
+
unload = jest.fn().mockImplementation(() => Promise.resolve());
|
|
104
|
+
display = jest.fn();
|
|
105
|
+
addClass = jest.fn();
|
|
106
|
+
const playerEl = document.createElement('div');
|
|
107
|
+
const ui = {
|
|
108
|
+
errorMessageOverlay: { display }
|
|
109
|
+
};
|
|
110
|
+
const playerMock = {
|
|
111
|
+
unload,
|
|
112
|
+
addClassToNpoPlayerElement: addClass,
|
|
113
|
+
getNpoPlayerElement: () => playerEl,
|
|
114
|
+
handleErrorRetry: jest.fn().mockImplementation(() => Promise.resolve())
|
|
115
|
+
};
|
|
116
|
+
playerContext = {
|
|
117
|
+
player: playerMock,
|
|
118
|
+
npoPlayer: {
|
|
119
|
+
jwt: 'token',
|
|
120
|
+
streamOptions: {},
|
|
121
|
+
uiComponents: ui,
|
|
122
|
+
logEmitter: { emit: emitLog },
|
|
123
|
+
sourceConfig: { poster: 'p.jpg' }
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
afterEach(() => {
|
|
128
|
+
jest.restoreAllMocks();
|
|
129
|
+
});
|
|
130
|
+
it('logs, hides controls, shows error without retry for status<1000', async () => {
|
|
131
|
+
await handlePlayerError({ playerContext, status: 404 });
|
|
132
|
+
expect(emitLog).toHaveBeenCalledWith('logError', 404, undefined);
|
|
133
|
+
expect(addClass).toHaveBeenCalledWith('npo-player-error');
|
|
134
|
+
expect(display).toHaveBeenCalledWith(expect.stringContaining('Foutcode 404'));
|
|
135
|
+
expect(display).not.toHaveBeenCalledWith(expect.stringContaining(retryButtonClass));
|
|
136
|
+
});
|
|
137
|
+
it('logs and shows retry button when status>=1000, and attaches retry handler', async () => {
|
|
138
|
+
await handlePlayerError({ playerContext, status: 1500 });
|
|
139
|
+
expect(emitLog).toHaveBeenCalledWith('logError', 1500, undefined);
|
|
140
|
+
expect(display).toHaveBeenCalledWith(expect.stringContaining(retryButtonClass));
|
|
141
|
+
const el = playerContext.player.getNpoPlayerElement();
|
|
142
|
+
el.innerHTML = display.mock.calls[0][0];
|
|
143
|
+
const btn = el.querySelector('.retry-button');
|
|
144
|
+
btn.click();
|
|
145
|
+
await Promise.resolve();
|
|
146
|
+
expect(playerContext.player.handleErrorRetry).toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { isJwtFresh } from '../../js/utilities/utilities.jwt';
|
|
2
|
+
export async function handleErrorRetry(playerContext) {
|
|
3
|
+
const { sourceConfig, jwt, streamOptions: { retryCallback } } = playerContext.npoPlayer;
|
|
4
|
+
if (!isJwtFresh(jwt) && retryCallback !== undefined) {
|
|
5
|
+
return retryCallback?.();
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
await playerContext.player.playerAPI.load(sourceConfig);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.error('Retry failed', error);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { handleErrorRetry } from './errorRetryHandler';
|
|
2
|
+
import { isJwtFresh } from '../../js/utilities/utilities.jwt';
|
|
3
|
+
jest.mock('../../js/utilities/utilities.jwt', () => ({
|
|
4
|
+
isJwtFresh: jest.fn()
|
|
5
|
+
}));
|
|
6
|
+
describe('handleErrorRetry', () => {
|
|
7
|
+
let retryCallback;
|
|
8
|
+
let loadMock;
|
|
9
|
+
let consoleErrorSpy;
|
|
10
|
+
let dummyConfig;
|
|
11
|
+
let playerContext;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
retryCallback = jest.fn();
|
|
14
|
+
loadMock = jest.fn().mockResolvedValue(undefined);
|
|
15
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {
|
|
16
|
+
});
|
|
17
|
+
dummyConfig = {};
|
|
18
|
+
playerContext = {
|
|
19
|
+
npoPlayer: {
|
|
20
|
+
sourceConfig: dummyConfig,
|
|
21
|
+
jwt: 'some.token',
|
|
22
|
+
streamOptions: { retryCallback }
|
|
23
|
+
},
|
|
24
|
+
player: {
|
|
25
|
+
playerAPI: { load: loadMock }
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
jest.resetAllMocks();
|
|
31
|
+
});
|
|
32
|
+
it('calls retryCallback and does not call load when JWT is stale and retryCallback is provided', async () => {
|
|
33
|
+
;
|
|
34
|
+
isJwtFresh.mockReturnValue(false);
|
|
35
|
+
await handleErrorRetry(playerContext);
|
|
36
|
+
expect(retryCallback).toHaveBeenCalledTimes(1);
|
|
37
|
+
expect(loadMock).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
it('falls back to load when JWT is stale but retryCallback is undefined', async () => {
|
|
40
|
+
;
|
|
41
|
+
isJwtFresh.mockReturnValue(false);
|
|
42
|
+
playerContext.npoPlayer.streamOptions.retryCallback = undefined;
|
|
43
|
+
await handleErrorRetry(playerContext);
|
|
44
|
+
expect(loadMock).toHaveBeenCalledWith(dummyConfig);
|
|
45
|
+
});
|
|
46
|
+
it('calls load when JWT is fresh', async () => {
|
|
47
|
+
;
|
|
48
|
+
isJwtFresh.mockReturnValue(true);
|
|
49
|
+
await handleErrorRetry(playerContext);
|
|
50
|
+
expect(retryCallback).not.toHaveBeenCalled();
|
|
51
|
+
expect(loadMock).toHaveBeenCalledWith(dummyConfig);
|
|
52
|
+
});
|
|
53
|
+
it('catches errors from load and logs them', async () => {
|
|
54
|
+
;
|
|
55
|
+
isJwtFresh.mockReturnValue(true);
|
|
56
|
+
const testError = new Error('boom');
|
|
57
|
+
loadMock.mockRejectedValue(testError);
|
|
58
|
+
await handleErrorRetry(playerContext);
|
|
59
|
+
expect(loadMock).toHaveBeenCalledWith(dummyConfig);
|
|
60
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Retry failed', testError);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const customSpecificErrorMessageOverlayConfig = {
|
|
2
2
|
1000: 'Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
3
3
|
1001: 'Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
4
|
-
1101: 'Er is een
|
|
5
|
-
1102: 'Er is een
|
|
4
|
+
1101: 'Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
5
|
+
1102: 'Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
6
6
|
1103: 'Er is een licentie-fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
7
7
|
1104: 'Er is een licentie-fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
8
8
|
1105: 'Er is een licentie-fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
@@ -29,11 +29,11 @@ export const customSpecificErrorMessageOverlayConfig = {
|
|
|
29
29
|
1402: 'Er is een serverfout opgetreden. Controleer je internetverbinding.',
|
|
30
30
|
1403: 'Er is een serverfout opgetreden. Controleer je internetverbinding.',
|
|
31
31
|
1404: 'Er is een serverfout opgetreden. Controleer je internetverbinding.',
|
|
32
|
-
2001: 'Er is een
|
|
33
|
-
2002: 'Er is een
|
|
32
|
+
2001: 'Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
33
|
+
2002: 'Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
34
34
|
2003: 'Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
35
35
|
2005: 'Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
36
|
-
2006: '
|
|
36
|
+
2006: 'Dit item is niet beschikbaar op dit apparaat. Controleer of jouw apparaat geschikt is voor het afspelen van beveiligde content.',
|
|
37
37
|
2007: 'Dit item is niet beschikbaar op dit apparaat. Controleer of jouw apparaat geschikt is voor het afspelen van beveiligde content.',
|
|
38
38
|
2008: 'Dit item is niet beschikbaar op dit apparaat. Controleer of jouw apparaat geschikt is voor het afspelen van beveiligde content.',
|
|
39
39
|
2009: 'Er is een licentie-fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.',
|
|
@@ -50,10 +50,13 @@ export const customSpecificErrorMessageOverlayConfig = {
|
|
|
50
50
|
4000: 'Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.'
|
|
51
51
|
};
|
|
52
52
|
export const npoBusinessErrors = {
|
|
53
|
+
401: 'Dit item is momenteel niet beschikbaar.',
|
|
53
54
|
402: 'Dit programma is alleen te zien op NPO Start met een plus-abonnement.',
|
|
54
55
|
403: 'Dit item is momenteel niet beschikbaar.',
|
|
55
56
|
404: 'Dit item is momenteel niet beschikbaar.',
|
|
56
57
|
410: 'Dit item is momenteel niet beschikbaar.',
|
|
58
|
+
412: 'Dit item is momenteel niet beschikbaar.',
|
|
59
|
+
422: 'Dit item kan niet worden afgespeeld vanwege een configuratiefout.',
|
|
57
60
|
450: 'Dit item heeft een leeftijdsrestrictie en is alleen beschikbaar tussen 20:00 uur en 06:00 uur of te streamen op NPO Start met een plus-abonnement.',
|
|
58
61
|
451: 'Dit item is niet beschikbaar op jouw locatie.'
|
|
59
62
|
};
|
|
@@ -7,10 +7,10 @@ describe('Test custom error messages', () => {
|
|
|
7
7
|
expect(customSpecificErrorMessageOverlayConfig[1001]).toBe('Er is een onbekende fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.');
|
|
8
8
|
});
|
|
9
9
|
it('should return a 1101 error message', () => {
|
|
10
|
-
expect(customSpecificErrorMessageOverlayConfig[1101]).toBe('Er is een
|
|
10
|
+
expect(customSpecificErrorMessageOverlayConfig[1101]).toBe('Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.');
|
|
11
11
|
});
|
|
12
12
|
it('should return a 1102 error message', () => {
|
|
13
|
-
expect(customSpecificErrorMessageOverlayConfig[1102]).toBe('Er is een
|
|
13
|
+
expect(customSpecificErrorMessageOverlayConfig[1102]).toBe('Er is een configuratiefout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.');
|
|
14
14
|
});
|
|
15
15
|
it('should return a 1103 error message', () => {
|
|
16
16
|
expect(customSpecificErrorMessageOverlayConfig[1103]).toBe('Er is een licentie-fout opgetreden. Als het probleem zich blijft voordoen, neem dan contact op met onze klantenservice.');
|
|
@@ -43,7 +43,7 @@ describe('Test custom error messages', () => {
|
|
|
43
43
|
expect(customSpecificErrorMessageOverlayConfig[1403]).toBe('Er is een serverfout opgetreden. Controleer je internetverbinding.');
|
|
44
44
|
});
|
|
45
45
|
it('should return a 2006 error message', () => {
|
|
46
|
-
expect(customSpecificErrorMessageOverlayConfig[2006]).toBe('
|
|
46
|
+
expect(customSpecificErrorMessageOverlayConfig[2006]).toBe('Dit item is niet beschikbaar op dit apparaat. Controleer of jouw apparaat geschikt is voor het afspelen van beveiligde content.');
|
|
47
47
|
});
|
|
48
48
|
it('should return a 2007 error message', () => {
|
|
49
49
|
expect(customSpecificErrorMessageOverlayConfig[2007]).toBe('Dit item is niet beschikbaar op dit apparaat. Controleer of jouw apparaat geschikt is voor het afspelen van beveiligde content.');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function addDataInInfoPanel(playerContext) {
|
|
2
|
+
const { npoPlayer } = playerContext;
|
|
3
|
+
const infoPanel = npoPlayer.uiComponents.infoPanel;
|
|
4
|
+
const infoToggleButtons = npoPlayer.uiComponents.infoPanelToggleButtons ?? [];
|
|
5
|
+
const htmlContent = npoPlayer.streamOptions.infoPanelHTML || '';
|
|
6
|
+
if (!infoPanel)
|
|
7
|
+
return;
|
|
8
|
+
infoPanel.hide();
|
|
9
|
+
infoPanel.setHtmlContent(htmlContent);
|
|
10
|
+
if (htmlContent) {
|
|
11
|
+
for (const button of infoToggleButtons) {
|
|
12
|
+
button.show();
|
|
13
|
+
button.off();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
for (const button of infoToggleButtons) {
|
|
18
|
+
button.hide();
|
|
19
|
+
button.off();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function clearInfoPanel(playerContext) {
|
|
24
|
+
const { npoPlayer } = playerContext;
|
|
25
|
+
const infoPanel = npoPlayer.uiComponents.infoPanel;
|
|
26
|
+
const infoToggleButtons = npoPlayer.uiComponents.infoPanelToggleButtons ?? [];
|
|
27
|
+
if (!infoPanel)
|
|
28
|
+
return;
|
|
29
|
+
infoPanel.hide();
|
|
30
|
+
infoPanel.setHtmlContent('');
|
|
31
|
+
for (const button of infoToggleButtons) {
|
|
32
|
+
button.hide();
|
|
33
|
+
button.off();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mockNpoPlayer } from '../../../tests/mocks/mockNpoplayer';
|
|
2
|
+
import { addDataInInfoPanel, clearInfoPanel } from './infoPanel';
|
|
3
|
+
describe('InfoPanel helpers', () => {
|
|
4
|
+
let infoPanel;
|
|
5
|
+
let toggleButtons;
|
|
6
|
+
let mockPlayerContext;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
infoPanel = {
|
|
9
|
+
hide: jest.fn(),
|
|
10
|
+
setHtmlContent: jest.fn()
|
|
11
|
+
};
|
|
12
|
+
toggleButtons = [
|
|
13
|
+
{ show: jest.fn(), hide: jest.fn(), off: jest.fn() },
|
|
14
|
+
{ show: jest.fn(), hide: jest.fn(), off: jest.fn() }
|
|
15
|
+
];
|
|
16
|
+
mockPlayerContext = { player: {}, npoPlayer: mockNpoPlayer };
|
|
17
|
+
mockPlayerContext.npoPlayer.uiComponents.infoPanel = infoPanel;
|
|
18
|
+
mockPlayerContext.npoPlayer.uiComponents.infoPanelToggleButtons = toggleButtons;
|
|
19
|
+
});
|
|
20
|
+
describe('addDataInInfoPanel', () => {
|
|
21
|
+
it('should hide the info panel and set empty content when no HTML is provided', () => {
|
|
22
|
+
mockPlayerContext.npoPlayer.streamOptions.infoPanelHTML = '';
|
|
23
|
+
addDataInInfoPanel(mockPlayerContext);
|
|
24
|
+
expect(infoPanel.hide).toHaveBeenCalled();
|
|
25
|
+
expect(infoPanel.setHtmlContent).toHaveBeenCalledWith('');
|
|
26
|
+
for (const button of toggleButtons) {
|
|
27
|
+
expect(button.hide).toHaveBeenCalled();
|
|
28
|
+
expect(button.off).toHaveBeenCalled();
|
|
29
|
+
expect(button.show).not.toHaveBeenCalled();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
it('should set HTML content and show buttons when HTML is provided', () => {
|
|
33
|
+
mockPlayerContext.npoPlayer.streamOptions.infoPanelHTML = '<p>Info</p>';
|
|
34
|
+
addDataInInfoPanel(mockPlayerContext);
|
|
35
|
+
expect(infoPanel.hide).toHaveBeenCalled();
|
|
36
|
+
expect(infoPanel.setHtmlContent).toHaveBeenCalledWith('<p>Info</p>');
|
|
37
|
+
for (const button of toggleButtons) {
|
|
38
|
+
expect(button.show).toHaveBeenCalled();
|
|
39
|
+
expect(button.off).toHaveBeenCalled();
|
|
40
|
+
expect(button.hide).not.toHaveBeenCalled();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
it('should return early if infoPanel is not available', () => {
|
|
44
|
+
mockPlayerContext.npoPlayer.uiComponents.infoPanel = undefined;
|
|
45
|
+
addDataInInfoPanel(mockPlayerContext);
|
|
46
|
+
for (const button of toggleButtons) {
|
|
47
|
+
expect(button.show).not.toHaveBeenCalled();
|
|
48
|
+
expect(button.hide).not.toHaveBeenCalled();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('clearInfoPanel', () => {
|
|
53
|
+
it('should hide panel, clear content and hide all buttons', () => {
|
|
54
|
+
clearInfoPanel(mockPlayerContext);
|
|
55
|
+
expect(infoPanel.hide).toHaveBeenCalled();
|
|
56
|
+
expect(infoPanel.setHtmlContent).toHaveBeenCalledWith('');
|
|
57
|
+
for (const button of toggleButtons) {
|
|
58
|
+
expect(button.hide).toHaveBeenCalled();
|
|
59
|
+
expect(button.off).toHaveBeenCalled();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it('should return early if infoPanel is not available', () => {
|
|
63
|
+
mockPlayerContext.npoPlayer.uiComponents.infoPanel = undefined;
|
|
64
|
+
clearInfoPanel(mockPlayerContext);
|
|
65
|
+
for (const button of toggleButtons) {
|
|
66
|
+
expect(button.hide).not.toHaveBeenCalled();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -37,7 +37,7 @@ export function resolveKeyPress(playerContext, e) {
|
|
|
37
37
|
ArrowLeft: () => npoPlayer.goBackwards(10),
|
|
38
38
|
ArrowRight: () => npoPlayer.goForward(10),
|
|
39
39
|
Escape: () => {
|
|
40
|
-
const { settingsPanels } = npoPlayer.uiComponents;
|
|
40
|
+
const { settingsPanels, infoPanel, infoPanelToggleButtons } = npoPlayer.uiComponents;
|
|
41
41
|
if (settingsPanels && settingsPanels.length > 0) {
|
|
42
42
|
for (const panel of settingsPanels) {
|
|
43
43
|
if (panel.isShown()) {
|
|
@@ -45,6 +45,16 @@ export function resolveKeyPress(playerContext, e) {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
if (infoPanel && infoPanel.isShown()) {
|
|
49
|
+
infoPanel.hide();
|
|
50
|
+
}
|
|
51
|
+
if (infoPanelToggleButtons && infoPanelToggleButtons.length > 0) {
|
|
52
|
+
for (const button of infoPanelToggleButtons) {
|
|
53
|
+
if (button.isOn()) {
|
|
54
|
+
button.off();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
48
58
|
}
|
|
49
59
|
};
|
|
50
60
|
const action = actions[e.code];
|
|
@@ -79,10 +79,14 @@ describe('resolveKeyPress', () => {
|
|
|
79
79
|
resolveKeyPress(mockPlayerContext, { ...e, code: 'ArrowRight' });
|
|
80
80
|
expect(mockNpoplayer.goForward).toHaveBeenCalledWith(10);
|
|
81
81
|
});
|
|
82
|
-
it('should hide the settings panel when "Escape" is pressed', () => {
|
|
82
|
+
it('should hide the settings panel and info panel when "Escape" is pressed', () => {
|
|
83
|
+
resolveKeyPress(mockPlayerContext, { ...e, code: 'Escape' });
|
|
83
84
|
if (mockNpoplayer.uiComponents.settingsPanels) {
|
|
84
|
-
resolveKeyPress(mockPlayerContext, { ...e, code: 'Escape' });
|
|
85
85
|
expect(mockNpoplayer.uiComponents.settingsPanels[0].hide).toHaveBeenCalled();
|
|
86
86
|
}
|
|
87
|
+
expect(mockNpoplayer.uiComponents.infoPanel?.hide).toHaveBeenCalled();
|
|
88
|
+
if (mockNpoplayer.uiComponents.infoPanelToggleButtons) {
|
|
89
|
+
expect(mockNpoplayer.uiComponents.infoPanelToggleButtons[0].off).toHaveBeenCalled();
|
|
90
|
+
}
|
|
87
91
|
});
|
|
88
92
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PlayerContext } from '../../types/interfaces';
|
|
2
|
+
export declare const SHOW_NICAM_AFTER_UI_HIDE_DURATION = 5000;
|
|
2
3
|
export declare function processNicam(playerContext: PlayerContext, nicamElement: HTMLElement | undefined): void;
|
|
3
4
|
export declare function addNicamIcon(character: string, nicamElement: Element): void;
|
|
4
5
|
export declare function showNicamAfterUiDelay(playerContext: PlayerContext): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const SHOW_NICAM_AFTER_UI_HIDE_DURATION = 5000;
|
|
1
2
|
export function processNicam(playerContext, nicamElement) {
|
|
2
3
|
const streamOptions = playerContext.npoPlayer.streamOptions;
|
|
3
4
|
const metadata = playerContext?.npoPlayer?.streamObject?.metadata ?? {};
|
|
@@ -55,7 +56,7 @@ export function showNicamAfterUiDelay(playerContext) {
|
|
|
55
56
|
playerContainer.classList.add(showNicamClassName);
|
|
56
57
|
setTimeout(() => {
|
|
57
58
|
playerContainer.classList.remove(showNicamClassName);
|
|
58
|
-
},
|
|
59
|
+
}, SHOW_NICAM_AFTER_UI_HIDE_DURATION);
|
|
59
60
|
});
|
|
60
61
|
uiManager?.activeUi.onControlsShow.subscribe(() => {
|
|
61
62
|
playerContainer.classList.remove(showNicamClassName);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { processNicam, showNicamAfterUiDelay } from './nicamhandler';
|
|
1
|
+
import { processNicam, SHOW_NICAM_AFTER_UI_HIDE_DURATION, showNicamAfterUiDelay } from './nicamhandler';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
import { createMockNpoPlayer, createPlayerContextMock } from '../../../tests/mocks/playerContextMock';
|
|
4
4
|
describe('NICAM Processing', () => {
|
|
@@ -105,7 +105,7 @@ describe('NICAM Visibility Management', () => {
|
|
|
105
105
|
showNicamAfterUiDelay(mockPlayerContext);
|
|
106
106
|
mockUiManager.activeUi.onControlsHide.subscribe.mock.calls[0][0]();
|
|
107
107
|
expect(mockContainer).toHaveClass(showNicamClass);
|
|
108
|
-
jest.advanceTimersByTime(
|
|
108
|
+
jest.advanceTimersByTime(SHOW_NICAM_AFTER_UI_HIDE_DURATION);
|
|
109
109
|
expect(mockContainer).not.toHaveClass(showNicamClass);
|
|
110
110
|
jest.useRealTimers();
|
|
111
111
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PlayerAPI, PlayerConfig, SourceConfig, TimeMode, VideoQuality, ViewMode } from 'bitmovin-player/modules/bitmovinplayer-core';
|
|
2
|
+
import { AdBreak, AdConfig } from 'bitmovin-player/modules/bitmovinplayer-advertising-core';
|
|
3
|
+
import { SubtitleTrack } from 'bitmovin-player/modules/bitmovinplayer-subtitles';
|
|
2
4
|
import { UIManager } from 'bitmovin-player-ui';
|
|
3
5
|
import { NpoPlayerUIVariants, PlayerContext, Technology } from 'types/interfaces';
|
|
4
6
|
import { NpoPlayerEventCallback, NpoPlayerEvent } from '../../types/events';
|
|
@@ -40,8 +42,12 @@ export declare class NpoPlayerAPI {
|
|
|
40
42
|
getDuration(): number;
|
|
41
43
|
getTimeShift(): number;
|
|
42
44
|
scheduleAds(adConfig: AdConfig): Promise<AdBreak[]>;
|
|
43
|
-
handleErrorRetry(playerContext: PlayerContext): void
|
|
45
|
+
handleErrorRetry(playerContext: PlayerContext): Promise<void>;
|
|
44
46
|
getActiveAdBreak(): AdBreak | null;
|
|
45
47
|
getConfig(mergedConfig?: boolean): PlayerConfig;
|
|
46
48
|
createUIManager(playerContext: PlayerContext, variant: NpoPlayerUIVariants): void | UIManager;
|
|
49
|
+
getAvailableVideoQualities(): VideoQuality[];
|
|
50
|
+
listSubtitles(): SubtitleTrack[];
|
|
51
|
+
setPlaybackSpeed(speed: number): void;
|
|
52
|
+
setVideoQuality(VideoQualityId: string): void;
|
|
47
53
|
}
|