diff --git a/package-lock.json b/package-lock.json index 2d3bba47d..618464043 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1202,25 +1202,24 @@ "type-detect": "4.0.8" } }, - "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", "dev": true, "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "@sinonjs/commons": "^1.7.0" } }, "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", + "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, "@sinonjs/text-encoding": { @@ -1762,12 +1761,6 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", @@ -4104,9 +4097,9 @@ "dev": true }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, "diffie-hellman": { @@ -8997,12 +8990,6 @@ "streamroller": "^2.2.4" } }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "dev": true - }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -9706,27 +9693,16 @@ "dev": true }, "nise": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", + "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.2.1", + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^7.0.4", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^5.0.1", "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - } } }, "node-libs-browser": { @@ -12479,18 +12455,34 @@ "dev": true }, "sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.1.tgz", + "integrity": "sha512-ZSSmlkSyhUWbkF01Z9tEbxZLF/5tRC9eojCdFh33gtQaP7ITQVaMWQHGuFM7Cuf/KEfihuh1tTl3/ABju3AQMg==", "dev": true, "requires": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^7.1.0", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "slash": { diff --git a/package.json b/package.json index f61deb871..2a0d212aa 100644 --- a/package.json +++ b/package.json @@ -139,11 +139,11 @@ "remark-validate-links": "^8.0.2", "replace": "^1.2.1", "rollup": "^2.2.0", - "rollup-plugin-istanbul": "^3.0.0", "rollup-plugin-alias": "^1.5.2", "rollup-plugin-babel": "^4.4.0", "rollup-plugin-commonjs": "^9.3.4", "rollup-plugin-ignore": "^1.0.5", + "rollup-plugin-istanbul": "^3.0.0", "rollup-plugin-json": "^3.1.0", "rollup-plugin-multi-entry": "^2.0.2", "rollup-plugin-node-resolve": "^4.2.4", @@ -153,7 +153,7 @@ "semver": "^5.7.0", "shelljs": "^0.8.3", "shx": "^0.3.2", - "sinon": "^7.3.2", + "sinon": "^11.1.1", "tui-jsdoc-template": "^1.2.2", "uglify-js": "^3.6.0", "unified": "^7.0.2", diff --git a/src/js/player.js b/src/js/player.js index 92cc1bf46..a8831fb3e 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -2850,7 +2850,7 @@ class Player extends Component { if (promise) { promise.then(offHandler, offHandler); - return promise; + promise.then(resolve, reject); } }); } @@ -2928,7 +2928,8 @@ class Player extends Component { if (promise) { promise.then(offHandler, offHandler); - return promise; + // map the promise to our resolve/reject methods + promise.then(resolve, reject); } }); } @@ -2941,7 +2942,9 @@ class Player extends Component { const promise = document[this.fsApi_.exitFullscreen](); if (promise) { - promise.then(() => this.isFullscreen(false)); + // we're splitting the promise here, so, we want to catch the + // potential error so that this chain doesn't have unhandled errors + silencePromise(promise.then(() => this.isFullscreen(false))); } return promise; diff --git a/test/karma.conf.js b/test/karma.conf.js index d12a88dd0..5cd796f02 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -39,7 +39,9 @@ module.exports = function(config) { config.files = [ 'node_modules/es5-shim/es5-shim.js', 'node_modules/es6-shim/es6-shim.js', - 'node_modules/sinon/pkg/sinon.js', + // make sinon be available via karma's server but don't include it directly + { pattern: 'node_modules/sinon/pkg/sinon.js', included: false, served: true }, + 'test/sinon.js', 'dist/video-js.css', 'test/dist/bundle.js', 'test/dist/browserify.js', diff --git a/test/sinon.js b/test/sinon.js new file mode 100644 index 000000000..e3d7d131e --- /dev/null +++ b/test/sinon.js @@ -0,0 +1,12 @@ +/* eslint-disable no-undef */ + +const s = document.createElement('script'); + +// on IE11 and Safari 9, load the last supported sinon version +if (/(?:MSIE|Trident\/7.0|Version\/9.*Safari)/.test(navigator.userAgent)) { + s.src = 'https://unpkg.com/sinon@9.2.4/pkg/sinon-no-sourcemaps.js'; +} else { + s.src = '/test/base/node_modules/sinon/pkg/sinon.js'; +} + +document.write(s.outerHTML); diff --git a/test/unit/player-fullscreen.test.js b/test/unit/player-fullscreen.test.js index 27a2925cc..efb4118be 100644 --- a/test/unit/player-fullscreen.test.js +++ b/test/unit/player-fullscreen.test.js @@ -3,6 +3,7 @@ import Player from '../../src/js/player.js'; import TestHelpers from './test-helpers.js'; import sinon from 'sinon'; import window from 'global/window'; +import document from 'global/document'; const FullscreenTestHelpers = { makePlayer(prefixed, playerOptions, videoTag) { @@ -229,7 +230,7 @@ QUnit.test('full window can be preferred to fullscreen tech', function(assert) { }); QUnit.test('fullwindow mode should exit when ESC event triggered', function(assert) { - const player = FullscreenTestHelpers.makePlayer(true); + const player = TestHelpers.makePlayer(); player.enterFullWindow(); assert.ok(player.isFullWindow, 'enterFullWindow should be called'); @@ -280,3 +281,70 @@ QUnit.test('fullscreenerror event from Html5 should pass through player', functi player.dispose(); }); + +// only run where we have sinon.promise +const skipOrTest = sinon.promise ? 'test' : 'skip'; + +QUnit[skipOrTest]('requestFullscreen returns a rejected promise if unable to go fullscreen', function(assert) { + const player = TestHelpers.makePlayer(); + const playerEl = player.el(); + const stub = sinon.stub(playerEl, player.fsApi_.requestFullscreen); + const promise = sinon.promise(); + + stub.returns(promise); + promise.reject(new Error('Cannot go fullscreen')); + + assert.rejects( + player.requestFullscreen(), + new Error('Cannot go fullscreen'), + 'our promise was rejected' + ); + + stub.restore(); +}); + +QUnit[skipOrTest]('requestFullscreen returns a resolved promise if we were fullscreen', function(assert) { + const player = TestHelpers.makePlayer(); + const playerEl = player.el(); + const stub = sinon.stub(playerEl, player.fsApi_.requestFullscreen); + const promise = sinon.promise(); + + stub.returns(promise); + // pretend we successfully went fullscreen. + promise.resolve(); + + player.requestFullscreen().then(() => assert.ok(true, 'our promise resolved')); + + stub.restore(); +}); + +QUnit[skipOrTest]('exitFullscreen returns a rejected promise if document is not active', function(assert) { + const player = TestHelpers.makePlayer(); + const stub = sinon.stub(document, player.fsApi_.exitFullscreen); + const promise = sinon.promise(); + + stub.returns(promise); + promise.reject(new Error('Document not active')); + + assert.rejects( + player.exitFullscreen(), + new Error('Document not active'), + 'our promise was rejected' + ); + + stub.restore(); +}); + +QUnit[skipOrTest]('exitFullscreen returns a resolved promise if we were fullscreen', function(assert) { + const player = TestHelpers.makePlayer(); + const stub = sinon.stub(document, player.fsApi_.exitFullscreen); + const promise = sinon.promise(); + + stub.returns(promise); + // pretend we successfully exited. + promise.resolve(); + + player.exitFullscreen().then(() => assert.ok(true, 'our promise resolved')); + + stub.restore(); +});