1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-04 18:29:39 +02:00
Oinktube/node_modules/videojs-contrib-ads/test/integration/test.snapshot.js
Daniel Neto 59a20745e7 Update
2024-02-08 10:08:03 -03:00

590 lines
19 KiB
JavaScript

import videojs from 'video.js';
import * as snapshot from '../../src/snapshot.js';
import QUnit from 'qunit';
import document from 'global/document';
import window from 'global/window';
import sinon from 'sinon';
import sharedModuleHooks from './lib/shared-module-hooks.js';
QUnit.module('Video Snapshot', sharedModuleHooks({
beforeEach() {
const captionTrack = document.createElement('track');
const otherTrack = document.createElement('track');
captionTrack.setAttribute('kind', 'captions');
captionTrack.setAttribute('src', '/test/integration/lib/testcaption.vtt');
otherTrack.setAttribute('src', '/test/integration/lib/testcaption.vtt');
this.video.appendChild(captionTrack);
this.video.appendChild(otherTrack);
this.player.ended = function() {
return false;
};
}
}));
QUnit.test('restores the original video src after ads', function(assert) {
const originalSrc = {
src: 'http://vjs.zencdn.net/v/oceans.webm',
type: 'video/webm'
};
this.player.src(originalSrc);
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.src({
src: '//example.com/ad.webm',
type: 'video/webm'
});
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.currentSrc(), originalSrc.src, 'the original src is restored');
});
QUnit.test('waits for the video to become seekable before restoring the time', function(assert) {
assert.expect(2);
this.player.trigger('adsready');
this.player.trigger('play');
// the video plays to time 100
const setTimeoutSpy = sinon.spy(window, 'setTimeout');
this.video.currentTime = 100;
this.player.ads.startLinearAdMode();
this.player.src({
src: '//example.com/ad.webm',
type: 'video/webm'
});
// the ad resets the current time
this.video.currentTime = 0;
this.player.ads.endLinearAdMode();
// we call setTimeout an extra time restorePlayerSnapshot
setTimeoutSpy.reset();
this.player.trigger('canplay');
assert.strictEqual(setTimeoutSpy.callCount, 1, 'restoring the time should be delayed');
assert.strictEqual(this.video.currentTime, 0, 'currentTime is not modified');
window.setTimeout.restore();
});
QUnit.test('the current time is restored at the end of an ad', function(assert) {
assert.expect(1);
this.player.trigger('adsready');
this.video.currentTime = 100;
this.player.trigger('play');
// the video plays to time 100
this.player.ads.startLinearAdMode();
this.player.src({
src: '//example.com/ad.webm',
type: 'video/webm'
});
// the ad resets the current time
this.video.currentTime = 0;
this.player.ads.endLinearAdMode();
this.player.trigger('canplay');
this.clock.tick(1000);
assert.strictEqual(this.video.currentTime, 100, 'currentTime was restored');
});
QUnit.test('only restores the player snapshot if the src changed', function(assert) {
this.player.trigger('adsready');
this.player.trigger('play');
const playSpy = sinon.spy(this.player, 'play');
const srcSpy = sinon.spy(this.player, 'src');
const currentTimeSpy = sinon.spy(this.player, 'currentTime');
// with a separate video display or server-side ad insertion, ads play but
// the src never changes. Modifying the src or currentTime would introduce
// unnecessary seeking and rebuffering
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
assert.ok(playSpy.called, 'content playback resumed');
assert.ok(srcSpy.alwaysCalledWithExactly(), 'the src was not reset');
this.player.trigger('playing');
// the src wasn't changed, so we shouldn't be waiting on loadedmetadata to
// update the currentTime
this.player.trigger('loadedmetadata');
assert.ok(currentTimeSpy.alwaysCalledWithExactly(), 'no seeking occurred');
});
QUnit.test('snapshot does not resume playback after post-rolls', function(assert) {
const playSpy = sinon.spy(this.player, 'play');
// start playback
this.player.src({
src: 'http://vjs.zencdn.net/v/oceans.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('loadedmetadata');
this.player.trigger('adsready');
this.player.tech_.trigger('play');
// trigger an ad
this.player.ads.startLinearAdMode();
this.player.src({
src: '//example.com/ad.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('loadedmetadata');
this.player.ads.endLinearAdMode();
// resume playback
this.player.src({
src: 'http://vjs.zencdn.net/v/oceans.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('canplay');
// "canplay" causes the `restorePlayerSnapshot` function in the plugin
// to be called. This causes content playback to be resumed after 20
// attempts of a 50ms timeout (20 * 50 == 1000).
this.clock.tick(1000);
assert.strictEqual(playSpy.callCount, 1, 'content playback resumed');
this.player.trigger('playing');
// if the video ends (regardless of burned in post-roll or otherwise) when
// stopLinearAdMode fires next we should not hit play() since we have reached
// the end of the stream
this.player.ended = function() {
return true;
};
this.player.trigger('ended');
playSpy.reset();
// trigger a post-roll
this.player.ads.startLinearAdMode();
this.player.src({
src: '//example.com/ad.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('loadedmetadata');
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
this.player.trigger('ended');
assert.strictEqual(playSpy.callCount, 0, 'content playback should not have been resumed');
});
QUnit.test('snapshot does not resume playback after a burned-in post-roll', function(assert) {
this.player.trigger('adsready');
this.player.trigger('play');
const playSpy = sinon.spy(this.player, 'play');
const loadSpy = sinon.spy(this.player, 'load');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
assert.ok(playSpy.called, 'content playback resumed');
// if the video ends (regardless of burned in post-roll or otherwise) when
// stopLinearAdMode fires next we should not hit play() since we have reached
// the end of the stream
this.player.ended = function() {
return true;
};
this.player.trigger('ended');
playSpy.reset();
// trigger a post-roll
this.player.currentTime(30);
this.player.ads.startLinearAdMode();
this.player.currentTime(50);
this.player.ads.endLinearAdMode();
this.player.trigger('ended');
assert.strictEqual(this.player.currentTime(), 50, 'currentTime should not be reset using burned in ads');
assert.notOk(loadSpy.called, 'player.load() should not be called if the player is ended.');
assert.notOk(playSpy.called, 'content playback should not have been resumed');
});
QUnit.test('snapshot does not resume playback after multiple post-rolls', function(assert) {
this.player.src({
src: 'http://vjs.zencdn.net/v/oceans.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('adsready');
this.player.trigger('play');
const playSpy = sinon.spy(this.player, 'play');
// with a separate video display or server-side ad insertion, ads play but
// the src never changes. Modifying the src or currentTime would introduce
// unnecessary seeking and rebuffering
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
assert.ok(playSpy.called, 'content playback resumed');
// if the video ends (regardless of burned in post-roll or otherwise) when
// stopLinearAdMode fires next we should not hit play() since we have reached
// the end of the stream
this.player.ended = function() {
return true;
};
this.player.trigger('ended');
playSpy.reset();
// trigger a lot of post-rolls
this.player.ads.startLinearAdMode();
this.player.src({
src: 'http://example.com/ad1.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.src({
src: 'http://example.com/ad2.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
this.player.trigger('ended');
assert.notOk(playSpy.called, 'content playback should not resume');
});
QUnit.test('changing the source and then timing out does not restore a snapshot', function(assert) {
this.player.paused = function() {
return false;
};
// load and play the initial video
this.player.src({
src: 'http://example.com/movie.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('play');
this.player.trigger('adsready');
// preroll
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
// change the content and timeout the new ad response
this.player.src({
src: 'http://example.com/movie2.webm',
type: 'video/webm'
});
this.player.trigger('loadstart');
this.player.trigger('adtimeout');
assert.strictEqual('http://example.com/movie2.webm', this.player.currentSrc(), 'playing the second video');
});
// changing the src attribute to a URL that AdBlocker is intercepting
// doesn't update currentSrc, so when restoring the snapshot we
// should check for src attribute modifications as well
QUnit.test('checks for a src attribute change that isn\'t reflected in currentSrc', function(assert) {
let updatedSrc;
const srcObj = {src: 'content.webm', type: 'video/webm'};
this.player.currentSource = function() {
return srcObj;
};
this.player.currentSources = function() {
return [srcObj];
};
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
// `src` gets called internally to set the source back to its original
// value when the player snapshot is restored when `endLinearAdMode`
// is called.
this.player.tech_.src = function(source) {
if (source === undefined) {
return 'ad.webm';
}
updatedSrc = source;
};
this.player.src = function(source) {
if (source === undefined) {
return 'ad.webm';
}
updatedSrc = source;
};
this.player.ads.endLinearAdMode();
this.player.trigger('playing');
assert.deepEqual(updatedSrc, [this.player.currentSource()], 'restored src attribute');
});
QUnit.test('When captions are enabled, the content\'s tracks will be disabled during the ad', function(assert) {
const trackSrc = '/test/integration/lib/testcaption.vtt';
// Add a text track
const remoteTrack = this.player.addRemoteTextTrack({
kind: 'captions',
language: 'fr',
label: 'French',
src: trackSrc
});
const tracks = this.player.textTracks ? this.player.textTracks() : [];
let showing = 0;
let disabled = 0;
let i;
if (tracks.length <= 0) {
assert.expect(0);
videojs.log.warn('Did not detect text track support, skipping');
return;
}
assert.expect(3);
this.player.trigger('adsready');
this.player.trigger('play');
// set all modes to 'showing'
for (i = 0; i < tracks.length; i++) {
tracks[i].mode = 'showing';
}
for (i = 0; i < tracks.length; i++) {
if (tracks[i].mode === 'showing') {
showing++;
}
}
assert.strictEqual(showing, tracks.length, 'all tracks should be showing');
showing = 0;
this.player.ads.startLinearAdMode();
for (i = 0; i < tracks.length; i++) {
if (tracks[i].mode === 'disabled') {
disabled++;
}
}
assert.strictEqual(disabled, tracks.length, 'all tracks should be disabled');
this.player.ads.endLinearAdMode();
// Track mode should be restored after the ad ends
for (i = 0; i < tracks.length; i++) {
if (tracks[i].mode === 'showing') {
showing++;
}
}
assert.strictEqual(showing, tracks.length, 'all tracks should be showing');
// Cleanup
this.player.textTracks().removeTrack(remoteTrack);
});
QUnit.test('No snapshot if duration is Infinity', function(assert) {
const originalSrc = 'foobar';
const newSrc = 'barbaz';
this.player.duration(Infinity);
this.player.src({
src: originalSrc,
type: 'video/webm'
});
this.player.trigger('adsready');
this.player.play();
this.player.ads.startLinearAdMode();
this.player.src({
src: newSrc,
type: 'video/webm'
});
this.player.ads.endLinearAdMode();
assert.strictEqual(this.player.currentSrc(), newSrc, 'source is not reset');
});
QUnit.test('Snapshot and text tracks', function(assert) {
const trackSrc = '/test/integration/lib/testcaption.vtt';
const originalAddTrack = this.player.addTextTrack;
const originalTextTracks = this.player.textTracks;
// No text tracks at start
assert.equal(this.player.textTracks().length, 0);
this.player.addTextTrack('captions', 'Spanish', 'es');
// Add a text track
const remoteTrack = this.player.addRemoteTextTrack({
kind: 'captions',
language: 'fr',
label: 'French',
src: trackSrc
});
// Make sure both track modes are 'showing', since it's 'disabled' by default
this.player.textTracks()[0].mode = 'showing';
this.player.textTracks()[1].mode = 'showing';
// Text track looks good
assert.equal(this.player.textTracks().length, 2);
assert.equal(this.player.textTracks()[0].kind, 'captions');
assert.equal(this.player.textTracks()[0].language, 'es');
assert.equal(this.player.textTracks()[0].mode, 'showing');
assert.equal(this.player.remoteTextTrackEls().trackElements_[0].src, trackSrc);
assert.equal(this.player.textTracks()[1].kind, 'captions');
assert.equal(this.player.textTracks()[1].language, 'fr');
assert.equal(this.player.textTracks()[1].mode, 'showing');
// Do a snapshot, as if an ad is starting
this.player.ads.snapshot = snapshot.getPlayerSnapshot(this.player);
// Snapshot reflects the text track
assert.equal(this.player.ads.snapshot.suppressedTracks.length, 2);
assert.equal(this.player.ads.snapshot.suppressedTracks[0].track.kind, 'captions');
assert.equal(this.player.ads.snapshot.suppressedTracks[0].track.language, 'es');
assert.equal(this.player.ads.snapshot.suppressedTracks[0].mode, 'showing');
assert.equal(this.player.ads.snapshot.suppressedTracks[1].track.kind, 'captions');
assert.equal(this.player.ads.snapshot.suppressedTracks[1].track.language, 'fr');
assert.equal(this.player.ads.snapshot.suppressedTracks[1].mode, 'showing');
// Meanwhile, track is intact, just disabled
assert.equal(this.player.textTracks().length, 2);
assert.equal(this.player.textTracks()[0].kind, 'captions');
assert.equal(this.player.textTracks()[0].language, 'es');
assert.equal(this.player.textTracks()[0].mode, 'disabled');
assert.equal(this.player.remoteTextTrackEls().trackElements_[0].src, trackSrc);
assert.equal(this.player.textTracks()[1].kind, 'captions');
assert.equal(this.player.textTracks()[1].language, 'fr');
assert.equal(this.player.textTracks()[1].mode, 'disabled');
// Double check that the track remains disabled after 3s
this.clock.tick(3000);
assert.equal(this.player.textTracks()[0].mode, 'disabled');
assert.equal(this.player.textTracks()[1].mode, 'disabled');
// Restore the snapshot, as if an ad is ending
snapshot.restorePlayerSnapshot(this.player);
// Everything is back to normal
assert.equal(this.player.textTracks().length, 2);
assert.equal(this.player.textTracks()[0].kind, 'captions');
assert.equal(this.player.textTracks()[0].language, 'es');
assert.equal(this.player.textTracks()[0].mode, 'showing');
assert.equal(this.player.remoteTextTrackEls().trackElements_[0].src, trackSrc);
assert.equal(this.player.textTracks()[1].kind, 'captions');
assert.equal(this.player.textTracks()[1].language, 'fr');
assert.equal(this.player.textTracks()[1].mode, 'showing');
// Resetting mocked methods
this.player.textTracks().removeTrack(remoteTrack);
this.player.addTextTrack = originalAddTrack;
this.player.textTracks = originalTextTracks;
});
QUnit.test('Snapshot object is cleaned up', function(assert) {
assert.equal(typeof this.player.ads.snapshot, 'undefined', 'no snapshot before ad');
this.player.ads.snapshot = snapshot.getPlayerSnapshot(this.player);
assert.equal(typeof this.player.ads.snapshot, 'object', 'snapshot during ad');
snapshot.restorePlayerSnapshot(this.player);
assert.equal(typeof this.player.ads.snapshot, 'undefined', 'no snapshot after ad');
});
QUnit.test('Call play after live preroll on iOS', function(assert) {
let played = 0;
this.player.duration(Infinity);
this.player.ads.videoElementRecycled = () => true;
videojs.browser = {IS_IOS: true};
this.player.play = () => {
played++;
};
this.player.trigger('loadstart');
this.player.trigger('adsready');
this.player.trigger('play');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.el().querySelector = query => {
if (query === '.vjs-tech') {
return {seekable: {length: 1}};
}
};
assert.strictEqual(played, 0, 'No play yet');
this.player.trigger('contentcanplay');
assert.strictEqual(played, 1, 'Play happened');
});
QUnit.test('sets autoplay directly on tech when forcing content load for iOS', function(assert) {
this.player.ads.videoElementRecycled = () => true;
videojs.browser = {IS_IOS: true};
this.player.play = () => {};
this.player.trigger('loadstart');
this.player.trigger('adsready');
this.player.trigger('play');
assert.notOk(this.player.tech("it's fine").autoplay(), 'confirm autoplay on tech is off initially');
assert.notOk(this.player.autoplay(), 'confirm autoplay for vjs is off initially');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.el().querySelector = query => {
if (query === '.vjs-tech') {
return {seekable: {length: 1}};
}
};
assert.ok(this.player.tech("it's fine").autoplay(), 'autoplay should be true on tech');
assert.notOk(this.player.autoplay(), 'autoplay should not be true on VJS');
// this will cause resume() to run and reset autoplay status if required
this.player.trigger('contentcanplay');
assert.notOk(this.player.tech("it's fine").autoplay(), 'confirm autoplay on tech is set back to off');
assert.notOk(this.player.autoplay(), 'confirm autoplay for vjs is still off');
});
QUnit.test('doesn\'t interfere with normal autoplay when forcing content load for iOS', function(assert) {
this.player.autoplay(true);
this.player.ads.videoElementRecycled = () => true;
videojs.browser = {IS_IOS: true};
this.player.play = () => {};
this.player.trigger('loadstart');
this.player.trigger('adsready');
this.player.trigger('play');
assert.ok(this.player.tech("it's fine").autoplay(), 'confirm autoplay on tech is on');
assert.ok(this.player.autoplay(), 'confirm autoplay for vjs is on');
this.player.ads.startLinearAdMode();
this.player.ads.endLinearAdMode();
this.player.el().querySelector = query => {
if (query === '.vjs-tech') {
return {seekable: {length: 1}};
}
};
assert.ok(this.player.tech("it's fine").autoplay(), 'autoplay should be true on tech');
assert.ok(this.player.autoplay(), 'autoplay should be true on VJS');
// this will cause resume() to run and reset autoplay status if required
this.player.trigger('contentcanplay');
assert.ok(this.player.tech("it's fine").autoplay(), 'confirm autoplay on tech is stil on');
assert.ok(this.player.autoplay(), 'confirm autoplay for vjs is still on');
});