TESTS: Add tests for fix of end-time in the video player.
BLD-662
This commit is contained in:
committed by
Valera Rozuvan
parent
dc373f22b1
commit
450dfe17b0
@@ -117,7 +117,7 @@
|
||||
|
||||
runs(function () {
|
||||
expect(state.videoPlayer.player.getPlayerState())
|
||||
.toBe(STATUS.PLAYING);
|
||||
.toBe(STATUS.BUFFERING);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -366,19 +366,22 @@ function (VideoPlayer) {
|
||||
});
|
||||
|
||||
it('Slider event causes log update', function () {
|
||||
|
||||
runs(function () {
|
||||
var currentTime = state.videoPlayer.currentTime;
|
||||
|
||||
spyOn(state.videoPlayer, 'log');
|
||||
state.videoProgressSlider.onSlide(
|
||||
jQuery.Event('slide'), { value: 2 }
|
||||
);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return state.videoPlayer.currentTime >= 2;
|
||||
}, 'currentTime is less than 2 seconds', WAIT_TIMEOUT);
|
||||
|
||||
runs(function () {
|
||||
expect(state.videoPlayer.log).toHaveBeenCalledWith(
|
||||
'seek_video',
|
||||
{
|
||||
old_time: currentTime,
|
||||
old_time: jasmine.any(Number),
|
||||
new_time: 2,
|
||||
type: 'onSlideSeek'
|
||||
}
|
||||
@@ -388,25 +391,37 @@ function (VideoPlayer) {
|
||||
|
||||
it('seek the player', function () {
|
||||
runs(function () {
|
||||
spyOn(state.videoPlayer.player, 'seekTo');
|
||||
spyOn(state.videoPlayer.player, 'seekTo').andCallThrough();
|
||||
state.videoProgressSlider.onSlide(
|
||||
jQuery.Event('slide'), { value: 60 }
|
||||
jQuery.Event('slide'), { value: 30 }
|
||||
);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return state.videoPlayer.currentTime >= 30;
|
||||
}, 'currentTime is less than 30 seconds', WAIT_TIMEOUT);
|
||||
|
||||
runs(function () {
|
||||
expect(state.videoPlayer.player.seekTo)
|
||||
.toHaveBeenCalledWith(60, true);
|
||||
.toHaveBeenCalledWith(30, true);
|
||||
});
|
||||
});
|
||||
|
||||
it('call updatePlayTime on player', function () {
|
||||
runs(function () {
|
||||
spyOn(state.videoPlayer, 'updatePlayTime');
|
||||
spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough();
|
||||
state.videoProgressSlider.onSlide(
|
||||
jQuery.Event('slide'), { value: 60 }
|
||||
jQuery.Event('slide'), { value: 30 }
|
||||
);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return state.videoPlayer.currentTime >= 30;
|
||||
}, 'currentTime is less than 30 seconds', WAIT_TIMEOUT);
|
||||
|
||||
runs(function () {
|
||||
expect(state.videoPlayer.updatePlayTime)
|
||||
.toHaveBeenCalledWith(60);
|
||||
.toHaveBeenCalledWith(jasmine.any(Number));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1070,6 +1085,7 @@ function (VideoPlayer) {
|
||||
youtubeId: jasmine.createSpy().andReturn('videoId'),
|
||||
isFlashMode: jasmine.createSpy().andReturn(false),
|
||||
isHtml5Mode: jasmine.createSpy().andReturn(true),
|
||||
isYoutubeType: jasmine.createSpy().andReturn(true),
|
||||
setPlayerMode: jasmine.createSpy(),
|
||||
videoPlayer: {
|
||||
currentTime: 60,
|
||||
@@ -1104,12 +1120,12 @@ function (VideoPlayer) {
|
||||
});
|
||||
|
||||
it('in HTML5 mode', function () {
|
||||
state.isYoutubeType.andReturn(false);
|
||||
VideoPlayer.prototype.setPlaybackRate.call(state, '0.75');
|
||||
expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75');
|
||||
});
|
||||
|
||||
it('Youtube video in FF, with new speed equal 1.0', function () {
|
||||
state.videoType = 'youtube';
|
||||
state.browserIsFirefox = true;
|
||||
|
||||
state.videoPlayer.isPlaying.andReturn(false);
|
||||
|
||||
@@ -68,6 +68,7 @@ function (VideoPlayer, VideoStorage) {
|
||||
initialize: initialize,
|
||||
isHtml5Mode: isHtml5Mode,
|
||||
isFlashMode: isFlashMode,
|
||||
isYoutubeType: isYoutubeType,
|
||||
parseSpeed: parseSpeed,
|
||||
parseVideoSources: parseVideoSources,
|
||||
parseYoutubeStreams: parseYoutubeStreams,
|
||||
@@ -847,6 +848,10 @@ function (VideoPlayer, VideoStorage) {
|
||||
return this.getPlayerMode() === 'html5';
|
||||
}
|
||||
|
||||
function isYoutubeType() {
|
||||
return this.videoType === 'youtube';
|
||||
}
|
||||
|
||||
function speedToString(speed) {
|
||||
return parseFloat(speed).toFixed(2).replace(/\.00$/, '.0');
|
||||
}
|
||||
|
||||
@@ -275,12 +275,13 @@ function () {
|
||||
|
||||
// Register the 'play' event.
|
||||
this.video.addEventListener('play', function () {
|
||||
_this.playerState = HTML5Video.PlayerState.PLAYING;
|
||||
_this.playerState = HTML5Video.PlayerState.BUFFERING;
|
||||
_this.callStateChangeCallback();
|
||||
}, false);
|
||||
|
||||
this.video.addEventListener('playing', function () {
|
||||
_this.playerState = HTML5Video.PlayerState.PLAYING;
|
||||
_this.callStateChangeCallback();
|
||||
}, false);
|
||||
|
||||
// Register the 'pause' event.
|
||||
|
||||
@@ -17,13 +17,24 @@ function (HTML5Video, Resizer) {
|
||||
methodsDict = {
|
||||
duration: duration,
|
||||
handlePlaybackQualityChange: handlePlaybackQualityChange,
|
||||
|
||||
// Added for finer graded seeking control.
|
||||
// Please see:
|
||||
// https://developers.google.com/youtube/js_api_reference#Events
|
||||
isBuffering: isBuffering,
|
||||
// https://developers.google.com/youtube/js_api_reference#cueVideoById
|
||||
isCued: isCued,
|
||||
|
||||
isEnded: isEnded,
|
||||
isPlaying: isPlaying,
|
||||
isUnstarted: isUnstarted,
|
||||
log: log,
|
||||
onCaptionSeek: onSeek,
|
||||
onEnded: onEnded,
|
||||
onPause: onPause,
|
||||
onPlay: onPlay,
|
||||
runTimer: runTimer,
|
||||
stopTimer: stopTimer,
|
||||
onPlaybackQualityChange: onPlaybackQualityChange,
|
||||
onReady: onReady,
|
||||
onSlideSeek: onSeek,
|
||||
@@ -54,7 +65,17 @@ function (HTML5Video, Resizer) {
|
||||
// Functions which will be accessible via 'state' object. When called,
|
||||
// these functions will get the 'state' object as a context.
|
||||
function _makeFunctionsPublic(state) {
|
||||
var debouncedF = _.debounce(
|
||||
function (params) {
|
||||
return onSeek.call(this, params);
|
||||
}.bind(state),
|
||||
300
|
||||
);
|
||||
|
||||
state.bindTo(methodsDict, state.videoPlayer, state);
|
||||
|
||||
state.videoPlayer.onSlideSeek = debouncedF;
|
||||
state.videoPlayer.onCaptionSeek = debouncedF;
|
||||
}
|
||||
|
||||
// function _initialize(state)
|
||||
@@ -79,10 +100,10 @@ function (HTML5Video, Resizer) {
|
||||
state.videoPlayer.player.setVolume(state.currentVolume);
|
||||
});
|
||||
|
||||
if (state.videoType === 'youtube') {
|
||||
if (state.isYoutubeType()) {
|
||||
state.videoPlayer.PlayerState = YT.PlayerState;
|
||||
state.videoPlayer.PlayerState.UNSTARTED = -1;
|
||||
} else { // if (state.videoType === 'html5') {
|
||||
} else {
|
||||
state.videoPlayer.PlayerState = HTML5Video.PlayerState;
|
||||
}
|
||||
|
||||
@@ -139,7 +160,7 @@ function (HTML5Video, Resizer) {
|
||||
_updateVcrAndRegion(state);
|
||||
}, false);
|
||||
|
||||
} else { // if (state.videoType === 'youtube') {
|
||||
} else {
|
||||
youTubeId = state.youtubeId();
|
||||
|
||||
state.videoPlayer.player = new YT.Player(state.id, {
|
||||
@@ -305,8 +326,8 @@ function (HTML5Video, Resizer) {
|
||||
// This function gets the video's current play position in time
|
||||
// (currentTime) and its duration.
|
||||
// It is called at a regular interval when the video is playing.
|
||||
function update() {
|
||||
this.videoPlayer.currentTime = this.videoPlayer.player.getCurrentTime();
|
||||
function update(time) {
|
||||
this.videoPlayer.currentTime = time || this.videoPlayer.player.getCurrentTime();
|
||||
|
||||
if (isFinite(this.videoPlayer.currentTime)) {
|
||||
this.videoPlayer.updatePlayTime(this.videoPlayer.currentTime);
|
||||
@@ -339,7 +360,7 @@ function (HTML5Video, Resizer) {
|
||||
!(
|
||||
this.browserIsFirefox &&
|
||||
newSpeed === '1.0' &&
|
||||
this.videoType === 'youtube'
|
||||
this.isYoutubeType()
|
||||
)
|
||||
) {
|
||||
this.videoPlayer.player.setPlaybackRate(newSpeed);
|
||||
@@ -404,6 +425,7 @@ function (HTML5Video, Resizer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.el.off('play.seek');
|
||||
this.videoPlayer.log(
|
||||
'seek_video',
|
||||
{
|
||||
@@ -420,24 +442,49 @@ function (HTML5Video, Resizer) {
|
||||
this.videoPlayer.stopAtEndTime = false;
|
||||
}
|
||||
|
||||
this.videoPlayer.player.seekTo(newTime, true);
|
||||
|
||||
if (this.videoPlayer.isPlaying()) {
|
||||
clearInterval(this.videoPlayer.updateInterval);
|
||||
this.videoPlayer.updateInterval = setInterval(
|
||||
this.videoPlayer.update, 200
|
||||
);
|
||||
|
||||
setTimeout(this.videoPlayer.update, 0);
|
||||
this.videoPlayer.stopTimer();
|
||||
} else {
|
||||
this.videoPlayer.currentTime = newTime;
|
||||
}
|
||||
var isUnplayed = this.videoPlayer.isUnstarted() ||
|
||||
this.videoPlayer.isCued();
|
||||
|
||||
this.videoPlayer.updatePlayTime(newTime);
|
||||
// Use `cueVideoById` method for youtube video that is not played before.
|
||||
if (isUnplayed && this.isYoutubeType()) {
|
||||
this.videoPlayer.player.cueVideoById(this.youtubeId(), newTime);
|
||||
} else {
|
||||
// Youtube video cannot be rewinded during bufferization, so wait to
|
||||
// finish bufferization and then rewind the video.
|
||||
if (this.isYoutubeType() && this.videoPlayer.isBuffering()) {
|
||||
this.el.on('play.seek', function () {
|
||||
this.videoPlayer.player.seekTo(newTime, true);
|
||||
}.bind(this));
|
||||
} else {
|
||||
// Otherwise, just seek the video
|
||||
this.videoPlayer.player.seekTo(newTime, true);
|
||||
}
|
||||
}
|
||||
|
||||
this.videoPlayer.updatePlayTime(newTime, true);
|
||||
this.el.trigger('seek', arguments);
|
||||
}
|
||||
|
||||
function runTimer() {
|
||||
if (!this.videoPlayer.updateInterval) {
|
||||
this.videoPlayer.updateInterval = window.setInterval(
|
||||
this.videoPlayer.update, 200
|
||||
);
|
||||
|
||||
this.videoPlayer.update();
|
||||
}
|
||||
}
|
||||
|
||||
function stopTimer() {
|
||||
window.clearInterval(this.videoPlayer.updateInterval);
|
||||
delete this.videoPlayer.updateInterval;
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
var time = this.videoPlayer.duration();
|
||||
|
||||
@@ -466,8 +513,7 @@ function (HTML5Video, Resizer) {
|
||||
}
|
||||
);
|
||||
|
||||
clearInterval(this.videoPlayer.updateInterval);
|
||||
delete this.videoPlayer.updateInterval;
|
||||
this.videoPlayer.stopTimer();
|
||||
|
||||
this.trigger('videoControl.pause', null);
|
||||
this.saveState(true);
|
||||
@@ -482,14 +528,7 @@ function (HTML5Video, Resizer) {
|
||||
}
|
||||
);
|
||||
|
||||
if (!this.videoPlayer.updateInterval) {
|
||||
this.videoPlayer.updateInterval = setInterval(
|
||||
this.videoPlayer.update, 200
|
||||
);
|
||||
|
||||
this.videoPlayer.update();
|
||||
}
|
||||
|
||||
this.videoPlayer.runTimer();
|
||||
this.trigger('videoControl.play', null);
|
||||
this.trigger('videoProgressSlider.notifyThroughHandleEnd', {
|
||||
end: false
|
||||
@@ -558,7 +597,7 @@ function (HTML5Video, Resizer) {
|
||||
// https://github.com/edx/edx-platform/pull/2841
|
||||
if (
|
||||
(this.isHtml5Mode() || availablePlaybackRates.length > 1) &&
|
||||
this.videoType === 'youtube'
|
||||
this.isYoutubeType()
|
||||
) {
|
||||
if (availablePlaybackRates.length === 1 && !this.isTouch) {
|
||||
// This condition is needed in cases when Firefox version is
|
||||
@@ -620,20 +659,34 @@ function (HTML5Video, Resizer) {
|
||||
}
|
||||
|
||||
function onStateChange(event) {
|
||||
this.el.removeClass([
|
||||
'is-unstarted', 'is-playing', 'is-paused', 'is-buffered',
|
||||
'is-ended', 'is-cued'
|
||||
].join(' '));
|
||||
|
||||
switch (event.data) {
|
||||
case this.videoPlayer.PlayerState.UNSTARTED:
|
||||
this.el.addClass('is-unstarted');
|
||||
this.videoPlayer.onUnstarted();
|
||||
break;
|
||||
case this.videoPlayer.PlayerState.PLAYING:
|
||||
this.el.addClass('is-playing');
|
||||
this.videoPlayer.onPlay();
|
||||
break;
|
||||
case this.videoPlayer.PlayerState.PAUSED:
|
||||
this.el.addClass('is-paused');
|
||||
this.videoPlayer.onPause();
|
||||
break;
|
||||
case this.videoPlayer.PlayerState.BUFFERING:
|
||||
this.el.addClass('is-buffered');
|
||||
this.el.trigger('buffering');
|
||||
break;
|
||||
case this.videoPlayer.PlayerState.ENDED:
|
||||
this.el.addClass('is-ended');
|
||||
this.videoPlayer.onEnded();
|
||||
break;
|
||||
case this.videoPlayer.PlayerState.CUED:
|
||||
this.el.addClass('is-cued');
|
||||
this.videoPlayer.player.seekTo(this.videoPlayer.seekToTimeOnCued, true);
|
||||
// We need to call play() explicitly because after the call
|
||||
// to functions cueVideoById() followed by seekTo() the video
|
||||
@@ -711,12 +764,12 @@ function (HTML5Video, Resizer) {
|
||||
return time;
|
||||
}
|
||||
|
||||
function updatePlayTime(time) {
|
||||
function updatePlayTime(time, skip_seek) {
|
||||
var videoPlayer = this.videoPlayer,
|
||||
duration = this.videoPlayer.duration(),
|
||||
youTubeId;
|
||||
|
||||
if (duration > 0 && videoPlayer.goToStartTime) {
|
||||
if (duration > 0 && videoPlayer.goToStartTime && !skip_seek) {
|
||||
videoPlayer.goToStartTime = false;
|
||||
|
||||
// The duration might have changed. Update the start-end time region to
|
||||
@@ -746,7 +799,7 @@ function (HTML5Video, Resizer) {
|
||||
//
|
||||
// HTML5 video sources play fine from start-time in both Chrome
|
||||
// and Firefox.
|
||||
if (this.browserIsFirefox && this.videoType === 'youtube') {
|
||||
if (this.browserIsFirefox && this.isYoutubeType()) {
|
||||
youTubeId = this.youtubeId();
|
||||
|
||||
// When we will call cueVideoById() for some strange reason
|
||||
@@ -794,10 +847,27 @@ function (HTML5Video, Resizer) {
|
||||
}
|
||||
|
||||
function isPlaying() {
|
||||
var playerState = this.videoPlayer.player.getPlayerState(),
|
||||
PLAYING = this.videoPlayer.PlayerState.PLAYING;
|
||||
var playerState = this.videoPlayer.player.getPlayerState();
|
||||
|
||||
return playerState === PLAYING;
|
||||
return playerState === this.videoPlayer.PlayerState.PLAYING;
|
||||
}
|
||||
|
||||
function isBuffering() {
|
||||
var playerState = this.videoPlayer.player.getPlayerState();
|
||||
|
||||
return playerState === this.videoPlayer.PlayerState.BUFFERING;
|
||||
}
|
||||
|
||||
function isCued() {
|
||||
var playerState = this.videoPlayer.player.getPlayerState();
|
||||
|
||||
return playerState === this.videoPlayer.PlayerState.CUED;
|
||||
}
|
||||
|
||||
function isUnstarted() {
|
||||
var playerState = this.videoPlayer.player.getPlayerState();
|
||||
|
||||
return playerState === this.videoPlayer.PlayerState.UNSTARTED;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -844,7 +914,7 @@ function (HTML5Video, Resizer) {
|
||||
// might differ by one or two seconds against the actual time as will
|
||||
// be reported later on by the player.getDuration() API function.
|
||||
if (!isFinite(dur) || dur <= 0) {
|
||||
if (this.videoType === 'youtube') {
|
||||
if (this.isYoutubeType()) {
|
||||
dur = this.getDuration();
|
||||
}
|
||||
}
|
||||
@@ -873,9 +943,9 @@ function (HTML5Video, Resizer) {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.videoType === 'youtube') {
|
||||
if (this.isYoutubeType()) {
|
||||
logInfo.code = this.youtubeId();
|
||||
} else if (this.videoType === 'html5') {
|
||||
} else {
|
||||
logInfo.code = 'html5';
|
||||
}
|
||||
|
||||
|
||||
@@ -177,15 +177,26 @@ function () {
|
||||
}
|
||||
|
||||
function onSlide(event, ui) {
|
||||
var time = ui.value,
|
||||
duration = this.videoPlayer.duration();
|
||||
|
||||
this.videoProgressSlider.frozen = true;
|
||||
|
||||
// Remember the seek to value so that we don't repeat ourselves on the
|
||||
// 'stop' slider event.
|
||||
this.videoProgressSlider.lastSeekValue = ui.value;
|
||||
this.videoProgressSlider.lastSeekValue = time;
|
||||
|
||||
this.trigger(
|
||||
'videoControl.updateVcrVidTime',
|
||||
{
|
||||
time: time,
|
||||
duration: duration
|
||||
}
|
||||
);
|
||||
|
||||
this.trigger(
|
||||
'videoPlayer.onSlideSeek',
|
||||
{'type': 'onSlideSeek', 'time': ui.value}
|
||||
{'type': 'onSlideSeek', 'time': time}
|
||||
);
|
||||
|
||||
// ARIA
|
||||
|
||||
Reference in New Issue
Block a user