Commit 9d9f28da by Valera Rozuvan

Merge pull request #3275 from edx/valera/l52a

TESTS: Add tests for fix of end-time functionality in the video player
parents dc373f22 450dfe17
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
runs(function () { runs(function () {
expect(state.videoPlayer.player.getPlayerState()) expect(state.videoPlayer.player.getPlayerState())
.toBe(STATUS.PLAYING); .toBe(STATUS.BUFFERING);
}); });
}); });
......
...@@ -366,19 +366,22 @@ function (VideoPlayer) { ...@@ -366,19 +366,22 @@ function (VideoPlayer) {
}); });
it('Slider event causes log update', function () { it('Slider event causes log update', function () {
runs(function () { runs(function () {
var currentTime = state.videoPlayer.currentTime;
spyOn(state.videoPlayer, 'log'); spyOn(state.videoPlayer, 'log');
state.videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 2 } 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( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'seek_video', 'seek_video',
{ {
old_time: currentTime, old_time: jasmine.any(Number),
new_time: 2, new_time: 2,
type: 'onSlideSeek' type: 'onSlideSeek'
} }
...@@ -388,25 +391,37 @@ function (VideoPlayer) { ...@@ -388,25 +391,37 @@ function (VideoPlayer) {
it('seek the player', function () { it('seek the player', function () {
runs(function () { runs(function () {
spyOn(state.videoPlayer.player, 'seekTo'); spyOn(state.videoPlayer.player, 'seekTo').andCallThrough();
state.videoProgressSlider.onSlide( 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) expect(state.videoPlayer.player.seekTo)
.toHaveBeenCalledWith(60, true); .toHaveBeenCalledWith(30, true);
}); });
}); });
it('call updatePlayTime on player', function () { it('call updatePlayTime on player', function () {
runs(function () { runs(function () {
spyOn(state.videoPlayer, 'updatePlayTime'); spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough();
state.videoProgressSlider.onSlide( 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) expect(state.videoPlayer.updatePlayTime)
.toHaveBeenCalledWith(60); .toHaveBeenCalledWith(jasmine.any(Number));
}); });
}); });
...@@ -1070,6 +1085,7 @@ function (VideoPlayer) { ...@@ -1070,6 +1085,7 @@ function (VideoPlayer) {
youtubeId: jasmine.createSpy().andReturn('videoId'), youtubeId: jasmine.createSpy().andReturn('videoId'),
isFlashMode: jasmine.createSpy().andReturn(false), isFlashMode: jasmine.createSpy().andReturn(false),
isHtml5Mode: jasmine.createSpy().andReturn(true), isHtml5Mode: jasmine.createSpy().andReturn(true),
isYoutubeType: jasmine.createSpy().andReturn(true),
setPlayerMode: jasmine.createSpy(), setPlayerMode: jasmine.createSpy(),
videoPlayer: { videoPlayer: {
currentTime: 60, currentTime: 60,
...@@ -1104,12 +1120,12 @@ function (VideoPlayer) { ...@@ -1104,12 +1120,12 @@ function (VideoPlayer) {
}); });
it('in HTML5 mode', function () { it('in HTML5 mode', function () {
state.isYoutubeType.andReturn(false);
VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75');
expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75'); expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75');
}); });
it('Youtube video in FF, with new speed equal 1.0', function () { it('Youtube video in FF, with new speed equal 1.0', function () {
state.videoType = 'youtube';
state.browserIsFirefox = true; state.browserIsFirefox = true;
state.videoPlayer.isPlaying.andReturn(false); state.videoPlayer.isPlaying.andReturn(false);
......
...@@ -68,6 +68,7 @@ function (VideoPlayer, VideoStorage) { ...@@ -68,6 +68,7 @@ function (VideoPlayer, VideoStorage) {
initialize: initialize, initialize: initialize,
isHtml5Mode: isHtml5Mode, isHtml5Mode: isHtml5Mode,
isFlashMode: isFlashMode, isFlashMode: isFlashMode,
isYoutubeType: isYoutubeType,
parseSpeed: parseSpeed, parseSpeed: parseSpeed,
parseVideoSources: parseVideoSources, parseVideoSources: parseVideoSources,
parseYoutubeStreams: parseYoutubeStreams, parseYoutubeStreams: parseYoutubeStreams,
...@@ -847,6 +848,10 @@ function (VideoPlayer, VideoStorage) { ...@@ -847,6 +848,10 @@ function (VideoPlayer, VideoStorage) {
return this.getPlayerMode() === 'html5'; return this.getPlayerMode() === 'html5';
} }
function isYoutubeType() {
return this.videoType === 'youtube';
}
function speedToString(speed) { function speedToString(speed) {
return parseFloat(speed).toFixed(2).replace(/\.00$/, '.0'); return parseFloat(speed).toFixed(2).replace(/\.00$/, '.0');
} }
......
...@@ -275,12 +275,13 @@ function () { ...@@ -275,12 +275,13 @@ function () {
// Register the 'play' event. // Register the 'play' event.
this.video.addEventListener('play', function () { this.video.addEventListener('play', function () {
_this.playerState = HTML5Video.PlayerState.PLAYING; _this.playerState = HTML5Video.PlayerState.BUFFERING;
_this.callStateChangeCallback(); _this.callStateChangeCallback();
}, false); }, false);
this.video.addEventListener('playing', function () { this.video.addEventListener('playing', function () {
_this.playerState = HTML5Video.PlayerState.PLAYING; _this.playerState = HTML5Video.PlayerState.PLAYING;
_this.callStateChangeCallback();
}, false); }, false);
// Register the 'pause' event. // Register the 'pause' event.
......
...@@ -177,15 +177,26 @@ function () { ...@@ -177,15 +177,26 @@ function () {
} }
function onSlide(event, ui) { function onSlide(event, ui) {
var time = ui.value,
duration = this.videoPlayer.duration();
this.videoProgressSlider.frozen = true; this.videoProgressSlider.frozen = true;
// Remember the seek to value so that we don't repeat ourselves on the // Remember the seek to value so that we don't repeat ourselves on the
// 'stop' slider event. // 'stop' slider event.
this.videoProgressSlider.lastSeekValue = ui.value; this.videoProgressSlider.lastSeekValue = time;
this.trigger(
'videoControl.updateVcrVidTime',
{
time: time,
duration: duration
}
);
this.trigger( this.trigger(
'videoPlayer.onSlideSeek', 'videoPlayer.onSlideSeek',
{'type': 'onSlideSeek', 'time': ui.value} {'type': 'onSlideSeek', 'time': time}
); );
// ARIA // ARIA
......
...@@ -35,7 +35,7 @@ def configure_screenshots_for_all_steps(_step, action): ...@@ -35,7 +35,7 @@ def configure_screenshots_for_all_steps(_step, action):
else: else:
raise ValueError('Parameter `action` should be one of "enable" or "disable".') raise ValueError('Parameter `action` should be one of "enable" or "disable".')
@world.absorb
def capture_screenshot_before_after(func): def capture_screenshot_before_after(func):
""" """
A decorator that will take a screenshot before and after the applied A decorator that will take a screenshot before and after the applied
......
...@@ -2,18 +2,6 @@ ...@@ -2,18 +2,6 @@
Feature: LMS.Video component Feature: LMS.Video component
As a student, I want to view course videos in LMS As a student, I want to view course videos in LMS
# 1 Disabled 4/8/14 after intermittent failures in master
#Scenario: Video component stores position correctly when page is reloaded
# Given the course has a Video component in "Youtube" mode
# When the video has rendered in "Youtube" mode
# And I click video button "play"
# And I click video button "pause"
# Then I seek video to "10" seconds
# And I click video button "play"
# And I click video button "pause"
# And I reload the page with video
# Then I see video slider at "10" seconds
# 1 # 1
Scenario: Video component is fully rendered in the LMS in HTML5 mode Scenario: Video component is fully rendered in the LMS in HTML5 mode
Given the course has a Video component in "HTML5" mode Given the course has a Video component in "HTML5" mode
...@@ -267,7 +255,106 @@ Feature: LMS.Video component ...@@ -267,7 +255,106 @@ Feature: LMS.Video component
Then the video has rendered in "HTML5" mode Then the video has rendered in "HTML5" mode
And the video does not show the captions And the video does not show the captions
# 20 Disabled 4/8/14 after intermittent failures in master # 20
Scenario: Start time works for Youtube video
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time |
| 00:00:10 |
And I click video button "play"
Then I see video slider at "0:10" position
# 21
Scenario: End time works for Youtube video
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:00:02 |
And I click video button "play"
And I wait "5" seconds
Then I see video slider at "0:02" position
# 22
Scenario: Youtube video with end-time at 1:00 and the video starts playing at 0:58
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:01:00 |
And I wait for video controls appear
And I seek video to "0:58" position
And I click video button "play"
And I wait "5" seconds
Then I see video slider at "1:00" position
# 23
Scenario: Start time and end time work together for Youtube video
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:00:10 | 00:00:12 |
And I click video button "play"
Then I see video slider at "0:10" position
And I wait "5" seconds
Then I see video slider at "0:12" position
# 24
Scenario: Youtube video after pausing at end time video plays to the end from end time
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:01:51 | 00:01:52 |
And I click video button "play"
And I wait "5" seconds
# The end time is 00:01:52.
Then I see video slider at "1:52" position
And I click video button "play"
And I wait "8" seconds
# The default video length is 00:01:55.
Then I see video slider at "1:55" position
# 25
Scenario: Youtube video with end-time at 0:32 and start-time at 0:30, the video starts playing from 0:28
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| start_time | end_time |
| 00:00:30 | 00:00:32 |
And I wait for video controls appear
And I seek video to "0:28" position
And I click video button "play"
And I wait "8" seconds
Then I see video slider at "0:32" position
# 26
Scenario: Youtube video with end-time at 1:00, the video starts playing from 1:52
Given I am registered for the course "test_course"
And it has a video in "Youtube" mode:
| end_time |
| 00:01:00 |
And I wait for video controls appear
And I seek video to "1:52" position
And I click video button "play"
And I wait "5" seconds
# Video stops at the end.
Then I see video slider at "1:55" position
# 27
@skip_firefox
Scenario: Quality button appears on play
Given the course has a Video component in "Youtube" mode
Then I see video button "quality" is hidden
And I click video button "play"
Then I see video button "quality" is visible
# 28
@skip_firefox
Scenario: Quality button works correctly
Given the course has a Video component in "Youtube" mode
And I click video button "play"
And I see video button "quality" is inactive
And I click video button "quality"
Then I see video button "quality" is active
# 29 Disabled 4/8/14 after intermittent failures in master
#Scenario: Transcripts are available on different speeds of Flash mode #Scenario: Transcripts are available on different speeds of Flash mode
# Given I am registered for the course "test_course" # Given I am registered for the course "test_course"
# And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets # And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
...@@ -282,7 +369,7 @@ Feature: LMS.Video component ...@@ -282,7 +369,7 @@ Feature: LMS.Video component
# Then I select the "1.25" speed # Then I select the "1.25" speed
# And I see "Hi, welcome to Edx." text in the captions # And I see "Hi, welcome to Edx." text in the captions
# 21 Disabled 4/8/14 after intermittent failures in master # 30 Disabled 4/8/14 after intermittent failures in master
#Scenario: Elapsed time calculates correctly on different speeds of Flash mode #Scenario: Elapsed time calculates correctly on different speeds of Flash mode
# Given I am registered for the course "test_course" # Given I am registered for the course "test_course"
# And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets # And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
...@@ -298,19 +385,14 @@ Feature: LMS.Video component ...@@ -298,19 +385,14 @@ Feature: LMS.Video component
# And I click video button "pause" # And I click video button "pause"
# And I click on caption line "2", video module shows elapsed time "4" # And I click on caption line "2", video module shows elapsed time "4"
# 27 # 31 Disabled 4/8/14 after intermittent failures in master
@skip_firefox #Scenario: Video component stores position correctly when page is reloaded
Scenario: Quality button appears on play # Given the course has a Video component in "Youtube" mode
Given the course has a Video component in "Youtube" mode # When the video has rendered in "Youtube" mode
Then I see video button "quality" is hidden # And I click video button "play"
And I click video button "play" # And I click video button "pause"
Then I see video button "quality" is visible # Then I seek video to "0:10" position
# And I click video button "play"
# 28 # And I click video button "pause"
@skip_firefox # And I reload the page with video
Scenario: Quality button works correctly # Then I see video slider at "0:10" position
Given the course has a Video component in "Youtube" mode
And I click video button "play"
And I see video button "quality" is inactive
And I click video button "quality"
Then I see video button "quality" is active
...@@ -482,6 +482,7 @@ def check_captions(_step): ...@@ -482,6 +482,7 @@ def check_captions(_step):
@step('I select language with code "([^"]*)"$') @step('I select language with code "([^"]*)"$')
def select_language(_step, code): def select_language(_step, code):
world.wait_for_visible('.video-controls')
# Make sure that all ajax requests that affects the language menu are finished. # Make sure that all ajax requests that affects the language menu are finished.
# For example, request to get new translation etc. # For example, request to get new translation etc.
world.wait_for_ajax_complete() world.wait_for_ajax_complete()
...@@ -506,16 +507,19 @@ def select_language(_step, code): ...@@ -506,16 +507,19 @@ def select_language(_step, code):
@step('I click video button "([^"]*)"$') @step('I click video button "([^"]*)"$')
def click_button(_step, button): def click_button(_step, button):
world.css_click(VIDEO_BUTTONS[button]) world.css_click(VIDEO_BUTTONS[button])
world.wait_for_ajax_complete() if button == "play":
# Needs to wait for video buffrization
world.wait_for(
func=lambda _: world.css_has_class('.video', 'is-playing') and world.is_css_present(VIDEO_BUTTONS['pause']),
timeout=30
)
world.wait_for_ajax_complete()
@step('I see video slider at "([^"]*)" seconds$')
def start_playing_video_from_n_seconds(_step, position):
world.wait_for(
func=lambda _: elapsed_time() > 0,
timeout=30
)
@step('I see video slider at "([^"]*)" position$')
def start_playing_video_from_n_seconds(_step, time_str):
position = parse_time_str(time_str)
actual_position = elapsed_time() actual_position = elapsed_time()
assert_equal(actual_position, int(position), "Current position is {}, but should be {}".format(actual_position, position)) assert_equal(actual_position, int(position), "Current position is {}, but should be {}".format(actual_position, position))
...@@ -530,12 +534,21 @@ def i_see_duration(_step, position): ...@@ -530,12 +534,21 @@ def i_see_duration(_step, position):
assert duration() == parse_time_str(position) assert duration() == parse_time_str(position)
@step('I seek video to "([^"]*)" seconds$') @step('I wait for video controls appear$')
def seek_video_to_n_seconds(_step, seconds): def controls_appear(_step):
time = float(seconds.strip()) world.wait_for_visible('.video-controls')
jsCode = "$('.video').data('video-player-state').videoPlayer.onSlideSeek({{time: {0:f}}})".format(time)
@step('I seek video to "([^"]*)" position$')
def seek_video_to_n_seconds(_step, time_str):
time = parse_time_str(time_str)
jsCode = "$('.video').data('video-player-state').videoPlayer.onSlideSeek({{time: {0}}})".format(time)
world.browser.execute_script(jsCode) world.browser.execute_script(jsCode)
_step.given('I see video slider at "{}" seconds'.format(seconds)) world.wait_for(
func=lambda _: world.retry_on_exception(lambda: elapsed_time() == time and not world.css_has_class('.video', 'is-buffering')),
timeout=30
)
_step.given('I see video slider at "{0}" position'.format(time_str))
@step('I have a "([^"]*)" transcript file in assets$') @step('I have a "([^"]*)" transcript file in assets$')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment