123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- import QUnit from 'qunit';
- import videojs from 'video.js';
- import sinon from 'sinon';
- import reloadSourceOnError from '../src/reload-source-on-error';
- QUnit.module('ReloadSourceOnError', {
- beforeEach() {
- this.clock = sinon.useFakeTimers();
- // setup a player
- this.player = new videojs.EventTarget();
- this.player.currentValues = {
- currentTime: 10,
- duration: 12
- };
- this.player.ready = (callback) => {
- callback.call(this.player);
- };
- this.tech = {
- currentSource_: {
- src: 'thisisasource.m3u8',
- type: 'doesn\'t/matter'
- }
- };
- this.player.tech = () => {
- return this.tech;
- };
- this.player.duration = () => {
- return this.player.currentValues.duration;
- };
- this.player.src = (source) => {
- this.player.currentValues.currentTime = 0;
- this.player.src.calledWith.push(source);
- };
- this.player.src.calledWith = [];
- this.player.currentTime = (time) => {
- if (time) {
- this.player.currentTime.calledWith.push(time);
- this.player.currentValues.currentTime = time;
- }
- return this.player.currentValues.currentTime;
- };
- this.player.currentTime.calledWith = [];
- this.player.play = () => {
- this.player.play.called++;
- };
- this.player.play.called = 0;
- this.player.reloadSourceOnError = reloadSourceOnError;
- this.clock.tick(60 * 1000);
- this.oldLog = videojs.log.error;
- this.errors = [];
- videojs.log.error = (...args) => {
- this.errors.push(...args);
- };
- },
- afterEach() {
- this.clock.restore();
- videojs.log.error = this.oldLog;
- }
- });
- QUnit.test('triggers on player error', function(assert) {
- this.player.reloadSourceOnError();
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- assert.deepEqual(this.player.src.calledWith[0],
- this.tech.currentSource_,
- 'player.src was called with player.currentSource');
- });
- QUnit.test('seeks to currentTime in VOD', function(assert) {
- this.player.reloadSourceOnError();
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(this.player.currentTime.calledWith.length,
- 1,
- 'player.currentTime was only called once');
- assert.deepEqual(this.player.currentTime.calledWith[0],
- 10,
- 'player.currentTime was called with the right value');
- });
- QUnit.test('doesn\'t seek to currentTime in live', function(assert) {
- this.player.reloadSourceOnError();
- this.player.currentValues.duration = Infinity;
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(this.player.currentTime.calledWith.length,
- 0,
- 'player.currentTime was not called');
- assert.deepEqual(this.player.currentTime(), 0, 'player.currentTime is still zero');
- });
- QUnit.test('by default, only allows a retry once every 30 seconds', function(assert) {
- let hlsErrorReloadInitializedEvents = 0;
- let hlsErrorReloadEvents = 0;
- let hlsErrorReloadCanceledEvents = 0;
- this.player.on('usage', (event) => {
- if (event.name === 'hls-error-reload-initialized') {
- hlsErrorReloadInitializedEvents++;
- }
- });
- this.player.on('usage', (event) => {
- if (event.name === 'hls-error-reload') {
- hlsErrorReloadEvents++;
- }
- });
- this.player.on('usage', (event) => {
- if (event.name === 'hls-error-reload-canceled') {
- hlsErrorReloadCanceledEvents++;
- }
- });
- assert.equal(hlsErrorReloadInitializedEvents, 0, 'the plugin has not been initialized');
- assert.equal(hlsErrorReloadEvents, 0, 'no source was set');
- assert.equal(hlsErrorReloadCanceledEvents, 0,
- 'reload canceled event has not been triggered');
- this.player.reloadSourceOnError();
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(hlsErrorReloadInitializedEvents, 1, 'the plugin has been initialized');
- assert.equal(hlsErrorReloadEvents, 1, 'src was set after an error caused the reload');
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- // Advance 59 seconds
- this.clock.tick(59 * 1000);
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(this.player.src.calledWith.length, 2, 'player.src was called twice');
- // Advance 29 seconds
- this.clock.tick(29 * 1000);
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(hlsErrorReloadCanceledEvents, 1,
- 'did not reload the source because not enough time has elapsed');
- assert.equal(this.player.src.calledWith.length, 2, 'player.src was called twice');
- });
- QUnit.test('allows you to override the default retry interval', function(assert) {
- this.player.reloadSourceOnError({
- errorInterval: 60
- });
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- // Advance 59 seconds
- this.clock.tick(59 * 1000);
- this.player.trigger('error', -2);
- this.player.trigger('loadedmetadata');
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- });
- QUnit.test('the plugin cleans up after it\'s previous incarnation when called again',
- function(assert) {
- this.player.reloadSourceOnError();
- this.player.reloadSourceOnError();
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- });
- QUnit.test('allows you to provide a getSource function', function(assert) {
- const newSource = {
- src: 'newsource.m3u8',
- type: 'this/matters'
- };
- this.player.reloadSourceOnError({
- getSource: (next) => {
- return next(newSource);
- }
- });
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
- assert.deepEqual(this.player.src.calledWith[0],
- newSource,
- 'player.src was called with return value of options.getSource()');
- });
- QUnit.test('errors if getSource is not a function', function(assert) {
- this.player.reloadSourceOnError({
- getSource: 'totally not a function'
- });
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
- assert.equal(this.errors.length, 1, 'videojs.log.error was called once');
- });
- QUnit.test('should not set source if getSource returns null or undefined',
- function(assert) {
- this.player.reloadSourceOnError({
- getSource: () => undefined
- });
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
- this.player.reloadSourceOnError({
- getSource: () => null
- });
- this.player.trigger('error', -2);
- assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
- });
|