UNPKG

33.3 kBJavaScriptView Raw
1import QUnit from 'qunit';
2import sinon from 'sinon';
3import videojs from 'video.js';
4import sharedModuleHooks from './lib/shared-module-hooks.js';
5
6QUnit.module('Contrib Ads', sharedModuleHooks());
7
8QUnit.test('begins in BeforePreroll', function(assert) {
9 assert.equal(this.player.ads._state.constructor.name, 'BeforePreroll');
10});
11
12QUnit.test('adstart is fired before a preroll', function(assert) {
13 const spy = sinon.spy();
14
15 assert.expect(1);
16
17 this.player.on('adstart', spy);
18 this.player.trigger('adsready');
19 this.player.trigger('play');
20 this.player.ads.startLinearAdMode();
21 assert.strictEqual(spy.callCount, 1, 'a preroll triggers adstart');
22});
23
24QUnit.test('player has the .vjs-has-started class once a preroll begins', function(assert) {
25 assert.expect(1);
26 this.player.trigger('adsready');
27
28 // This is a bit of a hack in order to not need the test to be async.
29 this.player.tech_.trigger('play');
30 this.player.ads.startLinearAdMode();
31 assert.ok(this.player.hasClass('vjs-has-started'), 'player has .vjs-has-started class');
32});
33
34QUnit.test('calls start immediately on play when ads are ready', function(assert) {
35 const readyForPrerollSpy = sinon.spy();
36
37 assert.expect(1);
38
39 this.player.on('readyforpreroll', readyForPrerollSpy);
40 this.player.trigger('adsready');
41 this.player.trigger('loadstart');
42 this.player.trigger('play');
43 assert.strictEqual(readyForPrerollSpy.callCount, 1, 'readyforpreroll was fired');
44});
45
46QUnit.test('adds the ad-mode class when a preroll plays', function(assert) {
47 assert.expect(1);
48
49 this.player.trigger('adsready');
50 this.player.trigger('play');
51 this.player.ads.startLinearAdMode();
52 const el = this.player.el();
53
54 assert.ok(this.player.hasClass('vjs-ad-playing'), 'the ad class should be in "' + el.className + '"');
55});
56
57QUnit.test('removes the ad-mode class when a preroll finishes', function(assert) {
58
59 this.player.trigger('adsready');
60 this.player.trigger('play');
61 this.player.ads.startLinearAdMode();
62 this.player.ads.endLinearAdMode();
63 const el = this.player.el();
64
65 assert.notOk(this.player.hasClass('vjs-ad-playing'), 'the ad class should not be in "' + el.className + '"');
66
67 this.player.trigger('playing');
68});
69
70QUnit.test('adds a class while waiting for an ad plugin to load', function(assert) {
71 assert.expect(1);
72
73 this.player.trigger('play');
74 const el = this.player.el();
75
76 assert.ok(this.player.hasClass('vjs-ad-loading'), 'the ad loading class should be in "' + el.className + '"');
77});
78
79QUnit.test('adds a class while waiting for a preroll', function(assert) {
80 assert.expect(1);
81
82 this.player.trigger('adsready');
83 this.player.trigger('play');
84 const el = this.player.el();
85
86 assert.ok(this.player.hasClass('vjs-ad-loading'), 'the ad loading class should be in "' + el.className + '"');
87});
88
89QUnit.test('removes the loading class when the preroll begins', function(assert) {
90 assert.expect(1);
91
92 this.player.trigger('adsready');
93 this.player.trigger('play');
94 this.player.ads.startLinearAdMode();
95 this.player.trigger('ads-ad-started');
96 const el = this.player.el();
97
98 assert.notOk(this.player.hasClass('vjs-ad-loading'), 'there should be no ad loading class present in "' + el.className + '"');
99});
100
101QUnit.test('removes the loading class when the preroll times out', function(assert) {
102 this.player.trigger('loadstart');
103 this.player.trigger('adsready');
104 this.player.trigger('play');
105 this.player.trigger('adtimeout');
106 this.player.trigger('playing');
107 const el = this.player.el();
108
109 assert.notOk(this.player.hasClass('vjs-ad-loading'), 'there should be no ad loading class present in "' + el.className + '"');
110});
111
112QUnit.test('begins resuming to content if there is no preroll', function(assert) {
113 this.player.trigger('loadstart');
114 this.player.trigger('adsready');
115 this.player.trigger('play');
116 this.clock.tick(1);
117 this.player.trigger('adtimeout');
118
119 assert.strictEqual(this.player.ads.inAdBreak(), false, 'should not be in an ad break');
120 assert.strictEqual(this.player.ads.isContentResuming(), true, 'should be resuming content');
121 assert.strictEqual(this.player.ads.isInAdMode(), true, 'should be in ad mode');
122});
123
124QUnit.test('removes the poster attribute so it does not flash between videos', function(assert) {
125 this.video.poster = 'http://www.videojs.com/img/poster.jpg';
126 assert.ok(this.video.poster, 'the poster is present initially');
127
128 this.player.trigger('adsready');
129 this.player.trigger('play');
130 this.player.ads.startLinearAdMode();
131 assert.strictEqual(this.video.poster, '', 'poster is removed');
132});
133
134QUnit.test('changing the src triggers "contentupdate"', function(assert) {
135 const spy = sinon.spy();
136
137 assert.expect(1);
138
139 this.player.on('contentupdate', spy);
140
141 // set src and trigger synthetic 'loadstart'
142 this.player.currentSrc = () => 'AH HA!!! I AM NOT A REAL SOURCE';
143 this.player.trigger('loadstart');
144 assert.strictEqual(spy.callCount, 1, 'one contentupdate event fired');
145});
146
147QUnit.test('"contentupdate" should fire when src is changed after postroll', function(assert) {
148 const contentupdateSpy = sinon.spy();
149
150 this.player.on('contentupdate', contentupdateSpy);
151
152 this.player.trigger('adsready');
153 this.player.trigger('play');
154 this.player.trigger('adtimeout');
155 this.player.trigger('ended');
156 this.player.trigger('adtimeout');
157
158 // set src and trigger synthetic 'loadstart'
159 this.player.src({
160 src: 'http://vjs.zencdn.net/v/oceans.webm',
161 type: 'video/webm'
162 });
163 this.player.trigger('loadstart');
164 assert.strictEqual(contentupdateSpy.callCount, 1, 'one contentupdate event fired');
165});
166
167QUnit.test('"contentupdate" should fire when src is changed after postroll', function(assert) {
168 const contentupdateSpy = sinon.spy();
169
170 this.player.on('contentupdate', contentupdateSpy);
171 this.player.trigger('adsready');
172 this.player.trigger('play');
173 this.player.trigger('adtimeout');
174 this.player.trigger('ended');
175 this.player.trigger('adtimeout');
176 this.player.trigger('ended');
177
178 // set src and trigger synthetic 'loadstart'
179 this.player.src({
180 src: 'http://vjs.zencdn.net/v/oceans.webm',
181 type: 'video/webm'
182 });
183 this.player.trigger('loadstart');
184 assert.strictEqual(contentupdateSpy.callCount, 1, 'one contentupdate event fired');
185});
186
187QUnit.test('changing src does not trigger "contentupdate" during ad playback', function(assert) {
188 const spy = sinon.spy();
189
190 this.player.on('contentupdate', spy);
191
192 // enter ad playback mode
193 this.player.trigger('adsready');
194 this.player.trigger('play');
195 this.player.ads.startLinearAdMode();
196
197 // set src and trigger synthetic 'loadstart'
198 this.player.src({
199 src: 'http://vjs.zencdn.net/v/oceans.webm',
200 type: 'video/webm'
201 });
202 this.player.trigger('loadstart');
203
204 // finish playing ad
205 this.player.ads.endLinearAdMode();
206 assert.strictEqual(spy.callCount, 0, 'no contentupdate events fired');
207});
208
209QUnit.test('the `_playRequested` flag is set on the first play request', function(assert) {
210 this.player.trigger('loadstart');
211 this.player.trigger('adsready');
212 assert.strictEqual(
213 this.player.ads._playRequested, false,
214 'initially set to false'
215 );
216 assert.strictEqual(
217 this.player.ads.isInAdMode(), false,
218 'starts in a content state'
219 );
220
221 this.player.trigger('play');
222 assert.strictEqual(
223 this.player.ads._playRequested, true,
224 '_playRequested is now true'
225 );
226 assert.strictEqual(
227 this.player.ads.isInAdMode(), true,
228 'now in ad state'
229 );
230});
231
232QUnit.test('ended event happens after postroll errors out', function(assert) {
233 const endedSpy = sinon.spy();
234
235 this.player.on('ended', endedSpy);
236
237 this.player.trigger('loadstart');
238 this.player.trigger('adsready');
239 this.player.trigger('play');
240 this.player.trigger('adtimeout');
241 // Entered content
242 this.player.trigger('playing');
243 this.player.trigger('ended');
244 this.player.trigger('adserror');
245
246 this.clock.tick(1);
247 assert.strictEqual(endedSpy.callCount, 1, 'ended event happened');
248});
249
250QUnit.test('ended event happens after postroll timed out', function(assert) {
251 const endedSpy = sinon.spy();
252
253 this.player.on('ended', endedSpy);
254
255 this.player.trigger('loadstart');
256 this.player.trigger('adsready');
257 this.player.trigger('play');
258 this.player.trigger('adtimeout');
259 // Entered content
260 this.player.trigger('playing');
261 this.player.trigger('ended');
262 this.player.trigger('adtimeout');
263
264 this.clock.tick(1);
265 assert.strictEqual(endedSpy.callCount, 1, 'ended event happened');
266});
267
268QUnit.test('ended event happens after postroll skipped', function(assert) {
269 const endedSpy = sinon.spy();
270
271 this.player.on('ended', endedSpy);
272
273 this.player.trigger('loadstart');
274 this.player.trigger('adsready');
275 this.player.trigger('play');
276 // preroll times out
277 this.player.trigger('adtimeout');
278 // Entered content
279 this.player.trigger('playing');
280 // content ends
281 this.player.trigger('ended');
282 this.player.ads.skipLinearAdMode();
283
284 this.clock.tick(1);
285 assert.strictEqual(endedSpy.callCount, 1, 'ended event happened');
286});
287
288QUnit.test('an "ended" event is fired after postroll if not fired naturally', function(assert) {
289 const endedSpy = sinon.spy();
290
291 this.player.on('ended', endedSpy);
292
293 this.player.trigger('loadstart');
294 this.player.trigger('adsready');
295 this.player.trigger('play');
296 // skip preroll
297 this.player.trigger('adtimeout');
298 // return to content
299 this.player.trigger('playing');
300 // handled by redispatch
301 this.player.trigger('ended');
302
303 assert.strictEqual(endedSpy.callCount, 0, 'no ended event before postroll');
304
305 // start postroll
306 this.player.ads.startLinearAdMode();
307 this.player.ads.endLinearAdMode();
308 this.player.trigger('resumeended');
309 assert.strictEqual(endedSpy.callCount, 1, 'ended event happened');
310});
311
312QUnit.test('ended events when content ends first and second time', function(assert) {
313 const endedSpy = sinon.spy();
314
315 this.player.on('ended', endedSpy);
316
317 this.player.trigger('loadstart');
318 this.player.trigger('adsready');
319 this.player.trigger('play');
320 // Preroll times out
321 this.player.trigger('adtimeout');
322 // Entered content
323 this.player.trigger('playing');
324 // Triggers readyforpostroll
325 this.player.trigger('ended');
326
327 // Postroll starts
328 this.player.ads.startLinearAdMode();
329 this.player.ads.endLinearAdMode();
330 this.player.trigger('resumeended');
331
332 assert.strictEqual(endedSpy.callCount, 1, 'ended event after postroll');
333
334 this.player.trigger('ended');
335 assert.strictEqual(endedSpy.callCount, 2, 'ended event after ads done');
336});
337
338QUnit.test('endLinearAdMode during ad break triggers adend', function(assert) {
339 const adendSpy = sinon.spy();
340
341 this.player.on('adend', adendSpy);
342
343 this.player.trigger('loadstart');
344 this.player.trigger('adsready');
345 this.player.trigger('play');
346 this.player.ads.startLinearAdMode();
347
348 assert.strictEqual(adendSpy.callCount, 0, 'no adend yet');
349
350 this.player.ads.endLinearAdMode();
351
352 assert.strictEqual(adendSpy.callCount, 1, 'adend happened');
353});
354
355QUnit.test('calling startLinearAdMode() when already in ad-playback does not trigger adstart', function(assert) {
356 const spy = sinon.spy();
357
358 this.player.on('adstart', spy);
359 this.player.trigger('adsready');
360 this.player.trigger('play');
361 this.player.ads.startLinearAdMode();
362 assert.strictEqual(spy.callCount, 1, 'adstart should have fired');
363
364 // add an extraneous start call
365 this.player.ads.startLinearAdMode();
366 assert.strictEqual(spy.callCount, 1, 'adstart should not have fired');
367
368 // make sure subsequent adstarts trigger again on exit/re-enter
369 this.player.ads.endLinearAdMode();
370 this.player.trigger('playing');
371
372 this.player.ads.startLinearAdMode();
373 assert.strictEqual(spy.callCount, 2, 'adstart should have fired');
374});
375
376QUnit.test('calling endLinearAdMode() outside of linear ad mode does not trigger adend', function(assert) {
377 const adendSpy = sinon.spy();
378
379 this.player.on('adend', adendSpy);
380
381 this.player.ads.endLinearAdMode();
382 assert.strictEqual(adendSpy.callCount, 0, 'adend should not have fired right away');
383
384 this.player.trigger('adsready');
385
386 this.player.ads.endLinearAdMode();
387 assert.strictEqual(adendSpy.callCount, 0, 'adend should not have fired after adsready');
388
389 this.player.trigger('play');
390
391 this.player.ads.endLinearAdMode();
392 assert.strictEqual(adendSpy.callCount, 0, 'adend should not have fired after play');
393
394 this.player.trigger('adtimeout');
395
396 this.player.ads.endLinearAdMode();
397 assert.strictEqual(adendSpy.callCount, 0, 'adend should not have fired after adtimeout');
398
399 this.player.ads.startLinearAdMode();
400
401 this.player.ads.endLinearAdMode();
402 assert.strictEqual(adendSpy.callCount, 1, 'adend should have fired after preroll');
403});
404
405QUnit.test('skipLinearAdMode during ad playback does not trigger adskip', function(assert) {
406 const adskipSpy = sinon.spy();
407
408 this.player.on('adskip', adskipSpy);
409
410 this.player.trigger('adsready');
411 this.player.trigger('play');
412 this.player.ads.startLinearAdMode();
413
414 this.player.ads.skipLinearAdMode();
415 assert.strictEqual(
416 adskipSpy.callCount, 0,
417 'adskip event should not trigger when skipLinearAdMode is called during an ad'
418 );
419});
420
421QUnit.test('adsready in content-playback triggers readyforpreroll', function(assert) {
422 const spy = sinon.spy();
423
424 this.player.on('readyforpreroll', spy);
425 this.player.trigger('loadstart');
426 this.player.trigger('play');
427 this.player.trigger('adtimeout');
428 // entered ContentPlayback
429 this.player.trigger('playing');
430 this.player.trigger('adsready');
431 assert.strictEqual(spy.callCount, 1, 'readyforpreroll should have been triggered.');
432});
433
434QUnit.test('adsready while preroll content resuming triggers readyforpreroll', function(assert) {
435 const spy = sinon.spy();
436
437 this.player.on('readyforpreroll', spy);
438 this.player.trigger('loadstart');
439 this.player.trigger('play');
440 this.player.trigger('adtimeout');
441 assert.strictEqual(this.player.ads.isContentResuming(), true, 'should be resuming to content');
442 this.player.trigger('adsready');
443 assert.strictEqual(spy.callCount, 1, 'readyforpreroll should have been triggered.');
444});
445
446// ----------------------------------
447// Event prefixing during ad playback
448// ----------------------------------
449
450QUnit.test('player events during prerolls are prefixed if tech is reused for ad', function(assert) {
451 const sawLoadstart = sinon.spy();
452 const sawPlaying = sinon.spy();
453 const sawPause = sinon.spy();
454 const sawEnded = sinon.spy();
455 const sawFirstplay = sinon.spy();
456 const sawLoadedalldata = sinon.spy();
457 const sawAdloadstart = sinon.spy();
458 const sawAdpause = sinon.spy();
459 const sawAdended = sinon.spy();
460 const sawAdfirstplay = sinon.spy();
461 const sawAdloadedalldata = sinon.spy();
462
463 // play a preroll
464 this.player.on('readyforpreroll', function() {
465 this.ads.startLinearAdMode();
466 });
467
468 this.player.trigger('play');
469 this.player.trigger('loadstart');
470 this.player.trigger('adsready');
471
472 this.player.ads.snapshot = {
473 currentSrc: 'something'
474 };
475
476 // simulate video events that should be prefixed
477 this.player.on('loadstart', sawLoadstart);
478 this.player.on('playing', sawPlaying);
479 this.player.on('pause', sawPause);
480 this.player.on('ended', sawEnded);
481 this.player.on('firstplay', sawFirstplay);
482 this.player.on('loadedalldata', sawLoadedalldata);
483 this.player.on('adloadstart', sawAdloadstart);
484 this.player.on('adpause', sawAdpause);
485 this.player.on('adended', sawAdended);
486 this.player.on('adfirstplay', sawAdfirstplay);
487 this.player.on('adloadedalldata', sawAdloadedalldata);
488 this.player.trigger('firstplay');
489 this.player.trigger('loadstart');
490 this.player.trigger('playing');
491 this.player.trigger('loadedalldata');
492 this.player.trigger('pause');
493 this.player.trigger('ended');
494 assert.strictEqual(sawLoadstart.callCount, 0, 'no loadstart fired');
495 assert.strictEqual(sawPlaying.callCount, 0, 'no playing fired');
496 assert.strictEqual(sawPause.callCount, 0, 'no pause fired');
497 assert.strictEqual(sawEnded.callCount, 0, 'no ended fired');
498 assert.strictEqual(sawFirstplay.callCount, 0, 'no firstplay fired');
499 assert.strictEqual(sawLoadedalldata.callCount, 0, 'no loadedalldata fired');
500 assert.strictEqual(sawAdloadstart.callCount, 1, 'adloadstart fired');
501 assert.strictEqual(sawAdpause.callCount, 1, 'adpause fired');
502 assert.strictEqual(sawAdended.callCount, 1, 'adended fired');
503 assert.strictEqual(sawAdfirstplay.callCount, 1, 'adfirstplay fired');
504 assert.strictEqual(sawAdloadedalldata.callCount, 1, 'adloadedalldata fired');
505});
506
507QUnit.test('player events during midrolls are prefixed if tech is reused for ad', function(assert) {
508 assert.expect(2);
509
510 const prefixed = sinon.spy();
511 const unprefixed = sinon.spy();
512
513 // play a midroll
514 this.player.trigger('play');
515 this.player.trigger('loadstart');
516 this.player.trigger('adsready');
517 this.player.trigger('adtimeout');
518 // return to content
519 this.player.trigger('playing');
520 this.player.ads.startLinearAdMode();
521
522 this.player.ads.snapshot = {
523 currentSrc: 'something'
524 };
525
526 // simulate video events that should be prefixed
527 this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
528 this.player.on(['adloadstart', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
529 this.player.trigger('firstplay');
530 this.player.trigger('loadstart');
531 this.player.trigger('playing');
532 this.player.trigger('loadedalldata');
533 this.player.trigger('pause');
534 this.player.trigger('ended');
535 assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
536 assert.strictEqual(prefixed.callCount, 5, 'prefixed events fired');
537});
538
539QUnit.test('player events during postrolls are prefixed if tech is reused for ad', function(assert) {
540 assert.expect(2);
541
542 const prefixed = sinon.spy();
543 const unprefixed = sinon.spy();
544
545 // play a postroll
546 this.player.trigger('play');
547 this.player.trigger('loadstart');
548 this.player.trigger('adsready');
549 this.player.trigger('adtimeout');
550 // return to content
551 this.player.trigger('playing');
552 this.player.trigger('ended');
553 this.player.ads.startLinearAdMode();
554
555 this.player.ads.snapshot = {
556 currentSrc: 'something'
557 };
558
559 // simulate video events that should be prefixed
560 this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
561 this.player.on(['adloadstart', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
562 this.player.trigger('firstplay');
563 this.player.trigger('loadstart');
564 this.player.trigger('playing');
565 this.player.trigger('loadedalldata');
566 this.player.trigger('pause');
567 this.player.trigger('ended');
568 assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
569 assert.strictEqual(prefixed.callCount, 5, 'prefixed events fired');
570});
571
572QUnit.test('player events during stitched ads are prefixed', function(assert) {
573 assert.expect(2);
574
575 const prefixed = sinon.spy();
576 const unprefixed = sinon.spy();
577
578 this.player.ads.stitchedAds(true);
579
580 // play a midroll
581 this.player.trigger('play');
582 this.player.trigger('loadstart');
583 this.player.trigger('adsready');
584 this.player.trigger('adtimeout');
585 this.player.trigger('playing');
586 this.player.ads.startLinearAdMode();
587
588 // simulate video events that should be prefixed
589 this.player.on(['loadstart', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
590 this.player.on(['adloadstart', 'adplaying', 'adpause', 'adended', 'adfirstplay', 'adloadedalldata'], prefixed);
591 this.player.trigger('firstplay');
592 this.player.trigger('loadstart');
593 this.player.trigger('playing');
594 this.player.trigger('loadedalldata');
595 this.player.trigger('pause');
596 this.player.trigger('ended');
597 assert.strictEqual(unprefixed.callCount, 0, 'no unprefixed events fired');
598 assert.strictEqual(prefixed.callCount, 6, 'prefixed events fired');
599});
600
601QUnit.test('player events during content playback are not prefixed', function(assert) {
602 assert.expect(3);
603
604 const prefixed = sinon.spy();
605 const unprefixed = sinon.spy();
606
607 // play content
608 this.player.trigger('loadstart');
609 this.player.trigger('play');
610 this.player.trigger('adsready');
611 this.player.trigger('adtimeout');
612 this.player.trigger('playing');
613 this.player.trigger('loadedalldata');
614
615 // simulate video events that should not be prefixed
616 this.player.on(['seeked', 'playing', 'pause', 'ended', 'firstplay', 'loadedalldata'], unprefixed);
617 this.player.on(['adseeked', 'adplaying', 'adpause', 'adended', 'contentended', 'adfirstplay', 'adloadedalldata'], prefixed);
618 this.player.trigger('firstplay');
619 this.player.trigger('seeked');
620 this.player.trigger('playing');
621 this.player.trigger('loadedalldata');
622 this.player.trigger('pause');
623 this.player.trigger('ended');
624 assert.strictEqual(unprefixed.callCount, 5, 'unprefixed events fired');
625 assert.strictEqual(prefixed.callCount, 1, 'prefixed events fired');
626 assert.strictEqual(prefixed.getCall(0).args[0].type, 'contentended', 'prefixed the ended event');
627});
628
629QUnit.test('startLinearAdMode should only trigger adstart from correct states', function(assert) {
630
631 const adstart = sinon.spy();
632
633 this.player.on('adstart', adstart);
634
635 this.player.ads.startLinearAdMode();
636 assert.strictEqual(adstart.callCount, 0, 'Before play');
637
638 this.player.trigger('play');
639
640 this.player.ads.startLinearAdMode();
641 assert.strictEqual(adstart.callCount, 0, 'Before adsready');
642
643 this.player.trigger('adsready');
644 this.player.ads.startLinearAdMode();
645 assert.strictEqual(adstart.callCount, 1, 'Preroll');
646
647 this.player.ads.startLinearAdMode();
648 assert.strictEqual(adstart.callCount, 1, 'During preroll playback');
649
650 this.player.ads.endLinearAdMode();
651 this.player.trigger('playing');
652
653 this.player.ads.startLinearAdMode();
654 assert.strictEqual(adstart.callCount, 2, 'Midroll');
655
656 this.player.ads.startLinearAdMode();
657 assert.strictEqual(adstart.callCount, 2, 'During midroll playback');
658
659 this.player.ads.endLinearAdMode();
660 this.player.trigger('playing');
661
662 this.player.trigger('ended');
663 this.player.ads.startLinearAdMode();
664 assert.strictEqual(adstart.callCount, 3, 'Postroll');
665
666 this.player.ads.startLinearAdMode();
667 assert.strictEqual(adstart.callCount, 3, 'During postroll playback');
668
669 this.player.ads.endLinearAdMode();
670 assert.strictEqual(adstart.callCount, 3, 'Ads done');
671
672});
673
674QUnit.test('ad impl can notify contrib-ads there is no preroll', function(assert) {
675 this.player.trigger('loadstart');
676 this.player.trigger('nopreroll');
677 this.player.trigger('play');
678 this.player.trigger('adsready');
679
680 assert.strictEqual(this.player.ads.isInAdMode(), true, 'in ad mode');
681 assert.strictEqual(this.player.ads.isContentResuming(), true, 'content is resuming');
682});
683
684// Same test as above with different event order because this used to be broken.
685QUnit.test('ad impl can notify contrib-ads there is no preroll 2', function(assert) {
686 this.player.trigger('loadstart');
687 this.player.trigger('nopreroll');
688 this.player.trigger('adsready');
689 this.player.trigger('play');
690
691 assert.strictEqual(this.player.ads.isInAdMode(), true, 'not in ad mode');
692 assert.strictEqual(this.player.ads.isContentResuming(), true, 'content is resuming');
693});
694
695QUnit.test('ad impl can notify contrib-ads there is no preroll 3', function(assert) {
696 this.player.trigger('loadstart');
697 this.player.trigger('play');
698 this.player.trigger('nopreroll');
699 this.player.trigger('adsready');
700
701 assert.strictEqual(this.player.ads.isInAdMode(), true, 'not in ad mode');
702 assert.strictEqual(this.player.ads.isContentResuming(), true, 'content is resuming');
703});
704
705QUnit.test('ad impl can notify contrib-ads there is no preroll 4', function(assert) {
706 this.player.trigger('loadstart');
707 this.player.trigger('adsready');
708 this.player.trigger('nopreroll');
709 this.player.trigger('play');
710
711 assert.strictEqual(this.player.ads.isInAdMode(), true, 'not in ad mode');
712 assert.strictEqual(this.player.ads.isContentResuming(), true, 'content is resuming');
713});
714
715QUnit.test('ended event is sent after nopostroll', function(assert) {
716
717 const ended = sinon.spy();
718
719 this.player.on('ended', ended);
720
721 this.player.trigger('loadstart');
722 this.player.trigger('nopostroll');
723 this.player.trigger('play');
724 this.player.trigger('adsready');
725 this.player.ads.skipLinearAdMode();
726 this.player.trigger('playing');
727 this.player.trigger('readyforpostroll');
728 this.clock.tick(1);
729 assert.ok(ended.calledOnce, 'Ended triggered');
730
731});
732
733QUnit.test('ended event is sent with postroll', function(assert) {
734
735 this.player.trigger('loadstart');
736 this.player.trigger('adsready');
737 this.player.trigger('play');
738 this.player.ads.skipLinearAdMode();
739 this.player.trigger('playing');
740
741 const ended = sinon.spy();
742
743 this.player.on('ended', ended);
744
745 this.player.trigger('readyforpostroll');
746
747 this.clock.tick(10000);
748 assert.ok(ended.calledOnce, 'Ended triggered');
749
750});
751
752QUnit.test('isLive', function(assert) {
753
754 // Make videojs.browser writeable
755 videojs.browser = Object.assign({}, videojs.browser);
756
757 this.player.duration = function() {
758 return 0;
759 };
760 videojs.browser.IOS_VERSION = '8';
761 assert.strictEqual(this.player.ads.isLive(this.player), true);
762
763 this.player.duration = function() {
764 return 5;
765 };
766 videojs.browser.IOS_VERSION = '8';
767 assert.strictEqual(this.player.ads.isLive(this.player), false);
768
769 this.player.duration = function() {
770 return Infinity;
771 };
772 videojs.browser.IOS_VERSION = '8';
773 assert.strictEqual(this.player.ads.isLive(this.player), true);
774
775 this.player.duration = function() {
776 return 0;
777 };
778 videojs.browser.IOS_VERSION = undefined;
779 assert.strictEqual(this.player.ads.isLive(this.player), false);
780
781 this.player.duration = function() {
782 return 5;
783 };
784 videojs.browser.IOS_VERSION = undefined;
785 assert.strictEqual(this.player.ads.isLive(this.player), false);
786
787 this.player.duration = function() {
788 return Infinity;
789 };
790 videojs.browser.IOS_VERSION = undefined;
791 assert.strictEqual(this.player.ads.isLive(this.player), true);
792
793});
794
795QUnit.test('shouldPlayContentBehindAd', function(assert) {
796
797 // Make videojs.browser writeable
798 videojs.browser = Object.assign({}, videojs.browser);
799
800 this.player.duration = function() {
801 return Infinity;
802 };
803 videojs.browser.IS_IOS = true;
804 videojs.browser.IS_ANDROID = true;
805 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
806
807 this.player.duration = function() {
808 return Infinity;
809 };
810 videojs.browser.IS_IOS = true;
811 videojs.browser.IS_ANDROID = false;
812 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
813
814 this.player.duration = function() {
815 return Infinity;
816 };
817 videojs.browser.IS_IOS = false;
818 videojs.browser.IS_ANDROID = true;
819 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
820
821 this.player.duration = function() {
822 return Infinity;
823 };
824 videojs.browser.IS_IOS = false;
825 videojs.browser.IS_ANDROID = false;
826 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), true);
827
828 this.player.duration = function() {
829 return 5;
830 };
831 videojs.browser.IS_IOS = true;
832 videojs.browser.IS_ANDROID = true;
833 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
834
835 this.player.duration = function() {
836 return 5;
837 };
838 videojs.browser.IS_IOS = true;
839 videojs.browser.IS_ANDROID = false;
840 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
841
842 this.player.duration = function() {
843 return 5;
844 };
845 videojs.browser.IS_IOS = false;
846 videojs.browser.IS_ANDROID = true;
847 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
848
849 this.player.duration = function() {
850 return 5;
851 };
852 videojs.browser.IS_IOS = false;
853 videojs.browser.IS_ANDROID = false;
854 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
855
856 this.player.duration = function() {
857 return Infinity;
858 };
859 videojs.browser.IS_IOS = false;
860 videojs.browser.IS_ANDROID = false;
861 try {
862 this.player.ads.shouldPlayContentBehindAd();
863 } catch (error) {
864 assert.strictEqual(
865 error.message,
866 'shouldPlayContentBehindAd requires a player as a param'
867 );
868 }
869
870 this.player.duration = function() {
871 return Infinity;
872 };
873 videojs.browser.IS_IOS = false;
874 videojs.browser.IS_ANDROID = false;
875 this.player.ads.settings.liveCuePoints = false;
876 assert.strictEqual(this.player.ads.shouldPlayContentBehindAd(this.player), false);
877});
878
879QUnit.test('Check incorrect addition of vjs-live during ad-playback', function(assert) {
880 this.player.trigger('play');
881 this.player.ads.startLinearAdMode();
882 assert.strictEqual(this.player.hasClass('vjs-live'), false, 'We have the correct class');
883
884});
885
886QUnit.test(
887 'Check for existence of vjs-live after ad-end for LIVE videos',
888 function(assert) {
889 this.player.trigger('loadstart');
890 this.player.trigger('adsready');
891 this.player.trigger('play');
892 this.player.ads.startLinearAdMode();
893 this.player.duration = function() {
894 return Infinity;
895 };
896 this.player.ads.endLinearAdMode();
897 this.player.trigger('playing');
898 assert.strictEqual(this.player.ads.isLive(this.player), true, 'Content is LIVE');
899 assert.ok(this.player.hasClass('vjs-live'), 'We should be having vjs-live class here');
900 }
901);
902
903QUnit.test('Plugin state resets after contentchanged', function(assert) {
904
905 assert.equal(this.player.ads.disableNextSnapshotRestore, false);
906 assert.equal(this.player.ads._contentHasEnded, false);
907 assert.equal(this.player.ads.snapshot, null);
908 assert.equal(this.player.ads.snapshot, null);
909 assert.equal(this.player.ads.nopreroll_, null);
910 assert.equal(this.player.ads.nopostroll_, null);
911
912 this.player.ads.disableNextSnapshotRestore = true;
913 this.player.ads._contentHasEnded = true;
914 this.player.ads.snapshot = {};
915 this.player.ads.nopreroll_ = true;
916 this.player.ads.nopostroll_ = true;
917
918 this.player.trigger('contentchanged');
919
920 assert.equal(this.player.ads.disableNextSnapshotRestore, false);
921 assert.equal(this.player.ads._contentHasEnded, false);
922 assert.equal(this.player.ads.snapshot, null);
923 assert.equal(this.player.ads.nopreroll_, false);
924 assert.equal(this.player.ads.nopostroll_, false);
925
926});
927
928QUnit.test('Plugin sets adType as expected', function(assert) {
929
930 // adType is unset originally
931 assert.strictEqual(this.player.ads.adType, null);
932
933 // before preroll
934 this.player.trigger('loadstart');
935 this.player.trigger('adsready');
936 assert.strictEqual(this.player.ads.adType, null);
937 this.player.trigger('play');
938 assert.strictEqual(this.player.ads.adType, null);
939
940 // preroll starts and finishes
941 this.player.ads.startLinearAdMode();
942 assert.strictEqual(this.player.ads.adType, 'preroll');
943 this.player.ads.endLinearAdMode();
944 assert.strictEqual(this.player.ads.adType, null);
945
946 // content is playing, midroll starts
947 this.player.trigger('playing');
948 this.player.ads.startLinearAdMode();
949 assert.strictEqual(this.player.ads.adType, 'midroll');
950
951 // midroll ends, content is playing
952 this.player.ads.endLinearAdMode();
953 assert.strictEqual(this.player.ads.adType, null);
954 this.player.trigger('playing');
955
956 // postroll starts
957 this.player.trigger('readyforpostroll');
958 this.player.ads.startLinearAdMode();
959 assert.strictEqual(this.player.ads.adType, 'postroll');
960
961 // postroll ends
962 this.player.ads.endLinearAdMode();
963 assert.strictEqual(this.player.ads.adType, null);
964
965 // reset values
966 this.player.trigger('contentchanged');
967 assert.strictEqual(this.player.ads.adType, null);
968
969 // check preroll case where play is observed
970 this.player.trigger('play');
971 assert.strictEqual(this.player.ads.adType, null);
972 this.player.trigger('adsready');
973 assert.strictEqual(this.player.ads.adType, null);
974 this.player.ads.startLinearAdMode();
975 assert.strictEqual(this.player.ads.adType, 'preroll');
976});
977
978if (videojs.browser.IS_IOS) {
979 QUnit.test('Check the textTrackChangeHandler takes effect on iOS', function(assert) {
980 const tracks = this.player.textTracks();
981
982 // Since addTextTrack is async, wait for the addtrack event
983 tracks.on('addtrack', function() {
984
985 // Confirm the track is added, set the mode to showing
986 assert.equal(tracks.length, 1);
987 tracks[0].mode = 'showing';
988 assert.equal(tracks[0].mode, 'showing', 'Initial state is showing');
989
990 // Start the ad, confirm the track is disabled
991 this.player.ads.startLinearAdMode();
992 assert.equal(tracks[0].mode, 'disabled', 'Snapshot sets tracks to disabled');
993
994 // Force the mode to showing
995 tracks[0].mode = 'showing';
996
997 }.bind(this));
998
999 // The mode should go back to disabled when the change event happens as
1000 // during ad playback we do not want the content captions to be visible on iOS
1001 tracks.on('change', function() {
1002 assert.equal(tracks[0].mode, 'disabled', 'Mode is reset to disabled');
1003
1004 // End the ad, check the track mode is showing again
1005 this.player.ads.endLinearAdMode();
1006 assert.equal(tracks[0].mode, 'showing', 'Mode is restored after ad');
1007 }.bind(this));
1008
1009 this.player.trigger('play');
1010 this.player.trigger('adsready');
1011 this.player.addTextTrack('captions', 'English', 'en');
1012 });
1013}