UNPKG

7.04 kBJavaScriptView Raw
1import QUnit from 'qunit';
2import videojs from 'video.js';
3import sinon from 'sinon';
4import reloadSourceOnError from '../src/reload-source-on-error';
5
6QUnit.module('ReloadSourceOnError', {
7 beforeEach() {
8 this.clock = sinon.useFakeTimers();
9
10 // setup a player
11 this.player = new videojs.EventTarget();
12 this.player.currentValues = {
13 currentTime: 10,
14 duration: 12
15 };
16
17 this.player.ready = (callback) => {
18 callback.call(this.player);
19 };
20
21 this.tech = {
22 currentSource_: {
23 src: 'thisisasource.m3u8',
24 type: 'doesn\'t/matter'
25 }
26 };
27
28 this.player.tech = () => {
29 return this.tech;
30 };
31
32 this.player.duration = () => {
33 return this.player.currentValues.duration;
34 };
35
36 this.player.src = (source) => {
37 this.player.currentValues.currentTime = 0;
38 this.player.src.calledWith.push(source);
39 };
40 this.player.src.calledWith = [];
41
42 this.player.currentTime = (time) => {
43 if (time) {
44 this.player.currentTime.calledWith.push(time);
45 this.player.currentValues.currentTime = time;
46 }
47 return this.player.currentValues.currentTime;
48 };
49 this.player.currentTime.calledWith = [];
50
51 this.player.play = () => {
52 this.player.play.called++;
53 };
54 this.player.play.called = 0;
55
56 this.player.reloadSourceOnError = reloadSourceOnError;
57 this.clock.tick(60 * 1000);
58
59 this.oldLog = videojs.log.error;
60 this.errors = [];
61
62 videojs.log.error = (...args) => {
63 this.errors.push(...args);
64 };
65 },
66
67 afterEach() {
68 this.clock.restore();
69 videojs.log.error = this.oldLog;
70 }
71});
72
73QUnit.test('triggers on player error', function(assert) {
74 this.player.reloadSourceOnError();
75 this.player.trigger('error', -2);
76
77 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
78 assert.deepEqual(this.player.src.calledWith[0],
79 this.tech.currentSource_,
80 'player.src was called with player.currentSource');
81});
82
83QUnit.test('seeks to currentTime in VOD', function(assert) {
84 this.player.reloadSourceOnError();
85 this.player.trigger('error', -2);
86 this.player.trigger('loadedmetadata');
87
88 assert.equal(this.player.currentTime.calledWith.length,
89 1,
90 'player.currentTime was only called once');
91 assert.deepEqual(this.player.currentTime.calledWith[0],
92 10,
93 'player.currentTime was called with the right value');
94});
95
96QUnit.test('doesn\'t seek to currentTime in live', function(assert) {
97 this.player.reloadSourceOnError();
98 this.player.currentValues.duration = Infinity;
99
100 this.player.trigger('error', -2);
101 this.player.trigger('loadedmetadata');
102
103 assert.equal(this.player.currentTime.calledWith.length,
104 0,
105 'player.currentTime was not called');
106 assert.deepEqual(this.player.currentTime(), 0, 'player.currentTime is still zero');
107});
108
109QUnit.test('by default, only allows a retry once every 30 seconds', function(assert) {
110 let hlsErrorReloadInitializedEvents = 0;
111 let hlsErrorReloadEvents = 0;
112 let hlsErrorReloadCanceledEvents = 0;
113
114 this.player.on('usage', (event) => {
115 if (event.name === 'hls-error-reload-initialized') {
116 hlsErrorReloadInitializedEvents++;
117 }
118 });
119
120 this.player.on('usage', (event) => {
121 if (event.name === 'hls-error-reload') {
122 hlsErrorReloadEvents++;
123 }
124 });
125
126 this.player.on('usage', (event) => {
127 if (event.name === 'hls-error-reload-canceled') {
128 hlsErrorReloadCanceledEvents++;
129 }
130 });
131
132 assert.equal(hlsErrorReloadInitializedEvents, 0, 'the plugin has not been initialized');
133 assert.equal(hlsErrorReloadEvents, 0, 'no source was set');
134 assert.equal(hlsErrorReloadCanceledEvents, 0,
135 'reload canceled event has not been triggered');
136
137 this.player.reloadSourceOnError();
138 this.player.trigger('error', -2);
139 this.player.trigger('loadedmetadata');
140
141 assert.equal(hlsErrorReloadInitializedEvents, 1, 'the plugin has been initialized');
142 assert.equal(hlsErrorReloadEvents, 1, 'src was set after an error caused the reload');
143 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
144
145 // Advance 59 seconds
146 this.clock.tick(59 * 1000);
147 this.player.trigger('error', -2);
148 this.player.trigger('loadedmetadata');
149
150 assert.equal(this.player.src.calledWith.length, 2, 'player.src was called twice');
151
152 // Advance 29 seconds
153 this.clock.tick(29 * 1000);
154 this.player.trigger('error', -2);
155 this.player.trigger('loadedmetadata');
156
157 assert.equal(hlsErrorReloadCanceledEvents, 1,
158 'did not reload the source because not enough time has elapsed');
159 assert.equal(this.player.src.calledWith.length, 2, 'player.src was called twice');
160});
161
162QUnit.test('allows you to override the default retry interval', function(assert) {
163 this.player.reloadSourceOnError({
164 errorInterval: 60
165 });
166
167 this.player.trigger('error', -2);
168 this.player.trigger('loadedmetadata');
169
170 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
171
172 // Advance 59 seconds
173 this.clock.tick(59 * 1000);
174 this.player.trigger('error', -2);
175 this.player.trigger('loadedmetadata');
176
177 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
178});
179
180QUnit.test('the plugin cleans up after it\'s previous incarnation when called again',
181function(assert) {
182 this.player.reloadSourceOnError();
183 this.player.reloadSourceOnError();
184
185 this.player.trigger('error', -2);
186
187 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
188});
189
190QUnit.test('allows you to provide a getSource function', function(assert) {
191 const newSource = {
192 src: 'newsource.m3u8',
193 type: 'this/matters'
194 };
195
196 this.player.reloadSourceOnError({
197 getSource: (next) => {
198 return next(newSource);
199 }
200 });
201
202 this.player.trigger('error', -2);
203
204 assert.equal(this.player.src.calledWith.length, 1, 'player.src was only called once');
205 assert.deepEqual(this.player.src.calledWith[0],
206 newSource,
207 'player.src was called with return value of options.getSource()');
208});
209
210QUnit.test('errors if getSource is not a function', function(assert) {
211 this.player.reloadSourceOnError({
212 getSource: 'totally not a function'
213 });
214
215 this.player.trigger('error', -2);
216
217 assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
218 assert.equal(this.errors.length, 1, 'videojs.log.error was called once');
219});
220
221QUnit.test('should not set source if getSource returns null or undefined',
222function(assert) {
223 this.player.reloadSourceOnError({
224 getSource: () => undefined
225 });
226
227 this.player.trigger('error', -2);
228
229 assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
230
231 this.player.reloadSourceOnError({
232 getSource: () => null
233 });
234
235 this.player.trigger('error', -2);
236
237 assert.equal(this.player.src.calledWith.length, 0, 'player.src was never called');
238});