diff --git a/common/lib/xmodule/xmodule/js/fixtures/video.html b/common/lib/xmodule/xmodule/js/fixtures/video.html index 15404a89d190..e86a24dc5ce0 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video.html @@ -1,12 +1,21 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file diff --git a/common/lib/xmodule/xmodule/js/spec/helper.coffee b/common/lib/xmodule/xmodule/js/spec/helper.coffee index fbc89f7bd984..5cf75366d8f0 100644 --- a/common/lib/xmodule/xmodule/js/spec/helper.coffee +++ b/common/lib/xmodule/xmodule/js/spec/helper.coffee @@ -28,7 +28,7 @@ jasmine.stubRequests = -> spyOn($, 'ajax').andCallFake (settings) -> if match = settings.url.match /youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/ settings.success data: jasmine.stubbedMetadata[match[1]] - else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/ + else if match = settings.url.match /static(\/.*)?\/subs\/(.+)\.srt\.sjson/ settings.success jasmine.stubbedCaption else if settings.url.match /.+\/problem_get$/ settings.success html: readFixtures('problem_content.html') @@ -47,19 +47,15 @@ jasmine.stubYoutubePlayer = -> jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) -> enableParts = [enableParts] unless $.isArray(enableParts) - suite = context.suite currentPartName = suite.description while suite = suite.parentSuite enableParts.push currentPartName - for part in ['VideoCaption', 'VideoSpeedControl', 'VideoVolumeControl', 'VideoProgressSlider'] - unless $.inArray(part, enableParts) >= 0 - spyOn window, part - loadFixtures 'video.html' jasmine.stubRequests() YT.Player = undefined - context.video = new Video 'example', '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId' + videosDefinition = '0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId' + context.video = new Video '#example', videosDefinition jasmine.stubYoutubePlayer() if createPlayer return new VideoPlayer(video: context.video) diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_caption_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_caption_spec.coffee index 90e026e57e01..8c63751f0761 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_caption_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_caption_spec.coffee @@ -1,23 +1,25 @@ -# TODO: figure out why failing -xdescribe 'VideoCaption', -> +describe 'VideoCaption', -> + beforeEach -> - jasmine.stubVideoPlayer @ - $('.subtitles').remove() + spyOn(VideoCaption.prototype, 'fetchCaption').andCallThrough() + spyOn($, 'ajaxWithPrefix').andCallThrough() + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn false afterEach -> YT.Player = undefined $.fn.scrollTo.reset() + $('.subtitles').remove() describe 'constructor', -> - beforeEach -> - spyOn($, 'getWithPrefix').andCallThrough() describe 'always', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption it 'set the youtube id', -> - expect(@caption.youtubeId).toEqual 'def456' + expect(@caption.youtubeId).toEqual 'normalSpeedYoutubeId' it 'create the caption element', -> expect($('.video')).toContain 'ol.subtitles' @@ -26,7 +28,12 @@ xdescribe 'VideoCaption', -> expect($('.video')).toContain 'a.hide-subtitles' it 'fetch the caption', -> - expect($.getWithPrefix).toHaveBeenCalledWith @caption.captionURL(), jasmine.any(Function) + expect(@caption.loaded).toBeTruthy() + expect(@caption.fetchCaption).toHaveBeenCalled() + expect($.ajaxWithPrefix).toHaveBeenCalledWith + url: @caption.captionURL() + notifyOnError: false + success: jasmine.any(Function) it 'bind window resize event', -> expect($(window)).toHandleWith 'resize', @caption.resize @@ -42,17 +49,17 @@ xdescribe 'VideoCaption', -> expect($('.subtitles')).toHandleWith 'DOMMouseScroll', @caption.onMovement describe 'when on a non touch-based device', -> + beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn false - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption it 'render the caption', -> - expect($('.subtitles').html()).toMatch new RegExp(''' -
  • Caption at 0
  • -
  • Caption at 10000
  • -
  • Caption at 20000
  • -
  • Caption at 30000
  • - '''.replace(/\n/g, '')) + captionsData = jasmine.stubbedCaption + $('.subtitles li[data-index]').each (index, link) => + expect($(link)).toHaveData 'index', index + expect($(link)).toHaveData 'start', captionsData.start[index] + expect($(link)).toHaveText captionsData.text[index] it 'add a padding element to caption', -> expect($('.subtitles li:first')).toBe '.spacing' @@ -66,9 +73,11 @@ xdescribe 'VideoCaption', -> expect(@caption.rendered).toBeTruthy() describe 'when on a touch-based device', -> + beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + window.onTouchBasedDevice.andReturn true + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption it 'show explaination message', -> expect($('.subtitles li')).toHaveHtml "Caption will be displayed when you start playing the video." @@ -77,12 +86,15 @@ xdescribe 'VideoCaption', -> expect(@caption.rendered).toBeFalsy() describe 'mouse movement', -> + beforeEach -> - spyOn(window, 'setTimeout').andReturn 100 + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption + window.setTimeout.andReturn(100) spyOn window, 'clearTimeout' - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' describe 'when cursor is outside of the caption box', -> + beforeEach -> $(window).trigger jQuery.Event 'mousemove' @@ -90,6 +102,7 @@ xdescribe 'VideoCaption', -> expect(@caption.frozen).toBeFalsy() describe 'when cursor is in the caption box', -> + beforeEach -> $('.subtitles').trigger jQuery.Event 'mouseenter' @@ -143,8 +156,10 @@ xdescribe 'VideoCaption', -> expect($.fn.scrollTo).not.toHaveBeenCalled() describe 'search', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption it 'return a correct caption index', -> expect(@caption.search(0)).toEqual 0 @@ -157,17 +172,17 @@ xdescribe 'VideoCaption', -> describe 'play', -> describe 'when the caption was not rendered', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + window.onTouchBasedDevice.andReturn true + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption @caption.play() it 'render the caption', -> - expect($('.subtitles').html()).toMatch new RegExp( - '''
  • Caption at 0
  • ''' + - '''
  • Caption at 10000
  • ''' + - '''
  • Caption at 20000
  • ''' + - '''
  • Caption at 30000
  • ''' - ) + captionsData = jasmine.stubbedCaption + $('.subtitles li[data-index]').each (index, link) => + expect($(link)).toHaveData 'index', index + expect($(link)).toHaveData 'start', captionsData.start[index] + expect($(link)).toHaveText captionsData.text[index] it 'add a padding element to caption', -> expect($('.subtitles li:first')).toBe '.spacing' @@ -185,7 +200,8 @@ xdescribe 'VideoCaption', -> describe 'pause', -> beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption @caption.playing = true @caption.pause() @@ -193,8 +209,10 @@ xdescribe 'VideoCaption', -> expect(@caption.playing).toBeFalsy() describe 'updatePlayTime', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption describe 'when the video speed is 1.0x', -> beforeEach -> @@ -240,26 +258,29 @@ xdescribe 'VideoCaption', -> expect($('.subtitles li[data-index=1]')).toHaveClass 'current' describe 'resize', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption $('.subtitles li[data-index=1]').addClass 'current' @caption.resize() it 'set the height of caption container', -> - expect(parseInt($('.subtitles').css('maxHeight'))).toEqual $('.video-wrapper').height() + expect(parseInt($('.subtitles').css('maxHeight'))).toBeCloseTo $('.video-wrapper').height(), 2 it 'set the height of caption spacing', -> - expect(parseInt($('.subtitles .spacing:first').css('height'))).toEqual( - $('.video-wrapper').height() / 2 - $('.subtitles li:not(.spacing):first').height() / 2) - expect(parseInt($('.subtitles .spacing:last').css('height'))).toEqual( - $('.video-wrapper').height() / 2 - $('.subtitles li:not(.spacing):last').height() / 2) + expect(Math.abs(parseInt($('.subtitles .spacing:first').css('height')) - @caption.topSpacingHeight())).toBeLessThan 1 + expect(Math.abs(parseInt($('.subtitles .spacing:last').css('height')) - @caption.bottomSpacingHeight())).toBeLessThan 1 + it 'scroll caption to new position', -> expect($.fn.scrollTo).toHaveBeenCalled() describe 'scrollCaption', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption describe 'when frozen', -> beforeEach -> @@ -291,15 +312,17 @@ xdescribe 'VideoCaption', -> offset: - ($('.video-wrapper').height() / 2 - $('.subtitles .current:first').height() / 2) describe 'seekPlayer', -> + beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption @time = null $(@caption).bind 'seek', (event, time) => @time = time describe 'when the video speed is 1.0x', -> beforeEach -> @caption.currentSpeed = '1.0' - $('.subtitles li[data-start="30000"]').click() + $('.subtitles li[data-start="30000"]').trigger('click') it 'trigger seek event with the correct time', -> expect(@time).toEqual 30.000 @@ -307,14 +330,15 @@ xdescribe 'VideoCaption', -> describe 'when the video speed is not 1.0x', -> beforeEach -> @caption.currentSpeed = '0.75' - $('.subtitles li[data-start="30000"]').click() + $('.subtitles li[data-start="30000"]').trigger('click') it 'trigger seek event with the correct time', -> expect(@time).toEqual 40.000 describe 'toggle', -> beforeEach -> - @caption = new VideoCaption el: $('.video'), youtubeId: 'def456', currentSpeed: '1.0' + @player = jasmine.stubVideoPlayer @ + @caption = @player.caption $('.subtitles li[data-index=1]').addClass 'current' describe 'when the caption is visible', -> @@ -325,7 +349,6 @@ xdescribe 'VideoCaption', -> it 'hide the caption', -> expect(@caption.el).toHaveClass 'closed' - describe 'when the caption is hidden', -> beforeEach -> @caption.el.addClass 'closed' diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_control_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_control_spec.coffee index 7603d5777f06..e15b0c856acc 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_control_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_control_spec.coffee @@ -1,53 +1,44 @@ -# TODO: figure out why failing -xdescribe 'VideoControl', -> +describe 'VideoControl', -> beforeEach -> - jasmine.stubVideoPlayer @ + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn false + loadFixtures 'video.html' $('.video-controls').html '' describe 'constructor', -> + it 'render the video controls', -> - new VideoControl(el: $('.video-controls')) - expect($('.video-controls').html()).toContain ''' -
    -
    - - -
    - ''' + @control = new window.VideoControl(el: $('.video-controls')) + expect($('.video-controls')).toContain + ['.slider', 'ul.vcr', 'a.play', '.vidtime', '.add-fullscreen'].join(',') + expect($('.video-controls').find('.vidtime')).toHaveText '0:00 / 0:00' it 'bind the playback button', -> - control = new VideoControl(el: $('.video-controls')) - expect($('.video_control')).toHandleWith 'click', control.togglePlayback + @control = new window.VideoControl(el: $('.video-controls')) + expect($('.video_control')).toHandleWith 'click', @control.togglePlayback describe 'when on a touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true + window.onTouchBasedDevice.andReturn true + @control = new window.VideoControl(el: $('.video-controls')) it 'does not add the play class to video control', -> - new VideoControl(el: $('.video-controls')) expect($('.video_control')).not.toHaveClass 'play' expect($('.video_control')).not.toHaveHtml 'Play' describe 'when on a non-touch based device', -> + beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn false + @control = new window.VideoControl(el: $('.video-controls')) it 'add the play class to video control', -> - new VideoControl(el: $('.video-controls')) expect($('.video_control')).toHaveClass 'play' expect($('.video_control')).toHaveHtml 'Play' describe 'play', -> + beforeEach -> - @control = new VideoControl(el: $('.video-controls')) + @control = new window.VideoControl(el: $('.video-controls')) @control.play() it 'switch playback button to play state', -> @@ -56,8 +47,9 @@ xdescribe 'VideoControl', -> expect($('.video_control')).toHaveHtml 'Pause' describe 'pause', -> + beforeEach -> - @control = new VideoControl(el: $('.video-controls')) + @control = new window.VideoControl(el: $('.video-controls')) @control.pause() it 'switch playback button to pause state', -> @@ -66,8 +58,9 @@ xdescribe 'VideoControl', -> expect($('.video_control')).toHaveHtml 'Play' describe 'togglePlayback', -> + beforeEach -> - @control = new VideoControl(el: $('.video-controls')) + @control = new window.VideoControl(el: $('.video-controls')) describe 'when the control does not have play or pause class', -> beforeEach -> diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_player_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_player_spec.coffee index b6c562c88a14..dab8c0815a10 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_player_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_player_spec.coffee @@ -1,6 +1,9 @@ -# TODO: figure out why failing -xdescribe 'VideoPlayer', -> +describe 'VideoPlayer', -> beforeEach -> + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn false + # It tries to call methods of VideoProgressSlider on Spy + for part in ['VideoCaption', 'VideoSpeedControl', 'VideoVolumeControl', 'VideoProgressSlider', 'VideoControl'] + spyOn(window[part].prototype, 'initialize').andCallThrough() jasmine.stubVideoPlayer @, [], false afterEach -> @@ -8,7 +11,6 @@ xdescribe 'VideoPlayer', -> describe 'constructor', -> beforeEach -> - spyOn window, 'VideoControl' spyOn YT, 'Player' $.fn.qtip.andCallFake -> $(this).data('qtip', true) @@ -22,32 +24,47 @@ xdescribe 'VideoPlayer', -> expect(@player.currentTime).toEqual 0 it 'set the element', -> - expect(@player.el).toBe '#video_example' + expect(@player.el).toHaveId 'video_id' it 'create video control', -> - expect(window.VideoControl).toHaveBeenCalledWith el: $('.video-controls', @player.el) + expect(window.VideoControl.prototype.initialize).toHaveBeenCalled() + expect(@player.control).toBeDefined() + expect(@player.control.el).toBe $('.video-controls', @player.el) it 'create video caption', -> - expect(window.VideoCaption).toHaveBeenCalledWith el: @player.el, youtubeId: 'normalSpeedYoutubeId', currentSpeed: '1.0' + expect(window.VideoCaption.prototype.initialize).toHaveBeenCalled() + expect(@player.caption).toBeDefined() + expect(@player.caption.el).toBe @player.el + expect(@player.caption.youtubeId).toEqual 'normalSpeedYoutubeId' + expect(@player.caption.currentSpeed).toEqual '1.0' + expect(@player.caption.captionAssetPath).toEqual '/static/subs/' it 'create video speed control', -> - expect(window.VideoSpeedControl).toHaveBeenCalledWith el: $('.secondary-controls', @player.el), speeds: ['0.75', '1.0'], currentSpeed: '1.0' + expect(window.VideoSpeedControl.prototype.initialize).toHaveBeenCalled() + expect(@player.speedControl).toBeDefined() + expect(@player.speedControl.el).toBe $('.secondary-controls', @player.el) + expect(@player.speedControl.speeds).toEqual ['0.75', '1.0'] + expect(@player.speedControl.currentSpeed).toEqual '1.0' it 'create video progress slider', -> - expect(window.VideoProgressSlider).toHaveBeenCalledWith el: $('.slider', @player.el) + expect(window.VideoSpeedControl.prototype.initialize).toHaveBeenCalled() + expect(@player.progressSlider).toBeDefined() + expect(@player.progressSlider.el).toBe $('.slider', @player.el) it 'create Youtube player', -> - expect(YT.Player).toHaveBeenCalledWith('example', { + expect(YT.Player).toHaveBeenCalledWith('id', { playerVars: controls: 0 wmode: 'transparent' rel: 0 showinfo: 0 enablejsapi: 1 + modestbranding: 1 videoId: 'normalSpeedYoutubeId' events: onReady: @player.onReady onStateChange: @player.onStateChange + onPlaybackQualityChange: @player.onPlaybackQualityChange }) it 'bind to video control play event', -> @@ -69,14 +86,13 @@ xdescribe 'VideoPlayer', -> expect($(@player.volumeControl)).toHandleWith 'volumeChange', @player.onVolumeChange it 'bind to key press', -> - expect($(document)).toHandleWith 'keyup', @player.bindExitFullScreen + expect($(document.documentElement)).toHandleWith 'keyup', @player.bindExitFullScreen it 'bind to fullscreen switching button', -> expect($('.add-fullscreen')).toHandleWith 'click', @player.toggleFullScreen describe 'when not on a touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn false $('.add-fullscreen, .hide-subtitles').removeData 'qtip' @player = new VideoPlayer video: @video @@ -85,11 +101,13 @@ xdescribe 'VideoPlayer', -> expect($('.hide-subtitles')).toHaveData 'qtip' it 'create video volume control', -> - expect(window.VideoVolumeControl).toHaveBeenCalledWith el: $('.secondary-controls', @player.el) + expect(window.VideoVolumeControl.prototype.initialize).toHaveBeenCalled() + expect(@player.volumeControl).toBeDefined() + expect(@player.volumeControl.el).toBe $('.secondary-controls', @player.el) describe 'when on a touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true + window.onTouchBasedDevice.andReturn true $('.add-fullscreen, .hide-subtitles').removeData 'qtip' @player = new VideoPlayer video: @video @@ -98,7 +116,8 @@ xdescribe 'VideoPlayer', -> expect($('.hide-subtitles')).not.toHaveData 'qtip' it 'does not create video volume control', -> - expect(window.VideoVolumeControl).not.toHaveBeenCalled() + expect(window.VideoVolumeControl.prototype.initialize).not.toHaveBeenCalled() + expect(@player.volumeControl).not.toBeDefined() describe 'onReady', -> beforeEach -> @@ -110,7 +129,6 @@ xdescribe 'VideoPlayer', -> describe 'when not on a touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn false spyOn @player, 'play' @player.onReady() @@ -119,7 +137,7 @@ xdescribe 'VideoPlayer', -> describe 'when on a touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true + window.onTouchBasedDevice.andReturn true spyOn @player, 'play' @player.onReady() @@ -347,9 +365,6 @@ xdescribe 'VideoPlayer', -> it 'replace the full screen button tooltip', -> expect($('.add-fullscreen')).toHaveAttr 'title', 'Exit fill browser' - it 'add a new exit from fullscreen button', -> - expect(@player.el).toContain 'a.exit' - it 'add the fullscreen class', -> expect(@player.el).toHaveClass 'fullscreen' @@ -438,7 +453,7 @@ xdescribe 'VideoPlayer', -> describe 'volume', -> beforeEach -> - @player = new VideoPlayer @video + @player = new VideoPlayer video: @video @player.player.getVolume.andReturn 42 describe 'without value', -> diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_progress_slider_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_progress_slider_spec.coffee index 99b675b1d73a..bf6dada93b39 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_progress_slider_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_progress_slider_spec.coffee @@ -1,31 +1,30 @@ -# TODO: figure out why failing -xdescribe 'VideoProgressSlider', -> +describe 'VideoProgressSlider', -> beforeEach -> - jasmine.stubVideoPlayer @ + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn false describe 'constructor', -> describe 'on a non-touch based device', -> beforeEach -> spyOn($.fn, 'slider').andCallThrough() - spyOn(window, 'onTouchBasedDevice').andReturn false - @slider = new VideoProgressSlider el: $('.slider') + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider it 'build the slider', -> - expect(@slider.slider).toBe '.slider' + expect(@progressSlider.slider).toBe '.slider' expect($.fn.slider).toHaveBeenCalledWith range: 'min' - change: @slider.onChange - slide: @slider.onSlide - stop: @slider.onStop + change: @progressSlider.onChange + slide: @progressSlider.onSlide + stop: @progressSlider.onStop it 'build the seek handle', -> - expect(@slider.handle).toBe '.slider .ui-slider-handle' + expect(@progressSlider.handle).toBe '.slider .ui-slider-handle' expect($.fn.qtip).toHaveBeenCalledWith content: "0:00" position: my: 'bottom center' at: 'top center' - container: @slider.handle + container: @progressSlider.handle hide: delay: 700 style: @@ -34,47 +33,51 @@ xdescribe 'VideoProgressSlider', -> describe 'on a touch-based device', -> beforeEach -> + window.onTouchBasedDevice.andReturn true spyOn($.fn, 'slider').andCallThrough() - spyOn(window, 'onTouchBasedDevice').andReturn true - @slider = new VideoProgressSlider el: $('.slider') + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider it 'does not build the slider', -> - expect(@slider.slider).toBeUndefined + expect(@progressSlider.slider).toBeUndefined expect($.fn.slider).not.toHaveBeenCalled() describe 'play', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') - spyOn($.fn, 'slider').andCallThrough() + spyOn(VideoProgressSlider.prototype, 'buildSlider').andCallThrough() + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider describe 'when the slider was already built', -> + beforeEach -> - @slider.play() + @progressSlider.play() it 'does not build the slider', -> - expect($.fn.slider).not.toHaveBeenCalled + expect(@progressSlider.buildSlider.calls.length).toEqual 1 describe 'when the slider was not already built', -> beforeEach -> - @slider.slider = null - @slider.play() + spyOn($.fn, 'slider').andCallThrough() + @progressSlider.slider = null + @progressSlider.play() it 'build the slider', -> - expect(@slider.slider).toBe '.slider' + expect(@progressSlider.slider).toBe '.slider' expect($.fn.slider).toHaveBeenCalledWith range: 'min' - change: @slider.onChange - slide: @slider.onSlide - stop: @slider.onStop + change: @progressSlider.onChange + slide: @progressSlider.onSlide + stop: @progressSlider.onStop it 'build the seek handle', -> - expect(@slider.handle).toBe '.ui-slider-handle' + expect(@progressSlider.handle).toBe '.ui-slider-handle' expect($.fn.qtip).toHaveBeenCalledWith content: "0:00" position: my: 'bottom center' at: 'top center' - container: @slider.handle + container: @progressSlider.handle hide: delay: 700 style: @@ -83,21 +86,23 @@ xdescribe 'VideoProgressSlider', -> describe 'updatePlayTime', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') - spyOn($.fn, 'slider').andCallThrough() + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider describe 'when frozen', -> beforeEach -> - @slider.frozen = true - @slider.updatePlayTime 20, 120 + spyOn($.fn, 'slider').andCallThrough() + @progressSlider.frozen = true + @progressSlider.updatePlayTime 20, 120 it 'does not update the slider', -> expect($.fn.slider).not.toHaveBeenCalled() describe 'when not frozen', -> beforeEach -> - @slider.frozen = false - @slider.updatePlayTime 20, 120 + spyOn($.fn, 'slider').andCallThrough() + @progressSlider.frozen = false + @progressSlider.updatePlayTime 20, 120 it 'update the max value of the slider', -> expect($.fn.slider).toHaveBeenCalledWith 'option', 'max', 120 @@ -107,55 +112,58 @@ xdescribe 'VideoProgressSlider', -> describe 'onSlide', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider @time = null - $(@slider).bind 'seek', (event, time) => @time = time - spyOnEvent @slider, 'seek' - @slider.onSlide {}, value: 20 + $(@progressSlider).bind 'seek', (event, time) => @time = time + spyOnEvent @progressSlider, 'seek' + @progressSlider.onSlide {}, value: 20 it 'freeze the slider', -> - expect(@slider.frozen).toBeTruthy() + expect(@progressSlider.frozen).toBeTruthy() it 'update the tooltip', -> expect($.fn.qtip).toHaveBeenCalled() it 'trigger seek event', -> - expect('seek').toHaveBeenTriggeredOn @slider + expect('seek').toHaveBeenTriggeredOn @progressSlider expect(@time).toEqual 20 describe 'onChange', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') - @slider.onChange {}, value: 20 + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider + @progressSlider.onChange {}, value: 20 it 'update the tooltip', -> expect($.fn.qtip).toHaveBeenCalled() describe 'onStop', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider @time = null - $(@slider).bind 'seek', (event, time) => @time = time - spyOnEvent @slider, 'seek' - spyOn(window, 'setTimeout') - @slider.onStop {}, value: 20 + $(@progressSlider).bind 'seek', (event, time) => @time = time + spyOnEvent @progressSlider, 'seek' + @progressSlider.onStop {}, value: 20 it 'freeze the slider', -> - expect(@slider.frozen).toBeTruthy() + expect(@progressSlider.frozen).toBeTruthy() it 'trigger seek event', -> - expect('seek').toHaveBeenTriggeredOn @slider + expect('seek').toHaveBeenTriggeredOn @progressSlider expect(@time).toEqual 20 it 'set timeout to unfreeze the slider', -> expect(window.setTimeout).toHaveBeenCalledWith jasmine.any(Function), 200 window.setTimeout.mostRecentCall.args[0]() - expect(@slider.frozen).toBeFalsy() + expect(@progressSlider.frozen).toBeFalsy() describe 'updateTooltip', -> beforeEach -> - @slider = new VideoProgressSlider el: $('.slider') - @slider.updateTooltip 90 + @player = jasmine.stubVideoPlayer @ + @progressSlider = @player.progressSlider + @progressSlider.updateTooltip 90 it 'set the tooltip value', -> expect($.fn.qtip).toHaveBeenCalledWith 'option', 'content.text', '1:30' diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_speed_control_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_speed_control_spec.coffee index a7af239094f9..687f90e03071 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_speed_control_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_speed_control_spec.coffee @@ -1,6 +1,6 @@ -# TODO: figure out why failing -xdescribe 'VideoSpeedControl', -> +describe 'VideoSpeedControl', -> beforeEach -> + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn false jasmine.stubVideoPlayer @ $('.speeds').remove() @@ -10,22 +10,23 @@ xdescribe 'VideoSpeedControl', -> @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0' it 'add the video speed control to player', -> - expect($('.secondary-controls').html()).toContain ''' -
    - -

    Speed

    -

    1.0x

    -
    -
    1. 1.0x
    2. 0.75x
    -
    - ''' + secondaryControls = $('.secondary-controls') + li = secondaryControls.find('.video_speeds li') + expect(secondaryControls).toContain '.speeds' + expect(secondaryControls).toContain '.video_speeds' + expect(secondaryControls.find('p.active').text()).toBe '1.0x' + expect(li.filter('.active')).toHaveData 'speed', @speedControl.currentSpeed + expect(li.length).toBe @speedControl.speeds.length + $.each li.toArray().reverse(), (index, link) => + expect($(link)).toHaveData 'speed', @speedControl.speeds[index] + expect($(link).find('a').text()).toBe @speedControl.speeds[index] + 'x' it 'bind to change video speed link', -> expect($('.video_speeds a')).toHandleWith 'click', @speedControl.changeVideoSpeed describe 'when running on touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn true + window.onTouchBasedDevice.andReturn true $('.speeds').removeClass 'open' @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0' @@ -37,7 +38,6 @@ xdescribe 'VideoSpeedControl', -> describe 'when running on non-touch based device', -> beforeEach -> - spyOn(window, 'onTouchBasedDevice').andReturn false $('.speeds').removeClass 'open' @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0' diff --git a/common/lib/xmodule/xmodule/js/spec/video/display/video_volume_control_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display/video_volume_control_spec.coffee index 41ac5dd3e401..a2b14afa5553 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display/video_volume_control_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display/video_volume_control_spec.coffee @@ -1,5 +1,4 @@ -# TODO: figure out why failing -xdescribe 'VideoVolumeControl', -> +describe 'VideoVolumeControl', -> beforeEach -> jasmine.stubVideoPlayer @ $('.volume').remove() diff --git a/common/lib/xmodule/xmodule/js/spec/video/display_spec.coffee b/common/lib/xmodule/xmodule/js/spec/video/display_spec.coffee index ac90310519bb..a83fa3905cb2 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/display_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/video/display_spec.coffee @@ -1,12 +1,20 @@ -# TODO: figure out why failing -xdescribe 'Video', -> +describe 'Video', -> + metadata = undefined + beforeEach -> loadFixtures 'video.html' jasmine.stubRequests() - @videosDefinition = '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId' + @videosDefinition = '0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId' @slowerSpeedYoutubeId = 'slowerSpeedYoutubeId' @normalSpeedYoutubeId = 'normalSpeedYoutubeId' + metadata = + slowerSpeedYoutubeId: + id: @slowerSpeedYoutubeId + duration: 300 + normalSpeedYoutubeId: + id: @normalSpeedYoutubeId + duration: 200 afterEach -> window.player = undefined @@ -16,17 +24,18 @@ xdescribe 'Video', -> beforeEach -> @stubVideoPlayer = jasmine.createSpy('VideoPlayer') $.cookie.andReturn '0.75' - window.player = 100 + window.player = undefined describe 'by default', -> beforeEach -> - @video = new Video 'example', @videosDefinition - + spyOn(window.Video.prototype, 'fetchMetadata').andCallFake -> + @metadata = metadata + @video = new Video '#example', @videosDefinition it 'reset the current video player', -> expect(window.player).toBeNull() it 'set the elements', -> - expect(@video.el).toBe '#video_example' + expect(@video.el).toBe '#video_id' it 'parse the videos', -> expect(@video.videos).toEqual @@ -34,13 +43,8 @@ xdescribe 'Video', -> '1.0': @normalSpeedYoutubeId it 'fetch the video metadata', -> - expect(@video.metadata).toEqual - slowerSpeedYoutubeId: - id: @slowerSpeedYoutubeId - duration: 300 - normalSpeedYoutubeId: - id: @normalSpeedYoutubeId - duration: 200 + expect(@video.fetchMetadata).toHaveBeenCalled + expect(@video.metadata).toEqual metadata it 'parse available video speeds', -> expect(@video.speeds).toEqual ['0.75', '1.0'] @@ -56,7 +60,7 @@ xdescribe 'Video', -> @originalYT = window.YT window.YT = { Player: true } spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer) - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition afterEach -> window.YT = @originalYT @@ -69,7 +73,7 @@ xdescribe 'Video', -> beforeEach -> @originalYT = window.YT window.YT = {} - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition afterEach -> window.YT = @originalYT @@ -82,7 +86,7 @@ xdescribe 'Video', -> @originalYT = window.YT window.YT = {} spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer) - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition window.onYouTubePlayerAPIReady() afterEach -> @@ -95,7 +99,7 @@ xdescribe 'Video', -> describe 'youtubeId', -> beforeEach -> $.cookie.andReturn '1.0' - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition describe 'with speed', -> it 'return the video id for given speed', -> @@ -108,7 +112,7 @@ xdescribe 'Video', -> describe 'setSpeed', -> beforeEach -> - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition describe 'when new speed is available', -> beforeEach -> @@ -129,14 +133,14 @@ xdescribe 'Video', -> describe 'getDuration', -> beforeEach -> - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition it 'return duration for current video', -> expect(@video.getDuration()).toEqual 200 describe 'log', -> beforeEach -> - @video = new Video 'example', @videosDefinition + @video = new Video '#example', @videosDefinition @video.setSpeed '1.0' spyOn Logger, 'log' @video.player = { currentTime: 25 } @@ -144,7 +148,7 @@ xdescribe 'Video', -> it 'call the logger with valid parameters', -> expect(Logger.log).toHaveBeenCalledWith 'someEvent', - id: 'example' + id: 'id' code: @normalSpeedYoutubeId currentTime: 25 speed: '1.0' diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee index bf3ec1e1029c..c72067b0dc45 100644 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee +++ b/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee @@ -37,7 +37,7 @@ class @VideoCaption extends Subview @loaded = true if onTouchBasedDevice() - $('.subtitles li').html "Caption will be displayed when you start playing the video." + $('.subtitles').html "
  • Caption will be displayed when you start playing the video.
  • " else @renderCaption() diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee index 561ca07c8a3f..73ff3512e2aa 100644 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee +++ b/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee @@ -15,7 +15,7 @@ class @VideoPlayer extends Subview $(@progressSlider).bind('seek', @onSeek) if @volumeControl $(@volumeControl).bind('volumeChange', @onVolumeChange) - $(document).keyup @bindExitFullScreen + $(document.documentElement).keyup @bindExitFullScreen @$('.add-fullscreen').click @toggleFullScreen @addToolTip() unless onTouchBasedDevice() diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee index 874756cb7196..ef2f38698b60 100644 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee +++ b/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee @@ -11,7 +11,7 @@ class @VideoProgressSlider extends Subview @buildHandle() buildHandle: -> - @handle = @$('.slider .ui-slider-handle') + @handle = @$('.ui-slider-handle') @handle.qtip content: "#{Time.format(@slider.slider('value'))}" position: diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py index f902a9665bef..994611c67619 100644 --- a/common/lib/xmodule/xmodule/video_module.py +++ b/common/lib/xmodule/xmodule/video_module.py @@ -1,3 +1,6 @@ +# pylint: disable=W0223 +"""Video is ungraded Xmodule for support video content.""" + import json import logging @@ -8,7 +11,6 @@ from xmodule.x_module import XModule from xmodule.raw_module import RawDescriptor -from xmodule.contentstore.content import StaticContent from xblock.core import Integer, Scope, String import datetime @@ -18,21 +20,26 @@ class VideoFields(object): + """Fields for `VideoModule` and `VideoDescriptor`.""" data = String(help="XML data for the problem", scope=Scope.content) position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) class VideoModule(VideoFields, XModule): + """Video Xmodule.""" video_time = 0 icon_class = 'video' - js = {'coffee': - [resource_string(__name__, 'js/src/time.coffee'), - resource_string(__name__, 'js/src/video/display.coffee')] + + js = { + 'coffee': [ + resource_string(__name__, 'js/src/time.coffee'), + resource_string(__name__, 'js/src/video/display.coffee') + ] + [resource_string(__name__, 'js/src/video/display/' + filename) for filename in sorted(resource_listdir(__name__, 'js/src/video/display')) - if filename.endswith('.coffee')]} + if filename.endswith('.coffee')] + } css = {'scss': [resource_string(__name__, 'css/video/display.scss')]} js_module_name = "Video" @@ -44,14 +51,14 @@ def __init__(self, *args, **kwargs): self.show_captions = xmltree.get('show_captions', 'true') self.source = self._get_source(xmltree) self.track = self._get_track(xmltree) - self.start_time, self.end_time = self._get_timeframe(xmltree) + self.start_time, self.end_time = self.get_timeframe(xmltree) def _get_source(self, xmltree): - # find the first valid source + """Find the first valid source.""" return self._get_first_external(xmltree, 'source') def _get_track(self, xmltree): - # find the first valid track + """Find the first valid track.""" return self._get_first_external(xmltree, 'track') def _get_first_external(self, xmltree, tag): @@ -68,59 +75,44 @@ def _get_first_external(self, xmltree, tag): break return result - def _get_timeframe(self, xmltree): + def get_timeframe(self, xmltree): """ Converts 'from' and 'to' parameters in video tag to seconds. If there are no parameters, returns empty string. """ - def parse_time(s): + def parse_time(str_time): """Converts s in '12:34:45' format to seconds. If s is None, returns empty string""" - if s is None: + if str_time is None: return '' else: - x = time.strptime(s, '%H:%M:%S') - return datetime.timedelta(hours=x.tm_hour, - minutes=x.tm_min, - seconds=x.tm_sec).total_seconds() + obj_time = time.strptime(str_time, '%H:%M:%S') + return datetime.timedelta( + hours=obj_time.tm_hour, + minutes=obj_time.tm_min, + seconds=obj_time.tm_sec + ).total_seconds() return parse_time(xmltree.get('from')), parse_time(xmltree.get('to')) def handle_ajax(self, dispatch, get): - ''' - Handle ajax calls to this video. - TODO (vshnayder): This is not being called right now, so the position - is not being saved. - ''' + """This is not being called right now and we raise 404 error.""" log.debug(u"GET {0}".format(get)) log.debug(u"DISPATCH {0}".format(dispatch)) - if dispatch == 'goto_position': - self.position = int(float(get['position'])) - log.info(u"NEW POSITION {0}".format(self.position)) - return json.dumps({'success': True}) raise Http404() - def get_progress(self): - ''' TODO (vshnayder): Get and save duration of youtube video, then return - fraction watched. - (Be careful to notice when video link changes and update) - - For now, we have no way of knowing if the video has even been watched, so - just return None. - ''' - return None - def get_instance_state(self): - #log.debug(u"STATE POSITION {0}".format(self.position)) + """Return information about state (position).""" return json.dumps({'position': self.position}) def video_list(self): + """Return video list.""" return self.youtube def get_html(self): # We normally let JS parse this, but in the case that we need a hacked # out player because YouTube has broken their