videojs-contrib-ads
Version:
A framework that provides common functionality needed by video advertisement libraries working with video.js.
1,092 lines (817 loc) • 38.2 kB
JavaScript
(function(window, QUnit) {
var timerExists = function(env, keyOrId) {
var timerId = _.isNumber(keyOrId) ? keyOrId : env.player.ads[String(keyOrId)];
return env.clock.timers.hasOwnProperty(String(timerId));
};
QUnit.module('Ad Framework', window.sharedModuleHooks());
QUnit.test('begins in content-set', function(assert) {
assert.expect(1);
assert.strictEqual(this.player.ads.state, 'content-set');
});
QUnit.test('pauses to wait for prerolls when the plugin loads before play', function(assert) {
var spy = sinon.spy(this.player, 'pause');
assert.expect(1);
this.player.paused = function() {
return false;
};
this.player.trigger('adsready');
this.player.trigger('play');
this.clock.tick(1);
this.player.trigger('play');
this.clock.tick(1);
assert.strictEqual(spy.callCount, 2, 'play attempts are paused');
});
QUnit.test('pauses to wait for prerolls when the plugin loads after play', function(assert) {
var pauseSpy;
assert.expect(1);
this.player.paused = function() {
return false;
};
pauseSpy = sinon.spy(this.player, 'pause');
this.player.trigger('play');
this.clock.tick(1);
this.player.trigger('play');
this.clock.tick(1);
assert.equal(pauseSpy.callCount, 2, 'play attempts are paused');
});
QUnit.test('stops canceling play events when an ad is playing', function(assert) {
var setTimeoutSpy = sinon.spy(window, 'setTimeout');
assert.expect(10);
// Throughout this test, we check both that the expected timeouts are
// populated on the `clock` _and_ that `setTimeout` has been called the
// expected number of times.
assert.notOk(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` does not exist');
assert.notOk(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` does not exist');
this.player.trigger('play');
assert.strictEqual(setTimeoutSpy.callCount, 2, 'two timers were created (`cancelPlayTimeout` and `adTimeoutTimeout`)');
assert.ok(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` exists');
assert.ok(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` exists');
this.player.trigger('adsready');
assert.strictEqual(setTimeoutSpy.callCount, 3, '`adTimeoutTimeout` was re-scheduled');
assert.ok(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` exists');
this.clock.tick(1);
this.player.trigger('adstart');
assert.strictEqual(this.player.ads.state, 'ad-playback', 'ads are playing');
assert.notOk(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` no longer exists');
assert.notOk(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` no longer exists');
window.setTimeout.restore();
});
QUnit.test('adstart is fired before a preroll', function(assert) {
var spy = sinon.spy();
assert.expect(1);
this.player.on('adstart', spy);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
assert.strictEqual(spy.callCount, 1, 'a preroll triggers adstart');
});
QUnit.test('player has the .vjs-has-started class once a preroll begins', function(assert) {
assert.expect(1);
this.player.trigger('adsready');
// This is a bit of a hack in order to not need the test to be async.
this.player.tech_.trigger('play');
this.player.ads.startLinearAdMode();
assert.ok(this.player.hasClass('vjs-has-started'), 'player has .vjs-has-started class');
});
QUnit.test('moves to content-playback after a preroll', function(assert) {
assert.expect(2);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.ads.state, 'content-resuming', 'the state is content-resuming');
this.player.trigger('playing');
assert.strictEqual(this.player.ads.state, 'content-playback', 'the state is content-resuming');
});
QUnit.test('moves to ad-playback if a midroll is requested', function(assert) {
assert.expect(1);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback', 'the state is ad-playback');
});
QUnit.test('moves to content-playback if the preroll times out', function(assert) {
this.player.trigger('adsready');
this.player.trigger('play');
this.player.trigger('adtimeout');
assert.strictEqual(this.player.ads.state, 'content-playback', 'the state is content-playback');
});
QUnit.test('waits for adsready if play is received first', function(assert) {
assert.expect(1);
this.player.trigger('play');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'preroll?', 'the state is preroll?');
});
QUnit.test('moves to content-playback if a plugin does not finish initializing', function(assert) {
this.player.trigger('play');
this.player.trigger('adtimeout');
assert.strictEqual(this.player.ads.state, 'content-playback', 'the state is content-playback');
});
QUnit.test('calls start immediately on play when ads are ready', function(assert) {
var spy = sinon.spy();
assert.expect(1);
this.player.on('readyforpreroll', spy);
this.player.trigger('adsready');
this.player.trigger('play');
assert.strictEqual(spy.callCount, 1, 'readyforpreroll was fired');
});
QUnit.test('adds the ad-mode class when a preroll plays', function(assert) {
var el;
assert.expect(1);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
el = this.player.el();
assert.ok(this.player.hasClass('vjs-ad-playing'), 'the ad class should be in "' + el.className + '"');
});
QUnit.test('removes the ad-mode class when a preroll finishes', function(assert) {
var el;
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
el = this.player.el();
assert.notOk(this.player.hasClass('vjs-ad-playing'), 'the ad class should not be in "' + el.className + '"');
assert.strictEqual(this.player.ads.triggerevent, 'adend', 'triggerevent for content-resuming should have been adend');
this.player.trigger('playing');
});
QUnit.test('adds a class while waiting for an ad plugin to load', function(assert) {
var el;
assert.expect(1);
this.player.trigger('play');
el = this.player.el();
assert.ok(this.player.hasClass('vjs-ad-loading'), 'the ad loading class should be in "' + el.className + '"');
});
QUnit.test('adds a class while waiting for a preroll', function(assert) {
var el;
assert.expect(1);
this.player.trigger('adsready');
this.player.trigger('play');
el = this.player.el();
assert.ok(this.player.hasClass('vjs-ad-loading'), 'the ad loading class should be in "' + el.className + '"');
});
QUnit.test('removes the loading class when the preroll begins', function(assert) {
var el;
assert.expect(1);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.trigger('ads-ad-started');
el = this.player.el();
assert.notOk(this.player.hasClass('vjs-ad-loading'), 'there should be no ad loading class present in "' + el.className + '"');
});
QUnit.test('removes the loading class when the preroll times out', function(assert) {
var el;
this.player.trigger('adsready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('playing');
el = this.player.el();
assert.notOk(this.player.hasClass('vjs-ad-loading'), 'there should be no ad loading class present in "' + el.className + '"');
});
QUnit.test('starts the content video if there is no preroll', function(assert) {
var spy = sinon.spy(this.player, 'play');
this.player.trigger('adsready');
this.player.trigger('play');
this.clock.tick(1);
this.player.trigger('adtimeout');
assert.strictEqual(spy.callCount, 1, 'play is called once');
});
QUnit.test('removes the poster attribute so it does not flash between videos', function(assert) {
this.video.poster = 'http://www.videojs.com/img/poster.jpg';
assert.ok(this.video.poster, 'the poster is present initially');
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.video.poster, '', 'poster is removed');
});
QUnit.test('restores the poster attribute after ads have ended', function(assert) {
this.video.poster = 'http://www.videojs.com/img/poster.jpg';
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
assert.ok(this.video.poster, 'the poster is restored');
this.player.trigger('playing');
});
QUnit.test('changing the src triggers "contentupdate"', function(assert) {
var spy = sinon.spy();
assert.expect(1);
this.player.on('contentupdate', spy);
// set src and trigger synthetic 'loadstart'
this.player.src('http://media.w3.org/2010/05/sintel/trailer.mp4');
this.player.trigger('loadstart');
assert.strictEqual(spy.callCount, 1, 'one contentupdate event fired');
});
QUnit.test('"contentupdate" should fire when src is changed in "content-resuming" state after postroll', function(assert) {
var spy = sinon.spy();
assert.expect(2);
this.player.on('contentupdate', spy);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
this.player.trigger('adtimeout');
this.player.ads.snapshot.ended = true;
// set src and trigger synthetic 'loadstart'
this.player.src('http://media.w3.org/2010/05/sintel/trailer.mp4');
this.player.trigger('loadstart');
assert.strictEqual(spy.callCount, 1, 'one contentupdate event fired');
assert.strictEqual(this.player.ads.state, 'content-set', 'we are in the content-set state');
});
QUnit.test('"contentupdate" should fire when src is changed in "content-playback" state after postroll', function(assert) {
var spy = sinon.spy();
assert.expect(2);
this.player.on('contentupdate', spy);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
this.player.trigger('adtimeout');
this.player.ads.snapshot.ended = true;
this.player.trigger('ended');
// set src and trigger synthetic 'loadstart'
this.player.src('http://media.w3.org/2010/05/sintel/trailer.mp4');
this.player.trigger('loadstart');
assert.strictEqual(spy.callCount, 1, 'one contentupdate event fired');
assert.strictEqual(this.player.ads.state, 'content-set', 'we are in the content-set state');
});
QUnit.test('changing src does not trigger "contentupdate" during ad playback', function(assert) {
var spy = sinon.spy();
this.player.on('contentupdate', spy);
// enter ad playback mode
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
// set src and trigger synthetic 'loadstart'
this.player.src('http://media.w3.org/2010/05/sintel/trailer.mp4');
this.player.trigger('loadstart');
// finish playing ad
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 0, 'no contentupdate events fired');
});
QUnit.test('the `cancelPlayTimeout` timeout is cleared when exiting "preroll?"', function(assert) {
var setTimeoutSpy = sinon.spy(window, 'setTimeout');
assert.expect(5);
this.player.trigger('adsready');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'preroll?', 'the player is waiting for prerolls');
assert.strictEqual(setTimeoutSpy.callCount, 2, 'two timers were created (`cancelPlayTimeout` and `adTimeoutTimeout`)');
assert.ok(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` exists');
assert.ok(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` exists');
this.player.trigger('play');
this.player.trigger('play');
this.player.trigger('play');
assert.strictEqual(setTimeoutSpy.callCount, 2, 'no additional timers were created on subsequent "play" events');
window.setTimeout.restore();
});
QUnit.test('"adscanceled" allows us to transition from "content-set" to "content-playback"', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adscanceled');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('"adscanceled" allows us to transition from "ads-ready?" to "content-playback"', function(assert) {
var setTimeoutSpy = sinon.spy(window, 'setTimeout');
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'ads-ready?');
assert.strictEqual(setTimeoutSpy.callCount, 2, 'two timers were created (`cancelPlayTimeout` and `adTimeoutTimeout`)');
assert.ok(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` exists');
assert.ok(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` exists');
this.player.trigger('adscanceled');
assert.strictEqual(this.player.ads.state, 'content-playback');
assert.notOk(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` was canceled');
window.setTimeout.restore();
});
QUnit.test('content is resumed on contentplayback if a user initiated play event is canceled', function(assert) {
var playSpy = sinon.spy(this.player, 'play');
var setTimeoutSpy = sinon.spy(window, 'setTimeout');
assert.expect(8);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'ads-ready?');
assert.strictEqual(setTimeoutSpy.callCount, 2, 'two timers were created (`cancelPlayTimeout` and `adTimeoutTimeout`)');
assert.ok(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` exists');
assert.ok(timerExists(this, 'adTimeoutTimeout'), '`adTimeoutTimeout` exists');
this.clock.tick(1);
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-playback');
assert.notOk(timerExists(this, 'cancelPlayTimeout'), '`cancelPlayTimeout` was canceled');
assert.strictEqual(playSpy.callCount, 1, 'a play event should be triggered once we enter "content-playback" state if on was canceled.');
});
QUnit.test('adserror in content-set transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adskip in content-set transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adskip');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adserror in ads-ready? transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'ads-ready?');
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adskip in ads-ready? transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'ads-ready?');
this.player.trigger('adskip');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adserror in ads-ready transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adskip in ads-ready transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('adskip');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adserror in preroll? transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'preroll?');
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adskip in preroll? transitions to content-playback', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'preroll?');
this.player.trigger('adskip');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adserror in postroll? transitions to content-playback and fires ended', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
assert.strictEqual(this.player.ads.state, 'postroll?');
this.player.ads.snapshot.ended = true;
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(this.player.ads.triggerevent, 'adserror', 'adserror should be the trigger event');
this.clock.tick(1);
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adtimeout in postroll? transitions to content-playback and fires ended', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
assert.strictEqual(this.player.ads.state, 'postroll?');
this.player.ads.snapshot.ended = true;
this.player.trigger('adtimeout');
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(this.player.ads.triggerevent, 'adtimeout', 'adtimeout should be the trigger event');
this.clock.tick(1);
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adskip in postroll? transitions to content-playback and fires ended', function(assert) {
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
assert.strictEqual(this.player.ads.state, 'postroll?');
this.player.ads.snapshot.ended = true;
this.player.trigger('adskip');
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(this.player.ads.triggerevent, 'adskip', 'adskip should be the trigger event');
this.clock.tick(1);
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('an "ended" event is fired in "content-resuming" via a timeout if not fired naturally', function(assert) {
var endedSpy = sinon.spy();
assert.expect(6);
this.player.on('ended', endedSpy);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
assert.strictEqual(this.player.ads.state, 'postroll?');
this.player.ads.startLinearAdMode();
this.player.ads.snapshot.ended = true;
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(endedSpy.callCount, 0, 'we should not have gotten an ended event yet');
this.clock.tick(1000);
assert.strictEqual(endedSpy.callCount, 1, 'we should have fired ended from the timeout');
});
QUnit.test('an "ended" event is not fired in "content-resuming" via a timeout if fired naturally', function(assert) {
var endedSpy = sinon.spy();
assert.expect(6);
this.player.on('ended', endedSpy);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.trigger('adtimeout');
this.player.trigger('ended');
assert.strictEqual(this.player.ads.state, 'postroll?');
this.player.ads.startLinearAdMode();
this.player.ads.snapshot.ended = true;
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(endedSpy.callCount, 0, 'we should not have gotten an ended event yet');
this.player.trigger('ended');
assert.strictEqual(endedSpy.callCount, 1, 'we should have fired ended from the timeout');
});
QUnit.test('adserror in ad-playback transitions to content-playback and triggers adend', function(assert) {
var spy;
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
spy = sinon.spy();
this.player.on('adend', spy);
this.player.trigger('adserror');
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(this.player.ads.triggerevent, 'adserror', 'The reason for content-resuming should have been adserror');
this.player.trigger('playing');
assert.strictEqual(this.player.ads.state, 'content-playback');
assert.strictEqual(spy.getCall(0).args[0].type, 'adend', 'adend should be fired when we enter content-playback from adserror');
});
QUnit.test('calling startLinearAdMode() when already in ad-playback does not trigger adstart', function(assert) {
var spy = sinon.spy();
this.player.on('adstart', spy);
assert.strictEqual(this.player.ads.state, 'content-set');
// go through preroll flow
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'preroll?');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback');
assert.strictEqual(spy.callCount, 1, 'adstart should have fired');
// add an extraneous start call
this.player.ads.startLinearAdMode();
assert.strictEqual(spy.callCount, 1, 'adstart should not have fired');
// make sure subsequent adstarts trigger again on exit/re-enter
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
assert.strictEqual(this.player.ads.state, 'content-playback');
this.player.ads.startLinearAdMode();
assert.strictEqual(spy.callCount, 2, 'adstart should have fired');
});
QUnit.test('calling endLinearAdMode() in any state but ad-playback does not trigger adend', function(assert) {
var spy;
assert.expect(13);
spy = sinon.spy();
this.player.on('adend', spy);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 0, 'adend should not have fired');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 0, 'adend should not have fired');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'preroll?');
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 0, 'adend should not have fired');
this.player.trigger('adtimeout');
assert.strictEqual(this.player.ads.state, 'content-playback');
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 0, 'adend should not have fired');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback');
this.player.ads.endLinearAdMode();
assert.strictEqual(spy.callCount, 1, 'adend should have fired');
this.player.trigger('playing');
assert.strictEqual(this.player.ads.state, 'content-playback');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback');
this.player.trigger('adserror');
assert.strictEqual(spy.callCount, 2, 'adend should have fired');
});
QUnit.test('skipLinearAdMode in ad-playback does not trigger adskip', function(assert) {
var spy;
spy = sinon.spy();
this.player.on('adskip', spy);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('adsready');
assert.strictEqual(this.player.ads.state, 'ads-ready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback');
this.player.ads.skipLinearAdMode();
assert.strictEqual(this.player.ads.state, 'ad-playback');
assert.strictEqual(spy.callCount, 0, 'adskip event should not trigger when skipLinearAdMode called in ad-playback state');
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.ads.state, 'content-resuming');
assert.strictEqual(this.player.ads.triggerevent, 'adend', 'The reason for content-resuming should have been adend');
this.player.trigger('playing');
assert.strictEqual(this.player.ads.state, 'content-playback');
});
QUnit.test('adsready in content-playback triggers readyforpreroll', function(assert) {
var spy;
spy = sinon.spy();
this.player.on('readyforpreroll', spy);
assert.strictEqual(this.player.ads.state, 'content-set');
this.player.trigger('play');
assert.strictEqual(this.player.ads.state, 'ads-ready?');
this.player.trigger('adtimeout');
assert.strictEqual(this.player.ads.state, 'content-playback');
this.player.trigger('adsready');
assert.strictEqual(spy.getCall(0).args[0].type, 'readyforpreroll', 'readyforpreroll should have been triggered.');
});
// ----------------------------------
// Event prefixing during ad playback
// ----------------------------------
QUnit.test('player events during prerolls are prefixed if tech is reused for ad', function(assert) {
var prefixed, unprefixed;
assert.expect(2);
prefixed = sinon.spy();
unprefixed = sinon.spy();
// play a preroll
this.player.on('readyforpreroll', function() {
this.ads.startLinearAdMode();
});
this.player.trigger('play');
this.player.trigger('adsready');
this.player.ads.snapshot = {
currentSrc: 'something'
};
// simulate video events that should be prefixed
this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
this.player.on(['adloadstart', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
this.player.trigger('firstplay');
this.player.trigger('loadstart');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
this.player.trigger('pause');
this.player.trigger('ended');
assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
assert.strictEqual(prefixed.callCount, 5, 'prefixed events fired');
});
QUnit.test('player events during midrolls are prefixed if tech is reused for ad', function(assert) {
var prefixed, unprefixed;
assert.expect(2);
prefixed = sinon.spy();
unprefixed = sinon.spy();
// play a midroll
this.player.trigger('play');
this.player.trigger('adsready');
this.player.trigger('adtimeout');
this.player.ads.startLinearAdMode();
this.player.ads.snapshot = {
currentSrc: 'something'
};
// simulate video events that should be prefixed
this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
this.player.on(['adloadstart', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
this.player.trigger('firstplay');
this.player.trigger('loadstart');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
this.player.trigger('pause');
this.player.trigger('ended');
assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
assert.strictEqual(prefixed.callCount, 5, 'prefixed events fired');
});
QUnit.test('player events during postrolls are prefixed if tech is reused for ad', function(assert) {
var prefixed, unprefixed;
assert.expect(2);
prefixed = sinon.spy();
unprefixed = sinon.spy();
// play a postroll
this.player.trigger('play');
this.player.trigger('adsready');
this.player.trigger('adtimeout');
this.player.trigger('ended');
this.player.ads.startLinearAdMode();
this.player.ads.snapshot = {
currentSrc: 'something'
};
// simulate video events that should be prefixed
this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
this.player.on(['adloadstart', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
this.player.trigger('firstplay');
this.player.trigger('loadstart');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
this.player.trigger('pause');
this.player.trigger('ended');
assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
assert.strictEqual(prefixed.callCount, 5, 'prefixed events fired');
});
QUnit.test('player events during stitched ads are prefixed', function(assert) {
var prefixed, unprefixed;
assert.expect(2);
prefixed = sinon.spy();
unprefixed = sinon.spy();
this.player.ads.stitchedAds(true);
// play a midroll
this.player.trigger('play');
this.player.trigger('adsready');
this.player.trigger('adtimeout');
this.player.ads.startLinearAdMode();
// simulate video events that should be prefixed
this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
this.player.on(['adloadstart', 'adplaying', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
this.player.trigger('firstplay');
this.player.trigger('loadstart');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
this.player.trigger('pause');
this.player.trigger('ended');
assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
assert.strictEqual(prefixed.callCount, 6, 'prefixed events fired');
});
QUnit.test('player events during content playback are not prefixed', function(assert) {
var prefixed, unprefixed;
assert.expect(3);
prefixed = sinon.spy();
unprefixed = sinon.spy();
// play content
this.player.trigger('play');
this.player.trigger('adsready');
this.player.trigger('adtimeout');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
// simulate video events that should not be prefixed
this.player.on(['seeked', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
this.player.on(['adseeked', 'adplaying', 'adpause', 'adended', 'contentended', 'adfirstplay', 'adloadedalldata'], prefixed);
this.player.trigger('firstplay');
this.player.trigger('seeked');
this.player.trigger('playing');
this.player.trigger('loadedalldata');
this.player.trigger('pause');
this.player.trigger('ended');
assert.strictEqual(unprefixed.callCount, 5, 'unprefixed events fired');
assert.strictEqual(prefixed.callCount, 1, 'prefixed events fired');
assert.strictEqual(prefixed.getCall(0).args[0].type, 'contentended', 'prefixed the ended event');
});
QUnit.test('startLinearAdMode should only trigger adstart from correct states', function(assert) {
var adstart = sinon.spy();
this.player.on('adstart', adstart);
this.player.ads.state = 'preroll?';
this.player.ads.startLinearAdMode();
assert.strictEqual(adstart.callCount, 1, 'preroll? state');
this.player.ads.state = 'content-playback';
this.player.ads.startLinearAdMode();
assert.strictEqual(adstart.callCount, 2, 'content-playback state');
this.player.ads.state = 'postroll?';
this.player.ads.startLinearAdMode();
assert.strictEqual(adstart.callCount, 3, 'postroll? state');
this.player.ads.state = 'content-set';
this.player.ads.startLinearAdMode();
this.player.ads.state = 'ads-ready?';
this.player.ads.startLinearAdMode();
this.player.ads.state = 'ads-ready';
this.player.ads.startLinearAdMode();
this.player.ads.state = 'ad-playback';
this.player.ads.startLinearAdMode();
assert.strictEqual(adstart.callCount, 3, 'other states');
});
QUnit.test('ad impl can notify contrib-ads there is no preroll', function(assert) {
this.player.ads.state = 'preroll?';
this.player.trigger('nopreroll');
assert.strictEqual(this.player.ads.state, 'content-playback', 'no longer in preroll?');
});
QUnit.test('ad impl can notify contrib-ads there is no postroll', function(assert) {
this.player.trigger('nopostroll');
this.player.ads.state = 'content-playback';
this.player.trigger('contentended');
this.clock.tick(5);
assert.strictEqual(this.player.ads.state, 'content-resuming', 'no longer in postroll?');
});
QUnit.test('ended event is sent with postroll', function(assert) {
var ended = sinon.spy();
this.player.tech_.el_ = {
ended: true,
hasChildNodes: function() {
return false;
},
removeAttribute: function() {
}
};
this.player.on('ended', ended);
this.player.ads.state = 'content-playback';
this.player.trigger('contentended');
this.clock.tick(10000);
assert.ok(ended.calledOnce, 'Ended triggered');
});
QUnit.test('ended event is sent without postroll', function(assert) {
var ended = sinon.spy();
this.player.tech_.el_ = {
ended: true,
hasChildNodes: function() {
return false;
},
removeAttribute: function() {
}
};
this.player.on('ended', ended);
this.player.ads.state = 'content-playback';
this.player.trigger('contentended');
this.clock.tick(10000);
assert.ok(ended.calledOnce, 'Ended triggered');
});
QUnit.test('isLive', function(assert) {
this.player.duration = function() {return 0;};
videojs.browser.IOS_VERSION = '8';
assert.strictEqual(this.player.ads.isLive(this.player), true);
this.player.duration = function() {return 5;};
videojs.browser.IOS_VERSION = '8';
assert.strictEqual(this.player.ads.isLive(this.player), false);
this.player.duration = function() {return Infinity;};
videojs.browser.IOS_VERSION = '8';
assert.strictEqual(this.player.ads.isLive(this.player), true);
this.player.duration = function() {return 0;};
videojs.browser.IOS_VERSION = undefined;
assert.strictEqual(this.player.ads.isLive(this.player), false);
this.player.duration = function() {return 5;};
videojs.browser.IOS_VERSION = undefined;
assert.strictEqual(this.player.ads.isLive(this.player), false);
this.player.duration = function() {return Infinity;};
videojs.browser.IOS_VERSION = undefined;
assert.strictEqual(this.player.ads.isLive(this.player), true);
});
QUnit.test('shouldPlayContentBehindAd', function(assert) {
this.player.duration = function() {return Infinity;};
videojs.browser.IS_IOS = true;
videojs.browser.IS_ANDROID = true;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return Infinity;};
videojs.browser.IS_IOS = true;
videojs.browser.IS_ANDROID = false;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return Infinity;};
videojs.browser.IS_IOS = false;
videojs.browser.IS_ANDROID = true;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return Infinity;};
videojs.browser.IS_IOS = false;
videojs.browser.IS_ANDROID = false;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), true);
this.player.duration = function() {return 5;};
videojs.browser.IS_IOS = true;
videojs.browser.IS_ANDROID = true;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return 5;};
videojs.browser.IS_IOS = true;
videojs.browser.IS_ANDROID = false;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return 5;};
videojs.browser.IS_IOS = false;
videojs.browser.IS_ANDROID = true;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
this.player.duration = function() {return 5;};
videojs.browser.IS_IOS = false;
videojs.browser.IS_ANDROID = false;
assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
});
QUnit.test('Check incorrect addition of vjs-live during ad-playback', function(assert) {
this.player.trigger('play');
this.player.ads.startLinearAdMode();
assert.strictEqual(this.player.hasClass('vjs-live'), false, 'We have the correct class');
});
QUnit.test('Check for existence of vjs-live after ad-end for LIVE videos',
function(assert) {
this.player.trigger('adstart');
this.player.ads.startLinearAdMode();
this.player.ads.state = 'ad-playback';
this.player.duration = function() {return Infinity;};
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
assert.strictEqual(this.player.ads.isLive(this.player), true, 'Content is LIVE');
assert.ok(this.player.hasClass('vjs-live'), 'We should be having vjs-live class here');
});
QUnit.test('Plugin state resets after contentupdate', function(assert) {
assert.equal(this.player.ads.disableNextSnapshotRestore, false);
assert.equal(this.player.ads._contentHasEnded, false);
assert.equal(this.player.ads.snapshot, null);
this.player.ads.disableNextSnapshotRestore = true;
this.player.ads._contentHasEnded = true;
this.player.ads.snapshot = {};
this.player.trigger('contentupdate');
assert.equal(this.player.ads.disableNextSnapshotRestore, false);
assert.equal(this.player.ads._contentHasEnded, false);
assert.equal(this.player.ads.snapshot, null);
});
}(window, window.QUnit));