From 19faaafd8c3926bce93f3a1b15c2b2c02bdfcc5b Mon Sep 17 00:00:00 2001 From: Alex Barstow Date: Thu, 24 Oct 2024 14:20:01 -0400 Subject: [PATCH] tests, avoid mutating prototype --- .../control-bar/progress-control/seek-bar.js | 7 +- test/unit/controls.test.js | 14 ++ test/unit/player.test.js | 148 ++++++++++++++++++ 3 files changed, 167 insertions(+), 2 deletions(-) diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index 4733affa34..b078b3d0f0 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -43,7 +43,10 @@ class SeekBar extends Slider { constructor(player, options) { options = merge(SeekBar.prototype.options_, options); - const shouldDisableSeekWhileScrubbingOnMobile = options.playerOptions.disableSeekWhileScrubbingOnMobile && (IS_IOS || IS_ANDROID); + // Avoid mutating the prototype's `children` array by creating a copy + options.children = [...options.children]; + + const shouldDisableSeekWhileScrubbingOnMobile = player.options_.disableSeekWhileScrubbingOnMobile && (IS_IOS || IS_ANDROID); // Add the TimeTooltip as a child if we are on desktop, or on mobile with `disableSeekWhileScrubbingOnMobile: true` if ((!IS_IOS && !IS_ANDROID) || shouldDisableSeekWhileScrubbingOnMobile) { @@ -240,7 +243,7 @@ class SeekBar extends Slider { */ getPercent() { // If we have a pending seek time, we are scrubbing on mobile and should set the slider percent - // to reflect where the user is scrubbing. + // to reflect the current scrub location. if (this.pendingSeekTime_) { return this.pendingSeekTime_ / this.player_.duration(); } diff --git a/test/unit/controls.test.js b/test/unit/controls.test.js index fcbc0be3e3..0a05551268 100644 --- a/test/unit/controls.test.js +++ b/test/unit/controls.test.js @@ -223,6 +223,20 @@ QUnit.test('SeekBar should be filled on 100% when the video/audio ends', functio window.cancelAnimationFrame = oldCAF; }); +QUnit.test('Seek bar percent should represent scrub location if we are scrubbing on mobile and have a pending seek time', function(assert) { + const player = TestHelpers.makePlayer(); + const seekBar = player.controlBar.progressControl.seekBar; + + player.duration(100); + seekBar.pendingSeekTime_ = 20; + + assert.equal(seekBar.getPercent(), 0.2, 'seek bar percent set correctly to pending seek time'); + + seekBar.pendingSeekTime_ = 50; + + assert.equal(seekBar.getPercent(), 0.5, 'seek bar percent set correctly to next pending seek time'); +}); + QUnit.test('playback rate button is hidden by default', function(assert) { assert.expect(1); diff --git a/test/unit/player.test.js b/test/unit/player.test.js index 4e6cbfa286..4608508808 100644 --- a/test/unit/player.test.js +++ b/test/unit/player.test.js @@ -3611,6 +3611,154 @@ QUnit.test('smooth seeking set to true should update the display time components player.dispose(); }); +QUnit.test('mouseTimeDisplay should be added as child when disableSeekWhileScrubbingOnMobile is true on mobile', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: true }); + const seekBar = player.controlBar.progressControl.seekBar; + const mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay'); + + assert.ok(mouseTimeDisplay, 'mouseTimeDisplay added as a child'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('mouseTimeDisplay should not be added as child on mobile when disableSeekWhileScrubbingOnMobile is false', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: false }); + const seekBar = player.controlBar.progressControl.seekBar; + const mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay'); + + assert.notOk(mouseTimeDisplay, 'mouseTimeDisplay not added as a child'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('Seeking should occur while scrubbing on mobile when disableSeekWhileScrubbingOnMobile is false', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: false }); + const seekBar = player.controlBar.progressControl.seekBar; + const userSeekSpy = sinon.spy(seekBar, 'userSeek_'); + + // Simulate a source loaded + player.duration(10); + + // Simulate scrub + seekBar.handleMouseMove({ pageX: 200 }); + + assert.ok(userSeekSpy.calledOnce, 'Seek initiated while scrubbing'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('Seeking should not occur while scrubbing on mobile when disableSeekWhileScrubbingOnMobile is true', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: true }); + const seekBar = player.controlBar.progressControl.seekBar; + const userSeekSpy = sinon.spy(seekBar, 'userSeek_'); + + // Simulate a source loaded + player.duration(10); + + // Simulate scrub + seekBar.handleMouseMove({ pageX: 200 }); + + assert.ok(userSeekSpy.notCalled, 'Seek not initiated while scrubbing'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('Seek should occur when scrubbing completes on mobile when disableSeekWhileScrubbingOnMobile is true', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: true }); + const seekBar = player.controlBar.progressControl.seekBar; + const userSeekSpy = sinon.spy(seekBar, 'userSeek_'); + const targetSeekTime = 5; + + // Simulate a source loaded + player.duration(10); + + seekBar.pendingSeekTime_ = targetSeekTime; + + // Simulate scrubbing completion + seekBar.handleMouseUp(); + + assert.ok(userSeekSpy.calledWith(targetSeekTime), 'Seeks to correct location when scrubbing completes'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('Player should pause while scrubbing on mobile when disableSeekWhileScrubbingOnMobile is false', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: false }); + const seekBar = player.controlBar.progressControl.seekBar; + const pauseSpy = sinon.spy(player, 'pause'); + + // Simulate start playing + player.play(); + + const mockMouseDownEvent = { + pageX: 200, + stopPropagation: () => {} + }; + + // Simulate scrubbing start + seekBar.handleMouseDown(mockMouseDownEvent); + + assert.ok(pauseSpy.calledOnce, 'Player paused'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + +QUnit.test('Player should not pause while scrubbing on mobile when disableSeekWhileScrubbingOnMobile is true', function(assert) { + const originalIsIos = browser.IS_IOS; + + browser.stub_IS_IOS(true); + + const player = TestHelpers.makePlayer({ disableSeekWhileScrubbingOnMobile: true }); + const seekBar = player.controlBar.progressControl.seekBar; + const pauseSpy = sinon.spy(player, 'pause'); + + // Simulate start playing + player.play(); + + const mockMouseDownEvent = { + pageX: 200, + stopPropagation: () => { } + }; + + // Simulate scrubbing start + seekBar.handleMouseDown(mockMouseDownEvent); + + assert.ok(pauseSpy.notCalled, 'Player not paused'); + + player.dispose(); + browser.stub_IS_IOS(originalIsIos); +}); + QUnit.test('addSourceElement calls tech method with correct args', function(assert) { const player = TestHelpers.makePlayer(); const addSourceElementSpy = sinon.spy(player.tech_, 'addSourceElement');