diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js index a06404e52f2..78c26cbda6a 100644 --- a/modules/jwplayerRtdProvider.js +++ b/modules/jwplayerRtdProvider.js @@ -12,7 +12,7 @@ import {submodule} from '../src/hook.js'; import {config} from '../src/config.js'; import {ajaxBuilder} from '../src/ajax.js'; -import {deepAccess, logError} from '../src/utils.js'; +import { deepAccess, logError, logWarn } from '../src/utils.js' import {find} from '../src/polyfill.js'; import {getGlobal} from '../src/prebidGlobal.js'; @@ -429,17 +429,37 @@ export function addTargetingToBid(bid, targeting) { bid.rtd = Object.assign({}, rtd, jwRtd); } -function getPlayer(playerDivId) { +export function getPlayer(playerDivId) { const jwplayer = window.jwplayer; if (!jwplayer) { logError(SUBMODULE_NAME + '.js was not found on page'); return; } - const player = jwplayer(playerDivId); - if (!player || !player.getPlaylist) { - logError('player ID did not match any players'); + let player = jwplayer(playerDivId); + if (player && player.getPlaylist) { + return player; + } + + const playerOnPageCount = document.getElementsByClassName('jwplayer').length; + if (playerOnPageCount === 0) { + logError('No JWPlayer instances have been detected on the page'); return; } - return player; + + let errorMessage = `player Div ID ${playerDivId} did not match any players.`; + + // If there are multiple instances on the page, we cannot guess which one should be targeted. + if (playerOnPageCount > 1) { + logError(errorMessage); + return; + } + + player = jwplayer(); + if (player && player.getPlaylist) { + logWarn(`${errorMessage} Targeting player Div ID ${player.id} instead`); + return player; + } + + logError(errorMessage); } diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js index 36794ceeae3..58cfc751a4f 100644 --- a/test/spec/modules/jwplayerRtdProvider_spec.js +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -12,6 +12,7 @@ import { getVatFromCache, getVatFromPlayer, setOverrides, + getPlayer, jwplayerSubmodule } from 'modules/jwplayerRtdProvider.js'; import {server} from 'test/mocks/xhr.js'; @@ -1603,6 +1604,66 @@ describe('jwplayerRtdProvider', function() { }); }); + describe('Player detection', function () { + const playerInstanceMock = { + getPlaylist: () => [], + getPlaylistItem: () => ({}) + }; + + beforeEach(function () { + window.jwplayer = sinon.stub(); + }); + + afterEach(function () { + delete window.jwplayer; + }); + + it('should fail if jwplayer global does not exist', function () { + delete window.jwplayer; + expect(getPlayer('divId')).to.be.undefined; + }); + + it('should return the player instance for the specified div id', function () { + window.jwplayer.returns(playerInstanceMock); + const player = getPlayer('divId'); + expect(player).to.deep.equal(playerInstanceMock); + }); + + it('should request a player when the div id does not match a player on the page and only 1 player is in the DOM', function () { + const playerDomElement = document.createElement('div'); + playerDomElement.className = 'jwplayer'; + document.body.appendChild(playerDomElement); + + window.jwplayer.withArgs('invalidDivId').returns(undefined); + window.jwplayer.returns(playerInstanceMock); + + const playerInstance = getPlayer('invalidDivId'); + + expect(playerInstance).to.deep.equal(playerInstanceMock); + + document.body.removeChild(playerDomElement); + }); + + it('should fail when the div id does not match a player on the page, and multiple players are instantiated', function () { + const firstPlayerDomElement = document.createElement('div'); + const secondPlayerDomElement = document.createElement('div'); + firstPlayerDomElement.className = 'jwplayer'; + secondPlayerDomElement.className = 'jwplayer'; + document.body.appendChild(firstPlayerDomElement); + document.body.appendChild(secondPlayerDomElement); + + window.jwplayer.withArgs('invalidDivId').returns(undefined); + window.jwplayer.returns(playerInstanceMock); + + const playerInstance = getPlayer('invalidDivId'); + + expect(playerInstance).to.be.undefined; + + document.body.removeChild(firstPlayerDomElement); + document.body.removeChild(secondPlayerDomElement); + }); + }); + describe('jwplayerSubmodule', function () { it('successfully instantiates', function () { expect(jwplayerSubmodule.init()).to.equal(true);