You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.9 KiB
239 lines
6.9 KiB
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');
|
|
});
|