plugin.test.js 10 KB

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