1 | import Flash from '../src/plugin';
|
2 | import {createTimeRange} from 'video.js';
|
3 | import document from 'global/document';
|
4 | import window from 'global/window';
|
5 | import sinon from 'sinon';
|
6 | import QUnit from 'qunit';
|
7 |
|
8 |
|
9 | class MockFlash extends Flash {
|
10 | constructor() {
|
11 | super({});
|
12 | }
|
13 | }
|
14 |
|
15 | QUnit.module('Flash');
|
16 |
|
17 | QUnit.test('Flash.canPlaySource', function(assert) {
|
18 | const canPlaySource = Flash.canPlaySource;
|
19 |
|
20 |
|
21 | assert.ok(canPlaySource({type: 'video/mp4; codecs=avc1.42E01E,mp4a.40.2' }, {}),
|
22 | 'codecs supported');
|
23 | assert.ok(canPlaySource({type: 'video/mp4' }, {}), 'video/mp4 supported');
|
24 | assert.ok(canPlaySource({type: 'video/x-flv' }, {}), 'video/x-flv supported');
|
25 | assert.ok(canPlaySource({type: 'video/flv' }, {}), 'video/flv supported');
|
26 | assert.ok(canPlaySource({type: 'video/m4v' }, {}), 'video/m4v supported');
|
27 | assert.ok(canPlaySource({type: 'VIDEO/FLV' }, {}), 'capitalized mime type');
|
28 |
|
29 |
|
30 | assert.ok(!canPlaySource({ type: 'video/webm; codecs="vp8, vorbis"' }, {}));
|
31 | assert.ok(!canPlaySource({ type: 'video/webm' }, {}));
|
32 | });
|
33 |
|
34 | QUnit.test('currentTime', function(assert) {
|
35 | const getCurrentTime = Flash.prototype.currentTime;
|
36 | const setCurrentTime = Flash.prototype.setCurrentTime;
|
37 | let seekingCount = 0;
|
38 | let seeking = false;
|
39 | let setPropVal;
|
40 | let getPropVal;
|
41 | let result;
|
42 |
|
43 |
|
44 | const mockFlash = {
|
45 | el_: {
|
46 |
|
47 | vjs_setProperty(prop, val) {
|
48 | setPropVal = val;
|
49 | },
|
50 | vjs_getProperty() {
|
51 | return getPropVal;
|
52 | }
|
53 |
|
54 | },
|
55 | seekable() {
|
56 | return createTimeRange(5, 1000);
|
57 | },
|
58 | trigger(event) {
|
59 | if (event === 'seeking') {
|
60 | seekingCount++;
|
61 | }
|
62 | },
|
63 | seeking() {
|
64 | return seeking;
|
65 | }
|
66 | };
|
67 |
|
68 |
|
69 | getPropVal = 3;
|
70 | result = getCurrentTime.call(mockFlash);
|
71 | assert.equal(result, 3, 'currentTime is retreived from the swf element');
|
72 |
|
73 |
|
74 | setCurrentTime.call(mockFlash, 10);
|
75 | assert.equal(setPropVal, 10, 'currentTime is set on the swf element');
|
76 | assert.equal(seekingCount, 1, 'triggered seeking');
|
77 |
|
78 |
|
79 | setCurrentTime.call(mockFlash, 20);
|
80 | seeking = true;
|
81 | result = getCurrentTime.call(mockFlash);
|
82 | assert.equal(result,
|
83 | 20,
|
84 | 'currentTime is retrieved from the lastSeekTarget while seeking');
|
85 | assert.notEqual(result,
|
86 | getPropVal,
|
87 | 'currentTime is not retrieved from the element while seeking');
|
88 | assert.equal(seekingCount, 2, 'triggered seeking');
|
89 |
|
90 |
|
91 | setCurrentTime.call(mockFlash, 1001);
|
92 | result = getCurrentTime.call(mockFlash);
|
93 | assert.equal(result, mockFlash.seekable().end(0), 'clamped to the seekable end');
|
94 | assert.equal(seekingCount, 3, 'triggered seeking');
|
95 |
|
96 | setCurrentTime.call(mockFlash, 1);
|
97 | result = getCurrentTime.call(mockFlash);
|
98 | assert.equal(result, mockFlash.seekable().start(0), 'clamped to the seekable start');
|
99 | assert.equal(seekingCount, 4, 'triggered seeking');
|
100 | });
|
101 |
|
102 | QUnit.test('dispose removes the object element even before ready fires', function(assert) {
|
103 |
|
104 |
|
105 | const dispose = Flash.prototype.dispose;
|
106 | const mockFlash = new MockFlash();
|
107 | const noop = function() {};
|
108 |
|
109 |
|
110 | mockFlash.off = noop;
|
111 | mockFlash.trigger = noop;
|
112 | mockFlash.el_ = {};
|
113 |
|
114 | dispose.call(mockFlash);
|
115 | assert.strictEqual(mockFlash.el_, null, 'swf el is nulled');
|
116 | });
|
117 |
|
118 | QUnit.test('ready triggering before and after disposing the tech', function(assert) {
|
119 | const checkReady = sinon.stub(Flash, 'checkReady');
|
120 | const fixtureDiv = document.getElementById('qunit-fixture');
|
121 | const playerDiv = document.createElement('div');
|
122 | const techEl = document.createElement('div');
|
123 |
|
124 | techEl.id = 'foo1234';
|
125 | playerDiv.appendChild(techEl);
|
126 | fixtureDiv.appendChild(playerDiv);
|
127 |
|
128 |
|
129 | techEl.tech = {
|
130 | el() {
|
131 | return techEl;
|
132 | }
|
133 | };
|
134 |
|
135 | playerDiv.player = {
|
136 | tech: techEl.tech
|
137 | };
|
138 |
|
139 | Flash.onReady(techEl.id);
|
140 | assert.ok(checkReady.called, 'checkReady should be called before the tech is disposed');
|
141 |
|
142 |
|
143 | playerDiv.removeChild(techEl);
|
144 | Flash.onReady(techEl.id);
|
145 | assert.ok(!checkReady.calledTwice,
|
146 | 'checkReady should not be called after the tech is disposed');
|
147 |
|
148 | Flash.checkReady.restore();
|
149 | });
|
150 |
|
151 | QUnit.test('should have the source handler interface', function(assert) {
|
152 | assert.ok(Flash.registerSourceHandler, 'has the registerSourceHandler function');
|
153 | });
|
154 |
|
155 | QUnit.test('canPlayType should select the correct types to play', function(assert) {
|
156 | const canPlayType = Flash.nativeSourceHandler.canPlayType;
|
157 |
|
158 | assert.equal(canPlayType('video/flv'), 'maybe', 'should be able to play FLV files');
|
159 | assert.equal(canPlayType('video/x-flv'), 'maybe', 'should be able to play x-FLV files');
|
160 | assert.equal(canPlayType('video/mp4'), 'maybe', 'should be able to play MP4 files');
|
161 | assert.equal(canPlayType('video/m4v'), 'maybe', 'should be able to play M4V files');
|
162 | assert.equal(canPlayType('video/ogg'),
|
163 | '',
|
164 | 'should return empty string if it can not play the video');
|
165 | });
|
166 |
|
167 | QUnit.test('canHandleSource should be able to work with src objects without a type', function(assert) {
|
168 | const canHandleSource = Flash.nativeSourceHandler.canHandleSource;
|
169 |
|
170 | assert.equal('maybe',
|
171 | canHandleSource({ src: 'test.video.mp4' }, {}),
|
172 | 'should guess that it is a mp4 video');
|
173 | assert.equal('maybe',
|
174 | canHandleSource({ src: 'test.video.m4v' }, {}),
|
175 | 'should guess that it is a m4v video');
|
176 | assert.equal('maybe',
|
177 | canHandleSource({ src: 'test.video.flv' }, {}),
|
178 | 'should guess that it is a flash video');
|
179 | assert.equal('',
|
180 | canHandleSource({ src: 'test.video.wgg' }, {}),
|
181 | 'should return empty string if it can not play the video');
|
182 | });
|
183 |
|
184 | QUnit.test('seekable', function(assert) {
|
185 | const seekable = Flash.prototype.seekable;
|
186 | let result;
|
187 | const mockFlash = {
|
188 | duration() {
|
189 | return this.duration_;
|
190 | }
|
191 | };
|
192 |
|
193 |
|
194 | mockFlash.duration_ = 23;
|
195 | result = seekable.call(mockFlash);
|
196 | assert.equal(result.length, 1, 'seekable is non-empty');
|
197 | assert.equal(result.start(0), 0, 'starts at zero');
|
198 | assert.equal(result.end(0), mockFlash.duration_, 'ends at the duration');
|
199 |
|
200 |
|
201 | mockFlash.duration_ = 0;
|
202 | result = seekable.call(mockFlash);
|
203 | assert.equal(result.length, mockFlash.duration_,
|
204 | 'seekable is empty with a zero duration');
|
205 | });
|
206 |
|
207 | QUnit.test('play after ended seeks to the beginning', function(assert) {
|
208 | let plays = 0;
|
209 | const seeks = [];
|
210 |
|
211 | Flash.prototype.play.call({
|
212 | el_: {
|
213 |
|
214 | vjs_play() {
|
215 | plays++;
|
216 | }
|
217 |
|
218 | },
|
219 | ended() {
|
220 | return true;
|
221 | },
|
222 | setCurrentTime(time) {
|
223 | seeks.push(time);
|
224 | }
|
225 | });
|
226 |
|
227 | assert.equal(plays, 1, 'called play on the SWF');
|
228 | assert.equal(seeks.length, 1, 'seeked on play');
|
229 | assert.equal(seeks[0], 0, 'seeked to the beginning');
|
230 | });
|
231 |
|
232 | QUnit.test('duration returns NaN, Infinity or duration according to the HTML standard', function(assert) {
|
233 | const duration = Flash.prototype.duration;
|
234 | let mockedDuration = -1;
|
235 | let mockedReadyState = 0;
|
236 | let result;
|
237 | const mockFlash = {
|
238 | el_: {
|
239 |
|
240 | vjs_getProperty() {
|
241 | return mockedDuration;
|
242 | }
|
243 |
|
244 | },
|
245 | readyState() {
|
246 | return mockedReadyState;
|
247 | }
|
248 | };
|
249 |
|
250 | result = duration.call(mockFlash);
|
251 | assert.ok(Number.isNaN(result), 'duration returns NaN when readyState equals 0');
|
252 |
|
253 | mockedReadyState = 1;
|
254 | result = duration.call(mockFlash);
|
255 | assert.ok(!Number.isFinite(result),
|
256 | 'duration returns Infinity when duration property is less then 0');
|
257 |
|
258 | mockedDuration = 1;
|
259 | result = duration.call(mockFlash);
|
260 | assert.equal(result,
|
261 | 1,
|
262 | 'duration returns duration property when readyState' +
|
263 | ' and duration property are both higher than 0');
|
264 | });
|
265 |
|
266 | QUnit.test('getVideoPlaybackQuality API exists', function(assert) {
|
267 | const propertyCalls = [];
|
268 | const videoPlaybackQuality = { test: 'test' };
|
269 | const mockFlash = {
|
270 | el_: {
|
271 |
|
272 | vjs_getProperty(attr) {
|
273 | propertyCalls.push(attr);
|
274 | return videoPlaybackQuality;
|
275 | }
|
276 |
|
277 | }
|
278 | };
|
279 |
|
280 | assert.deepEqual(Flash.prototype.getVideoPlaybackQuality.call(mockFlash),
|
281 | videoPlaybackQuality,
|
282 | 'called to get property from flash');
|
283 | assert.equal(propertyCalls.length, 1, 'only one property call');
|
284 | assert.equal(propertyCalls[0],
|
285 | 'getVideoPlaybackQuality',
|
286 | 'called for getVideoPlaybackQuality');
|
287 | });
|
288 |
|
289 | QUnit.test('getVideoPlaybackQuality uses best available creationTime', function(assert) {
|
290 | const origPerformance = window.performance;
|
291 | const origDate = window.Date;
|
292 | const videoPlaybackQuality = {};
|
293 | const mockFlash = {
|
294 | el_: {
|
295 |
|
296 | vjs_getProperty(attr) {
|
297 | return videoPlaybackQuality;
|
298 | }
|
299 |
|
300 | }
|
301 | };
|
302 |
|
303 | window.performance = void 0;
|
304 | assert.notOk(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime,
|
305 | 'no creationTime when no performance API available');
|
306 |
|
307 | window.performance = {
|
308 | timing: {}
|
309 | };
|
310 | assert.notOk(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime,
|
311 | 'no creationTime when performance API insufficient');
|
312 |
|
313 | window.performance = {
|
314 | now: () => 4
|
315 | };
|
316 | assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime,
|
317 | 4,
|
318 | 'creationTime is performance.now when available');
|
319 |
|
320 | window.Date = {
|
321 | now: () => 10
|
322 | };
|
323 | window.performance = {
|
324 | timing: {
|
325 | navigationStart: 3
|
326 | }
|
327 | };
|
328 | assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime,
|
329 | 7,
|
330 | 'creationTime uses Date.now() - navigationStart when available');
|
331 |
|
332 | window.performance.now = () => 4;
|
333 | assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime,
|
334 | 4,
|
335 | 'creationTime prioritizes performance.now when available');
|
336 |
|
337 | window.Date = origDate;
|
338 | window.performance = origPerformance;
|
339 | });
|