diff --git a/common/djangoapps/terrain/stubs/youtube.py b/common/djangoapps/terrain/stubs/youtube.py index c0df85565e..fc68cc3da0 100644 --- a/common/djangoapps/terrain/stubs/youtube.py +++ b/common/djangoapps/terrain/stubs/youtube.py @@ -83,7 +83,7 @@ class StubYouTubeHandler(StubHttpRequestHandler): 'duration': 60, }) }) - response = callback + '({})'.format(json.dumps(data)) + response = "{cb}({data})".format(cb=callback, data=json.dumps(data)) self.send_response(200, content=response, headers={'Content-type': 'text/html'}) self.log_message("Youtube: sent response {}".format(message)) diff --git a/common/lib/xmodule/xmodule/js/spec/helper.coffee b/common/lib/xmodule/xmodule/js/spec/helper.coffee deleted file mode 100644 index 0456e8d0c9..0000000000 --- a/common/lib/xmodule/xmodule/js/spec/helper.coffee +++ /dev/null @@ -1,177 +0,0 @@ -# Stub Youtube API -window.YT = - Player: -> - getDuration: -> - 60 - PlayerState: - UNSTARTED: -1 - ENDED: 0 - PLAYING: 1 - PAUSED: 2 - BUFFERING: 3 - CUED: 5 - ready: (f) -> f() - -window.STATUS = window.YT.PlayerState - -oldAjaxWithPrefix = window.jQuery.ajaxWithPrefix - -window.onTouchBasedDevice = -> - navigator.userAgent.match /iPhone|iPod|iPad/i - -jasmine.stubbedCaption = - end: [3120, 6270, 8490, 21620, 24920, 25750, 27900, 34380, 35550, 40250] - start: [1180, 3120, 6270, 14910, 21620, 24920, 25750, 27900, 34380, 35550] - text: [ - "MICHAEL CIMA: So let's do the first one here.", - "Vacancies, where do they come from?", - "Well, imagine a perfect crystal.", - "Now we know at any temperature other than absolute zero there's enough", - "energy going around that some atoms will have more energy", - "than others, right?", - "There's a distribution.", - "If I plot energy here and number, these atoms in the crystal will have a", - "distribution of energy.", - "And some will have quite a bit of energy, just for a moment." - ] - -# For our purposes, we need to make sure that the function $.ajaxWithPrefix -# does not fail when during tests a captions file is requested. -# It is originally defined in -# -# common/static/coffee/src/ajax_prefix.js -# -# We will replace it with a function that does: -# -# 1.) Return a hard coded captions object if the file name contains 'Z5KLxerq05Y'. -# 2.) Behaves the same a as the origianl in all other cases. - -window.jQuery.ajaxWithPrefix = (url, settings) -> - if not settings - settings = url - url = settings.url - success = settings.success - data = settings.data - - if url.match(/Z5KLxerq05Y/g) isnt null or url.match(/7tqY6eQzVhE/g) isnt null or url.match(/cogebirgzzM/g) isnt null - if window.jQuery.isFunction(success) is true - success jasmine.stubbedCaption - else if window.jQuery.isFunction(data) is true - data jasmine.stubbedCaption - else - oldAjaxWithPrefix.apply @, arguments - -# Time waitsFor() should wait for before failing a test. -window.WAIT_TIMEOUT = 5000 - -jasmine.getFixtures().fixturesPath += 'fixtures' - -jasmine.stubbedMetadata = - '7tqY6eQzVhE': - id: '7tqY6eQzVhE' - duration: 300 - 'cogebirgzzM': - id: 'cogebirgzzM' - duration: 200 - bogus: - duration: 100 - -jasmine.fireEvent = (el, eventName) -> - if document.createEvent - event = document.createEvent "HTMLEvents" - event.initEvent eventName, true, true - else - event = document.createEventObject() - event.eventType = eventName - event.eventName = eventName - if document.createEvent - el.dispatchEvent(event) - else - el.fireEvent("on" + event.eventType, event) - -jasmine.stubbedHtml5Speeds = ['0.75', '1.0', '1.25', '1.50'] - -jasmine.stubRequests = -> - spyOn($, 'ajax').andCallFake (settings) -> - if match = settings.url.match /youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/ - status = match[1].split('_') - if status and status[0] is 'status' - { - always: (callback) -> - callback.call(window, {}, status[1]) - error: (callback) -> - callback.call(window, {}, status[1]) - done: (callback) -> - callback.call(window, {}, status[1]) - } - else if settings.success - # match[1] - it's video ID - settings.success data: jasmine.stubbedMetadata[match[1]] - else { - always: (callback) -> - callback.call(window, {}, 'success') - done: (callback) -> - callback.call(window, {}, 'success') - } - 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') - else if settings.url == '/calculate' || - settings.url.match(/.+\/goto_position$/) || - settings.url.match(/event$/) || - settings.url.match(/.+\/problem_(check|reset|show|save)$/) - # do nothing - else - throw "External request attempted for #{settings.url}, which is not defined." - -jasmine.stubYoutubePlayer = -> - YT.Player = -> - obj = jasmine.createSpyObj 'YT.Player', ['cueVideoById', 'getVideoEmbedCode', - 'getCurrentTime', 'getPlayerState', 'getVolume', 'setVolume', 'loadVideoById', - 'playVideo', 'pauseVideo', 'seekTo', 'getDuration', 'getAvailablePlaybackRates', 'setPlaybackRate'] - obj['getDuration'] = jasmine.createSpy('getDuration').andReturn 60 - obj['getAvailablePlaybackRates'] = jasmine.createSpy('getAvailablePlaybackRates').andReturn [0.75, 1.0, 1.25, 1.5] - obj - -jasmine.stubVideoPlayer = (context, enableParts, html5=false) -> - suite = context.suite - currentPartName = suite.description while suite = suite.parentSuite - if html5 == false - loadFixtures 'video.html' - else - loadFixtures 'video_html5.html' - jasmine.stubRequests() - YT.Player = undefined - window.OldVideoPlayer = undefined - jasmine.stubYoutubePlayer() - return new Video '#example', '.75:7tqY6eQzVhE,1.0:cogebirgzzM' - -# Add custom matchers -beforeEach -> - @addMatchers - toHaveAttrs: (attrs) -> - element = @.actual - result = true - if $.isEmptyObject attrs - return false - $.each attrs, (name, value) -> - result = result && element.attr(name) == value - return result - - toBeInRange: (min, max) -> - return min <= @.actual && @.actual <= max - - toBeInArray: (array) -> - return $.inArray(@.actual, array) > -1 - - @addMatchers imagediff.jasmine - -# Stub jQuery.cookie -$.cookie = jasmine.createSpy('jQuery.cookie').andReturn '1.0' - -# Stub jQuery.qtip -$.fn.qtip = jasmine.createSpy 'jQuery.qtip' - -# Stub jQuery.scrollTo -$.fn.scrollTo = jasmine.createSpy 'jQuery.scrollTo' diff --git a/common/lib/xmodule/xmodule/js/spec/helper.js b/common/lib/xmodule/xmodule/js/spec/helper.js new file mode 100644 index 0000000000..8194b97992 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/spec/helper.js @@ -0,0 +1,290 @@ +(function ($, undefined) { + var oldAjaxWithPrefix = $.ajaxWithPrefix; + + // Stub YouTube API. + window.YT = { + Player: function () { + var Player = jasmine.createSpyObj( + 'YT.Player', + [ + 'cueVideoById', 'getVideoEmbedCode', 'getCurrentTime', + 'getPlayerState', 'getVolume', 'setVolume', + 'loadVideoById', 'getAvailablePlaybackRates', 'playVideo', + 'pauseVideo', 'seekTo', 'getDuration', 'setPlaybackRate', + 'getPlaybackQuality' + ] + ); + + Player.getDuration.andReturn(60); + Player.getAvailablePlaybackRates.andReturn(['0.50', '1.0', '1.50', '2.0']); + + return Player; + }, + + PlayerState: { + UNSTARTED: -1, + ENDED: 0, + PLAYING: 1, + PAUSED: 2, + BUFFERING: 3, + CUED: 5 + }, + ready: function (f) { + return f(); + } + }; + + window.STATUS = window.YT.PlayerState; + + window.onTouchBasedDevice = function () { + return navigator.userAgent.match(/iPhone|iPod|iPad/i); + }; + + jasmine.stubbedCaption = { + end: [ + 3120, 6270, 8490, 21620, 24920, 25750, 27900, 34380, 35550, 40250 + ], + start: [ + 1180, 3120, 6270, 14910, 21620, 24920, 25750, 27900, 34380, 35550 + ], + text: [ + 'MICHAEL CIMA: So let\'s do the first one here.', + 'Vacancies, where do they come from?', + 'Well, imagine a perfect crystal.', + 'Now we know at any temperature other than absolute zero ' + + 'there\'s enough', + 'energy going around that some atoms will have more energy', + 'than others, right?', + 'There\'s a distribution.', + 'If I plot energy here and number, these atoms in the crystal ' + + 'will have a', + 'distribution of energy.', + 'And some will have quite a bit of energy, just for a moment.' + ] + }; + + // For our purposes, we need to make sure that the function + // $.ajaxWithPrefix does not fail when during tests a captions file is + // requested. It is originally defined in file: + // + // common/static/coffee/src/ajax_prefix.js + // + // We will replace it with a function that does: + // + // 1.) Return a hard coded captions object if the file name contains + // 'Z5KLxerq05Y'. + // 2.) Behaves the same a as the original function in all other cases. + $.ajaxWithPrefix = function (url, settings) { + var data, success; + + if (!settings) { + settings = url; + url = settings.url; + success = settings.success; + data = settings.data; + } + + if ( + url.match(/Z5KLxerq05Y/g) || + url.match(/7tqY6eQzVhE/g) || + url.match(/cogebirgzzM/g) + ) { + if ($.isFunction(success)) { + return success(jasmine.stubbedCaption); + } else if ($.isFunction(data)) { + return data(jasmine.stubbedCaption); + } + } else { + return oldAjaxWithPrefix.apply(this, arguments); + } + }; + + // Time waitsFor() should wait for before failing a test. + window.WAIT_TIMEOUT = 5000; + + jasmine.getFixtures().fixturesPath += 'fixtures'; + + jasmine.stubbedMetadata = { + '7tqY6eQzVhE': { + id: '7tqY6eQzVhE', + duration: 300 + }, + 'cogebirgzzM': { + id: 'cogebirgzzM', + duration: 200 + }, + bogus: { + duration: 100 + } + }; + + jasmine.fireEvent = function (el, eventName) { + var event; + + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent(eventName, true, true); + } else { + event = document.createEventObject(); + event.eventType = eventName; + } + + event.eventName = eventName; + + if (document.createEvent) { + el.dispatchEvent(event); + } else { + el.fireEvent('on' + event.eventType, event); + } + }; + + jasmine.stubbedHtml5Speeds = ['0.75', '1.0', '1.25', '1.50']; + + jasmine.stubRequests = function () { + return spyOn($, 'ajax').andCallFake(function (settings) { + var match, status, callCallback; + + if ( + match = settings.url + .match(/youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/) + ) { + status = match[1].split('_'); + if (status && status[0] === 'status') { + callCallback = function (callback) { + callback.call(window, {}, status[1]); + }; + + return { + always: callCallback, + error: callCallback, + done: callCallback + }; + } else if (settings.success) { + return settings.success({ + data: jasmine.stubbedMetadata[match[1]] + }); + } else { + return { + always: function (callback) { + return callback.call(window, {}, 'success'); + }, + done: function (callback) { + return callback.call(window, {}, 'success'); + } + }; + } + } else if ( + match = settings.url + .match(/static(\/.*)?\/subs\/(.+)\.srt\.sjson/) + ) { + return settings.success(jasmine.stubbedCaption); + } else if (settings.url.match(/.+\/problem_get$/)) { + return settings.success({ + html: readFixtures('problem_content.html') + }); + } else if ( + settings.url === '/calculate' || + settings.url.match(/.+\/goto_position$/) || + settings.url.match(/event$/) || + settings.url.match(/.+\/problem_(check|reset|show|save)$/) + ) { + // Do nothing. + } else { + throw 'External request attempted for ' + + settings.url + + ', which is not defined.'; + } + }); + }; + + // Add custom Jasmine matchers. + beforeEach(function () { + this.addMatchers({ + toHaveAttrs: function (attrs) { + var element = this.actual, + result = true; + + if ($.isEmptyObject(attrs)) { + return false; + } + + $.each(attrs, function (name, value) { + return result = result && element.attr(name) === value; + }); + + return result; + }, + toBeInRange: function (min, max) { + return min <= this.actual && this.actual <= max; + }, + toBeInArray: function (array) { + return $.inArray(this.actual, array) > -1; + } + }); + + return this.addMatchers(imagediff.jasmine); + }); + + // Stub jQuery.cookie module. + $.cookie = jasmine.createSpy('jQuery.cookie').andReturn('1.0'); + + // # Stub jQuery.qtip module. + $.fn.qtip = jasmine.createSpy('jQuery.qtip'); + + // Stub jQuery.scrollTo module. + $.fn.scrollTo = jasmine.createSpy('jQuery.scrollTo'); + + jasmine.initializePlayer = function (fixture, params) { + var state; + + if (_.isString(fixture)) { + // `fixture` is a name of a fixture file. + loadFixtures(fixture); + } else { + // `fixture` is not a string. The first parameter is an object? + if (_.isObject(fixture)) { + // The first parameter contains attributes for the main video + // DIV element. + params = fixture; + } + + // "video_all.html" is the default HTML template for HTML5 video. + loadFixtures('video_all.html'); + } + + // If `params` is an object, assign it's properties as data attributes + // to the main video DIV element. + if (_.isObject(params)) { + $('#example') + .find('#video_id') + .data(params); + } + + state = new Video('#example'); + + state.resizer = (function () { + var methods = [ + 'align', + 'alignByWidthOnly', + 'alignByHeightOnly', + 'setParams', + 'setMode' + ], + obj = {}; + + $.each(methods, function (index, method) { + obj[method] = jasmine.createSpy(method).andReturn(obj); + }); + + return obj; + }()); + + // We return the `state` object of the newly initialized Video. + return state; + }; + + jasmine.initializePlayerYouTube = function () { + // "video.html" contains HTML template for a YouTube video. + return jasmine.initializePlayer('video.html'); + }; +}).call(this, window.jQuery); diff --git a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js index 54a856dbe7..20fa4fc00a 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js @@ -1,165 +1,108 @@ -(function () { +(function (undefined) { describe('VideoPlayer Events', function () { - var state, videoPlayer, player, videoControl, videoCaption, - videoProgressSlider, videoSpeedControl, videoVolumeControl, - oldOTBD; + var state, oldOTBD; - function initialize(fixture, params) { - if (_.isString(fixture)) { - loadFixtures(fixture); - } else { - if (_.isObject(fixture)) { - params = fixture; - } + describe('HTML5', function () { + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine + .createSpy('onTouchBasedDevice') + .andReturn(null); - loadFixtures('video_all.html'); - } + jasmine.stubRequests(); - if (_.isObject(params)) { - $('#example') - .find('#video_id') - .data(params); - } + state = jasmine.initializePlayer(); - state = new Video('#example'); + state.videoEl = $('video, iframe'); + }); - state.videoEl = $('video, iframe'); - videoPlayer = state.videoPlayer; - player = videoPlayer.player; - videoControl = state.videoControl; - videoCaption = state.videoCaption; - videoProgressSlider = state.videoProgressSlider; - videoSpeedControl = state.videoSpeedControl; - videoVolumeControl = state.videoVolumeControl; + afterEach(function () { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; + }); - state.resizer = (function () { - var methods = [ - 'align', - 'alignByWidthOnly', - 'alignByHeightOnly', - 'setParams', - 'setMode' - ], - obj = {}; + it('initialize', function () { + waitsFor(function () { + return state.el.hasClass('is-initialized'); + }, 'Player is not initialized.', WAIT_TIMEOUT); - $.each(methods, function (index, method) { - obj[method] = jasmine.createSpy(method).andReturn(obj); + runs(function () { + expect('initialize').not.toHaveBeenTriggeredOn('.video'); + }); + }); + + it('ready', function () { + waitsFor(function () { + return state.el.hasClass('is-initialized'); + }, 'Player is not initialized.', WAIT_TIMEOUT); + + runs(function () { + expect('ready').not.toHaveBeenTriggeredOn('.video'); + }); + }); + + it('play', function () { + state.videoPlayer.play(); + expect('play').not.toHaveBeenTriggeredOn('.video'); + }); + + it('pause', function () { + state.videoPlayer.play(); + state.videoPlayer.pause(); + expect('pause').not.toHaveBeenTriggeredOn('.video'); + }); + + it('volumechange', function () { + state.videoPlayer.onVolumeChange(60); + + expect('volumechange').not.toHaveBeenTriggeredOn('.video'); + }); + + it('speedchange', function () { + state.videoPlayer.onSpeedChange('2.0'); + + expect('speedchange').not.toHaveBeenTriggeredOn('.video'); + }); + + it('seek', function () { + state.videoPlayer.onCaptionSeek({ + time: 1, + type: 'any' }); - return obj; - }()); - } - - function initializeYouTube() { - initialize('video.html'); - } - - beforeEach(function () { - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); - this.oldYT = window.YT; - - jasmine.stubRequests(); - window.YT = { - Player: function () { - return { - getPlaybackQuality: function () {}, - getDuration: function () { return 60; } - }; - }, - PlayerState: this.oldYT.PlayerState, - ready: function (callback) { - callback(); - } - }; - }); - - afterEach(function () { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - window.YT = this.oldYT; - }); - - it('initialize', function(){ - runs(function () { - initialize(); + expect('seek').not.toHaveBeenTriggeredOn('.video'); }); - waitsFor(function () { - return state.el.hasClass('is-initialized'); - }, 'Player is not initialized.', WAIT_TIMEOUT); + it('ended', function () { + state.videoPlayer.onEnded(); - runs(function () { - expect('initialize').not.toHaveBeenTriggeredOn('.video'); + expect('ended').not.toHaveBeenTriggeredOn('.video'); }); }); - it('ready', function() { - runs(function () { - initialize(); + describe('YouTube', function () { + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine + .createSpy('onTouchBasedDevice') + .andReturn(null); + + jasmine.stubRequests(); + + state = jasmine.initializePlayerYouTube(); }); - waitsFor(function () { - return state.el.hasClass('is-initialized'); - }, 'Player is not initialized.', WAIT_TIMEOUT); - - runs(function () { - expect('ready').not.toHaveBeenTriggeredOn('.video'); - }); - }); - - it('play', function() { - initialize(); - videoPlayer.play(); - expect('play').not.toHaveBeenTriggeredOn('.video'); - }); - - it('pause', function() { - initialize(); - videoPlayer.play(); - videoPlayer.pause(); - expect('pause').not.toHaveBeenTriggeredOn('.video'); - }); - - it('volumechange', function() { - initialize(); - videoPlayer.onVolumeChange(60); - - expect('volumechange').not.toHaveBeenTriggeredOn('.video'); - }); - - it('speedchange', function() { - initialize(); - videoPlayer.onSpeedChange('2.0'); - - expect('speedchange').not.toHaveBeenTriggeredOn('.video'); - }); - - it('qualitychange', function() { - initializeYouTube(); - videoPlayer.onPlaybackQualityChange(); - - expect('qualitychange').not.toHaveBeenTriggeredOn('.video'); - }); - - it('seek', function() { - initialize(); - videoPlayer.onCaptionSeek({ - time: 1, - type: 'any' + afterEach(function () { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; }); - expect('seek').not.toHaveBeenTriggeredOn('.video'); + it('qualitychange', function () { + state.videoPlayer.onPlaybackQualityChange(); + + expect('qualitychange').not.toHaveBeenTriggeredOn('.video'); + }); }); - - it('ended', function() { - initialize(); - videoPlayer.onEnded(); - - expect('ended').not.toHaveBeenTriggeredOn('.video'); - }); - }); }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js index dd575104b0..a1209b19f9 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js @@ -1,4 +1,4 @@ -(function () { +(function (undefined) { describe('Video', function () { var oldOTBD; @@ -10,7 +10,6 @@ }); afterEach(function () { - window.OldVideoPlayer = undefined; $('source').remove(); }); @@ -30,10 +29,6 @@ expect(this.state.videoType).toEqual('youtube'); }); - it('reset the current video player', function () { - expect(window.OldVideoPlayer).toBeUndefined(); - }); - it('set the elements', function () { expect(this.state.el).toBe('#video_id'); }); @@ -76,10 +71,6 @@ expect(state.videoType).toEqual('html5'); }); - it('reset the current video player', function () { - expect(window.OldVideoPlayer).toBeUndefined(); - }); - it('set the elements', function () { expect(state.el).toBe('#video_id'); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js index 6a2b0b8fad..bfc106bb46 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js @@ -1,12 +1,6 @@ -(function () { +(function (undefined) { describe('Video HTML5Video', function () { - var state, player, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5]; - - function initialize() { - loadFixtures('video_html5.html'); - state = new Video('#example'); - player = state.videoPlayer.player; - } + var state, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5]; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; @@ -14,7 +8,7 @@ .createSpy('onTouchBasedDevice').andReturn(null); }); - afterEach(function() { + afterEach(function () { state = undefined; $.fn.scrollTo.reset(); $('.subtitles').remove(); @@ -24,48 +18,46 @@ describe('on non-Touch devices', function () { beforeEach(function () { - initialize(); - player.config.events.onReady = jasmine.createSpy('onReady'); + state = jasmine.initializePlayer('video_html5.html'); + + state.videoPlayer.player.config.events.onReady = jasmine.createSpy('onReady'); }); describe('events:', function () { beforeEach(function () { - spyOn(player, 'callStateChangeCallback').andCallThrough(); + spyOn(state.videoPlayer.player, 'callStateChangeCallback').andCallThrough(); }); describe('[click]', function () { describe('when player is paused', function () { beforeEach(function () { - spyOn(player.video, 'play').andCallThrough(); - player.playerState = STATUS.PAUSED; - $(player.videoEl).trigger('click'); + spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); + state.videoPlayer.player.playerState = STATUS.PAUSED; + $(state.videoPlayer.player.videoEl).trigger('click'); }); it('native play event was called', function () { - expect(player.video.play).toHaveBeenCalled(); + expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); it('player state was changed', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.PAUSED; + return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.getPlayerState()) + expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PLAYING); }); }); it('callback was called', function () { waitsFor(function () { - var stateStatus = state.videoPlayer.player - .getPlayerState(); - - return stateStatus !== STATUS.PAUSED; + return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.callStateChangeCallback) + expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }); }); @@ -73,33 +65,33 @@ describe('[player is playing]', function () { beforeEach(function () { - spyOn(player.video, 'pause').andCallThrough(); - player.playerState = STATUS.PLAYING; - $(player.videoEl).trigger('click'); + spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); + state.videoPlayer.player.playerState = STATUS.PLAYING; + $(state.videoPlayer.player.videoEl).trigger('click'); }); it('native event was called', function () { - expect(player.video.pause).toHaveBeenCalled(); + expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); it('player state was changed', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.PLAYING; + return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.getPlayerState()) + expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); }); }); it('callback was called', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.PLAYING; + return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.callStateChangeCallback) + expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }); }); @@ -108,37 +100,34 @@ describe('[play]', function () { beforeEach(function () { - spyOn(player.video, 'play').andCallThrough(); - player.playerState = STATUS.PAUSED; - player.playVideo(); + spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); + state.videoPlayer.player.playerState = STATUS.PAUSED; + state.videoPlayer.player.playVideo(); }); it('native event was called', function () { - expect(player.video.play).toHaveBeenCalled(); + expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); it('player state was changed', function () { waitsFor(function () { - var state = player.getPlayerState(); - - return state !== STATUS.PAUSED; + return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.getPlayerState()).toBe(STATUS.PLAYING); + expect(state.videoPlayer.player.getPlayerState()) + .toBe(STATUS.PLAYING); }); }); it('callback was called', function () { waitsFor(function () { - var state = player.getPlayerState(); - - return state !== STATUS.PAUSED; + return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.callStateChangeCallback) + expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }); }); @@ -146,35 +135,36 @@ describe('[pause]', function () { beforeEach(function () { - spyOn(player.video, 'pause').andCallThrough(); - player.playerState = STATUS.UNSTARTED; - player.playVideo(); + spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); + state.videoPlayer.player.playerState = STATUS.UNSTARTED; + state.videoPlayer.player.playVideo(); waitsFor(function () { - return player.getPlayerState() !== STATUS.UNSTARTED; + return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; }, 'Video never started playing', WAIT_TIMEOUT); - player.pauseVideo(); + state.videoPlayer.player.pauseVideo(); }); it('native event was called', function () { - expect(player.video.pause).toHaveBeenCalled(); + expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); it('player state was changed', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.PLAYING; + return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.getPlayerState()).toBe(STATUS.PAUSED); + expect(state.videoPlayer.player.getPlayerState()) + .toBe(STATUS.PAUSED); }); }); it('callback was called', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.PLAYING; + return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; }, 'Player state should be changed', WAIT_TIMEOUT); runs(function () { - expect(player.callStateChangeCallback) + expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }); }); @@ -186,13 +176,14 @@ 'onReady called', function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.UNSTARTED; + return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; }, 'Video cannot be played', WAIT_TIMEOUT); runs(function () { - expect(player.getPlayerState()).toBe(STATUS.PAUSED); - expect(player.video.currentTime).toBe(0); - expect(player.config.events.onReady) + expect(state.videoPlayer.player.getPlayerState()) + .toBe(STATUS.PAUSED); + expect(state.videoPlayer.player.video.currentTime).toBe(0); + expect(state.videoPlayer.player.config.events.onReady) .toHaveBeenCalled(); }); }); @@ -201,20 +192,21 @@ describe('[ended]', function () { beforeEach(function () { waitsFor(function () { - return player.getPlayerState() !== STATUS.UNSTARTED; + return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; }, 'Video cannot be played', WAIT_TIMEOUT); }); it('player state was changed', function () { runs(function () { - jasmine.fireEvent(player.video, 'ended'); - expect(player.getPlayerState()).toBe(STATUS.ENDED); + jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); }); }); it('callback was called', function () { - jasmine.fireEvent(player.video, 'ended'); - expect(player.callStateChangeCallback).toHaveBeenCalled(); + jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); + expect(state.videoPlayer.player.callStateChangeCallback) + .toHaveBeenCalled(); }); }); }); @@ -224,36 +216,36 @@ beforeEach(function () { waitsFor(function () { - volume = player.video.volume; - seek = player.video.currentTime; - return player.playerState === STATUS.PAUSED; + volume = state.videoPlayer.player.video.volume; + seek = state.videoPlayer.player.video.currentTime; + return state.videoPlayer.player.playerState === STATUS.PAUSED; }, 'Video cannot be played', WAIT_TIMEOUT); }); it('pauseVideo', function () { runs(function () { - spyOn(player.video, 'pause').andCallThrough(); - player.pauseVideo(); - expect(player.video.pause).toHaveBeenCalled(); + spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); + state.videoPlayer.player.pauseVideo(); + expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); }); describe('seekTo', function () { it('set new correct value', function () { runs(function () { - player.seekTo(2); - expect(player.getCurrentTime()).toBe(2); + state.videoPlayer.player.seekTo(2); + expect(state.videoPlayer.player.getCurrentTime()).toBe(2); }); }); it('set new inccorrect values', function () { runs(function () { - player.seekTo(-50); - expect(player.getCurrentTime()).toBe(seek); - player.seekTo('5'); - expect(player.getCurrentTime()).toBe(seek); - player.seekTo(500000); - expect(player.getCurrentTime()).toBe(seek); + state.videoPlayer.player.seekTo(-50); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); + state.videoPlayer.player.seekTo('5'); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); + state.videoPlayer.player.seekTo(500000); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); }); }); }); @@ -261,88 +253,89 @@ describe('setVolume', function () { it('set new correct value', function () { runs(function () { - player.setVolume(50); - expect(player.getVolume()).toBe(50 * 0.01); + state.videoPlayer.player.setVolume(50); + expect(state.videoPlayer.player.getVolume()).toBe(50 * 0.01); }); }); it('set new incorrect values', function () { runs(function () { - player.setVolume(-50); - expect(player.getVolume()).toBe(volume); - player.setVolume('5'); - expect(player.getVolume()).toBe(volume); - player.setVolume(500000); - expect(player.getVolume()).toBe(volume); + state.videoPlayer.player.setVolume(-50); + expect(state.videoPlayer.player.getVolume()).toBe(volume); + state.videoPlayer.player.setVolume('5'); + expect(state.videoPlayer.player.getVolume()).toBe(volume); + state.videoPlayer.player.setVolume(500000); + expect(state.videoPlayer.player.getVolume()).toBe(volume); }); }); }); it('getCurrentTime', function () { runs(function () { - player.video.currentTime = 3; - expect(player.getCurrentTime()) - .toBe(player.video.currentTime); + state.videoPlayer.player.video.currentTime = 3; + expect(state.videoPlayer.player.getCurrentTime()) + .toBe(state.videoPlayer.player.video.currentTime); }); }); it('playVideo', function () { runs(function () { - spyOn(player.video, 'play').andCallThrough(); - player.playVideo(); - expect(player.video.play).toHaveBeenCalled(); + spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); + state.videoPlayer.player.playVideo(); + expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); }); it('getPlayerState', function () { runs(function () { - player.playerState = STATUS.PLAYING; - expect(player.getPlayerState()).toBe(STATUS.PLAYING); - player.playerState = STATUS.ENDED; - expect(player.getPlayerState()).toBe(STATUS.ENDED); + state.videoPlayer.player.playerState = STATUS.PLAYING; + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.PLAYING); + state.videoPlayer.player.playerState = STATUS.ENDED; + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); }); }); it('getVolume', function () { runs(function () { - volume = player.video.volume = 0.5; - expect(player.getVolume()).toBe(volume); + volume = state.videoPlayer.player.video.volume = 0.5; + expect(state.videoPlayer.player.getVolume()).toBe(volume); }); }); it('getDuration', function () { runs(function () { - duration = player.video.duration; - expect(player.getDuration()).toBe(duration); + duration = state.videoPlayer.player.video.duration; + expect(state.videoPlayer.player.getDuration()).toBe(duration); }); }); describe('setPlaybackRate', function () { it('set a correct value', function () { playbackRate = 1.5; - player.setPlaybackRate(playbackRate); - expect(player.video.playbackRate).toBe(playbackRate); + state.videoPlayer.player.setPlaybackRate(playbackRate); + expect(state.videoPlayer.player.video.playbackRate).toBe(playbackRate); }); it('set NaN value', function () { - var oldPlaybackRate = player.video.playbackRate; + var oldPlaybackRate = state.videoPlayer.player.video.playbackRate; // When we try setting the playback rate to some // non-numerical value, nothing should happen. playbackRate = NaN; - player.setPlaybackRate(playbackRate); - expect(player.video.playbackRate).toBe(oldPlaybackRate); + state.videoPlayer.player.setPlaybackRate(playbackRate); + expect(state.videoPlayer.player.video.playbackRate) + .toBe(oldPlaybackRate); }); }); it('getAvailablePlaybackRates', function () { - expect(player.getAvailablePlaybackRates()) + expect(state.videoPlayer.player.getAvailablePlaybackRates()) .toEqual(playbackRates); }); it('_getLogs', function () { runs(function () { - var logs = player._getLogs(); + var logs = state.videoPlayer.player._getLogs(); expect(logs).toEqual(jasmine.any(Array)); expect(logs.length).toBeGreaterThan(0); }); @@ -352,8 +345,10 @@ it('native controls are used on iPhone', function () { window.onTouchBasedDevice.andReturn(['iPhone']); - initialize(); - player.config.events.onReady = jasmine.createSpy('onReady'); + + state = jasmine.initializePlayer('video_html5.html'); + + state.videoPlayer.player.config.events.onReady = jasmine.createSpy('onReady'); expect($('video')).toHaveAttr('controls'); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js index eea22f5047..0b312db0c9 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js @@ -1,4 +1,4 @@ -(function (requirejs, require, define) { +(function (requirejs, require, define, undefined) { require( ['video/00_resizer.js'], @@ -104,7 +104,7 @@ function (Resizer) { beforeEach(function () { var spiesCount = _.range(3); - spiesList = $.map(spiesCount, function() { + spiesList = $.map(spiesCount, function () { return jasmine.createSpy(); }); @@ -113,13 +113,13 @@ function (Resizer) { it('callbacks are called', function () { - $.each(spiesList, function(index, spy) { + $.each(spiesList, function (index, spy) { resizer.callbacks.add(spy); }); resizer.align(); - $.each(spiesList, function(index, spy) { + $.each(spiesList, function (index, spy) { expect(spy).toHaveBeenCalled(); }); }); @@ -135,20 +135,20 @@ function (Resizer) { }); it('All callbacks are removed', function () { - $.each(spiesList, function(index, spy) { + $.each(spiesList, function (index, spy) { resizer.callbacks.add(spy); }); resizer.callbacks.removeAll(); resizer.align(); - $.each(spiesList, function(index, spy) { + $.each(spiesList, function (index, spy) { expect(spy).not.toHaveBeenCalled(); }); }); it('Specific callback is removed', function () { - $.each(spiesList, function(index, spy) { + $.each(spiesList, function (index, spy) { resizer.callbacks.add(spy); }); @@ -158,14 +158,17 @@ function (Resizer) { expect(spiesList[1]).not.toHaveBeenCalled(); }); - it('Error message is shown when wrong argument type is passed', function () { + it( + 'Error message is shown when wrong argument type is passed', + function () + { var methods = ['add', 'once'], errorMessage = 'TypeError: Argument is not a function.', arg = {}; spyOn(console, 'error'); - $.each(methods, function(index, methodName) { + $.each(methods, function (index, methodName) { resizer.callbacks[methodName](arg); expect(console.error).toHaveBeenCalledWith(errorMessage); //reset spy diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js index 3be31f458c..20a33e9138 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js @@ -1,26 +1,20 @@ -(function () { +(function (undefined) { describe('VideoCaption', function () { - var state, videoPlayer, videoCaption, videoSpeedControl, oldOTBD; - - function initialize() { - loadFixtures('video_all.html'); - state = new Video('#example'); - videoPlayer = state.videoPlayer; - videoCaption = state.videoCaption; - videoSpeedControl = state.videoSpeedControl; - videoControl = state.videoControl; - $.fn.scrollTo.reset(); - } + var state, oldOTBD; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .andReturn(null); - initialize(); + + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); afterEach(function () { - YT.Player = undefined; $('.subtitles').remove(); // `source` tags should be removed to avoid memory leak bug that we @@ -35,7 +29,12 @@ describe('always', function () { beforeEach(function () { spyOn($, 'ajaxWithPrefix').andCallThrough(); - initialize(); + + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); it('create the caption element', function () { @@ -57,7 +56,7 @@ it('fetch the caption', function () { waitsFor(function () { - if (videoCaption.loaded === true) { + if (state.videoCaption.loaded === true) { return true; } @@ -66,7 +65,7 @@ runs(function () { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ - url: videoCaption.captionURL(), + url: state.videoCaption.captionURL(), notifyOnError: false, success: jasmine.any(Function), error: jasmine.any(Function) @@ -76,37 +75,37 @@ it('bind window resize event', function () { expect($(window)).toHandleWith( - 'resize', videoCaption.resize + 'resize', state.videoCaption.resize ); }); it('bind the hide caption button', function () { expect($('.hide-subtitles')).toHandleWith( - 'click', videoCaption.toggle + 'click', state.videoCaption.toggle ); }); it('bind the mouse movement', function () { expect($('.subtitles')).toHandleWith( - 'mouseover', videoCaption.onMouseEnter + 'mouseover', state.videoCaption.onMouseEnter ); expect($('.subtitles')).toHandleWith( - 'mouseout', videoCaption.onMouseLeave + 'mouseout', state.videoCaption.onMouseLeave ); expect($('.subtitles')).toHandleWith( - 'mousemove', videoCaption.onMovement + 'mousemove', state.videoCaption.onMovement ); expect($('.subtitles')).toHandleWith( - 'mousewheel', videoCaption.onMovement + 'mousewheel', state.videoCaption.onMovement ); expect($('.subtitles')).toHandleWith( - 'DOMMouseScroll', videoCaption.onMovement + 'DOMMouseScroll', state.videoCaption.onMovement ); }); it('bind the scroll', function () { expect($('.subtitles')) - .toHandleWith('scroll', videoCaption.autoShowCaptions); + .toHandleWith('scroll', state.videoCaption.autoShowCaptions); expect($('.subtitles')) .toHandleWith('scroll', videoControl.showControls); }); @@ -114,7 +113,11 @@ describe('when on a non touch-based device', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); it('render the caption', function () { @@ -145,38 +148,43 @@ function (index, link) { expect($(link)).toHandleWith( - 'mouseover', videoCaption.captionMouseOverOut + 'mouseover', state.videoCaption.captionMouseOverOut ); expect($(link)).toHandleWith( - 'mouseout', videoCaption.captionMouseOverOut + 'mouseout', state.videoCaption.captionMouseOverOut ); expect($(link)).toHandleWith( - 'mousedown', videoCaption.captionMouseDown + 'mousedown', state.videoCaption.captionMouseDown ); expect($(link)).toHandleWith( - 'click', videoCaption.captionClick + 'click', state.videoCaption.captionClick ); expect($(link)).toHandleWith( - 'focus', videoCaption.captionFocus + 'focus', state.videoCaption.captionFocus ); expect($(link)).toHandleWith( - 'blur', videoCaption.captionBlur + 'blur', state.videoCaption.captionBlur ); expect($(link)).toHandleWith( - 'keydown', videoCaption.captionKeyDown + 'keydown', state.videoCaption.captionKeyDown ); }); }); it('set rendered to true', function () { - expect(videoCaption.rendered).toBeTruthy(); + expect(state.videoCaption.rendered).toBeTruthy(); }); }); describe('when on a touch-based device', function () { beforeEach(function () { window.onTouchBasedDevice.andReturn(['iPad']); - initialize(); + + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); it('show explaination message', function () { @@ -187,7 +195,7 @@ }); it('does not set rendered to true', function () { - expect(videoCaption.rendered).toBeFalsy(); + expect(state.videoCaption.rendered).toBeFalsy(); }); }); @@ -199,11 +207,10 @@ $('#example').find('#video_id').data('sub', ''); state = new Video('#example'); - videoCaption = state.videoCaption; }); it('captions panel is not shown', function () { - expect(videoCaption.hideSubtitlesEl).toBeHidden(); + expect(state.videoCaption.hideSubtitlesEl).toBeHidden(); }); }); }); @@ -221,20 +228,20 @@ }); it('does not set freezing timeout', function () { - expect(videoCaption.frozen).toBeFalsy(); + expect(state.videoCaption.frozen).toBeFalsy(); }); }); describe('when cursor is in the caption box', function () { beforeEach(function () { - spyOn(videoCaption, 'onMouseLeave'); + spyOn(state.videoCaption, 'onMouseLeave'); $('.subtitles').trigger(jQuery.Event('mouseenter')); jasmine.Clock.tick(state.config.captionsFreezeTime); }); it('set the freezing timeout', function () { - expect(videoCaption.frozen).not.toBeFalsy(); - expect(videoCaption.onMouseLeave).toHaveBeenCalled(); + expect(state.videoCaption.frozen).not.toBeFalsy(); + expect(state.videoCaption.onMouseLeave).toHaveBeenCalled(); }); describe('when the cursor is moving', function () { @@ -263,7 +270,7 @@ function () { beforeEach(function () { - videoCaption.frozen = 100; + state.videoCaption.frozen = 100; $.fn.scrollTo.reset(); }); @@ -277,13 +284,13 @@ }); it('unfreeze the caption', function () { - expect(videoCaption.frozen).toBeNull(); + expect(state.videoCaption.frozen).toBeNull(); }); }); describe('when the player is playing', function () { beforeEach(function () { - videoCaption.playing = true; + state.videoCaption.playing = true; $('.subtitles li[data-index]:first') .addClass('current'); $('.subtitles').trigger(jQuery.Event('mouseout')); @@ -296,7 +303,7 @@ describe('when the player is not playing', function () { beforeEach(function () { - videoCaption.playing = false; + state.videoCaption.playing = false; $('.subtitles').trigger(jQuery.Event('mouseout')); }); @@ -309,12 +316,12 @@ describe('search', function () { it('return a correct caption index', function () { - expect(videoCaption.search(0)).toEqual(-1); - expect(videoCaption.search(3120)).toEqual(1); - expect(videoCaption.search(6270)).toEqual(2); - expect(videoCaption.search(8490)).toEqual(2); - expect(videoCaption.search(21620)).toEqual(4); - expect(videoCaption.search(24920)).toEqual(5); + expect(state.videoCaption.search(0)).toEqual(-1); + expect(state.videoCaption.search(3120)).toEqual(1); + expect(state.videoCaption.search(6270)).toEqual(2); + expect(state.videoCaption.search(8490)).toEqual(2); + expect(state.videoCaption.search(21620)).toEqual(4); + expect(state.videoCaption.search(24920)).toEqual(5); }); }); @@ -322,8 +329,14 @@ describe('when the caption was not rendered', function () { beforeEach(function () { window.onTouchBasedDevice.andReturn(['iPad']); - initialize(); - videoCaption.play(); + + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); + + state.videoCaption.play(); }); it('render the caption', function () { @@ -352,78 +365,78 @@ function (index, link) { expect($(link)).toHandleWith( - 'mouseover', videoCaption.captionMouseOverOut + 'mouseover', state.videoCaption.captionMouseOverOut ); expect($(link)).toHandleWith( - 'mouseout', videoCaption.captionMouseOverOut + 'mouseout', state.videoCaption.captionMouseOverOut ); expect($(link)).toHandleWith( - 'mousedown', videoCaption.captionMouseDown + 'mousedown', state.videoCaption.captionMouseDown ); expect($(link)).toHandleWith( - 'click', videoCaption.captionClick + 'click', state.videoCaption.captionClick ); expect($(link)).toHandleWith( - 'focus', videoCaption.captionFocus + 'focus', state.videoCaption.captionFocus ); expect($(link)).toHandleWith( - 'blur', videoCaption.captionBlur + 'blur', state.videoCaption.captionBlur ); expect($(link)).toHandleWith( - 'keydown', videoCaption.captionKeyDown + 'keydown', state.videoCaption.captionKeyDown ); }); }); it('set rendered to true', function () { - expect(videoCaption.rendered).toBeTruthy(); + expect(state.videoCaption.rendered).toBeTruthy(); }); it('set playing to true', function () { - expect(videoCaption.playing).toBeTruthy(); + expect(state.videoCaption.playing).toBeTruthy(); }); }); }); describe('pause', function () { beforeEach(function () { - videoCaption.playing = true; - videoCaption.pause(); + state.videoCaption.playing = true; + state.videoCaption.pause(); }); it('set playing to false', function () { - expect(videoCaption.playing).toBeFalsy(); + expect(state.videoCaption.playing).toBeFalsy(); }); }); describe('updatePlayTime', function () { describe('when the video speed is 1.0x', function () { beforeEach(function () { - videoSpeedControl.currentSpeed = '1.0'; - videoCaption.updatePlayTime(25.000); + state.videoSpeedControl.currentSpeed = '1.0'; + state.videoCaption.updatePlayTime(25.000); }); it('search the caption based on time', function () { - expect(videoCaption.currentIndex).toEqual(5); + expect(state.videoCaption.currentIndex).toEqual(5); }); }); describe('when the video speed is not 1.0x', function () { beforeEach(function () { - videoSpeedControl.currentSpeed = '0.75'; - videoCaption.updatePlayTime(25.000); + state.videoSpeedControl.currentSpeed = '0.75'; + state.videoCaption.updatePlayTime(25.000); }); it('search the caption based on 1.0x speed', function () { - expect(videoCaption.currentIndex).toEqual(5); + expect(state.videoCaption.currentIndex).toEqual(5); }); }); describe('when the index is not the same', function () { beforeEach(function () { - videoCaption.currentIndex = 1; + state.videoCaption.currentIndex = 1; $('.subtitles li[data-index=5]').addClass('current'); - videoCaption.updatePlayTime(25.000); + state.videoCaption.updatePlayTime(25.000); }); it('deactivate the previous caption', function () { @@ -437,7 +450,7 @@ }); it('save new index', function () { - expect(videoCaption.currentIndex).toEqual(5); + expect(state.videoCaption.currentIndex).toEqual(5); }); // Disabled 11/25/13 due to flakiness in master @@ -448,9 +461,9 @@ describe('when the index is the same', function () { beforeEach(function () { - videoCaption.currentIndex = 1; + state.videoCaption.currentIndex = 1; $('.subtitles li[data-index=3]').addClass('current'); - videoCaption.updatePlayTime(15.000); + state.videoCaption.updatePlayTime(15.000); }); it('does not change current subtitle', function () { @@ -462,9 +475,14 @@ describe('resize', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); + $('.subtitles li[data-index=1]').addClass('current'); - videoCaption.resize(); + state.videoCaption.resize(); }); describe('set the height of caption container', function () { @@ -484,7 +502,7 @@ controlHeight, shouldBeHeight; state.captionsHidden = true; - videoCaption.setSubtitlesHeight(); + state.videoCaption.setSubtitlesHeight(); realHeight = parseInt( $('.subtitles').css('maxHeight'), 10 @@ -510,9 +528,9 @@ $('.subtitles .spacing:last').css('height'), 10 )); - expect(firstSpacing - videoCaption.topSpacingHeight()) + expect(firstSpacing - state.videoCaption.topSpacingHeight()) .toBeLessThan(1); - expect(lastSpacing - videoCaption.bottomSpacingHeight()) + expect(lastSpacing - state.videoCaption.bottomSpacingHeight()) .toBeLessThan(1); }); @@ -524,14 +542,18 @@ // Disabled 11/25/13 due to flakiness in master xdescribe('scrollCaption', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); describe('when frozen', function () { beforeEach(function () { - videoCaption.frozen = true; + state.videoCaption.frozen = true; $('.subtitles li[data-index=1]').addClass('current'); - videoCaption.scrollCaption(); + state.videoCaption.scrollCaption(); }); it('does not scroll the caption', function () { @@ -541,12 +563,12 @@ describe('when not frozen', function () { beforeEach(function () { - videoCaption.frozen = false; + state.videoCaption.frozen = false; }); describe('when there is no current caption', function () { beforeEach(function () { - videoCaption.scrollCaption(); + state.videoCaption.scrollCaption(); }); it('does not scroll the caption', function () { @@ -557,7 +579,7 @@ describe('when there is a current caption', function () { beforeEach(function () { $('.subtitles li[data-index=1]').addClass('current'); - videoCaption.scrollCaption(); + state.videoCaption.scrollCaption(); }); it('scroll to current caption', function () { @@ -571,24 +593,29 @@ xdescribe('seekPlayer', function () { describe('when the video speed is 1.0x', function () { beforeEach(function () { - videoSpeedControl.currentSpeed = '1.0'; + state.videoSpeedControl.currentSpeed = '1.0'; $('.subtitles li[data-start="14910"]').trigger('click'); }); it('trigger seek event with the correct time', function () { - expect(videoPlayer.currentTime).toEqual(14.91); + expect(state.videoPlayer.currentTime).toEqual(14.91); }); }); describe('when the video speed is not 1.0x', function () { beforeEach(function () { - initialize(); - videoSpeedControl.currentSpeed = '0.75'; + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); + + state.videoSpeedControl.currentSpeed = '0.75'; $('.subtitles li[data-start="14910"]').trigger('click'); }); it('trigger seek event with the correct time', function () { - expect(videoPlayer.currentTime).toEqual(14.91); + expect(state.videoPlayer.currentTime).toEqual(14.91); }); }); @@ -596,36 +623,46 @@ function () { beforeEach(function () { - initialize(); - videoSpeedControl.currentSpeed = '0.75'; + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); + + state.videoSpeedControl.currentSpeed = '0.75'; state.currentPlayerMode = 'flash'; $('.subtitles li[data-start="14910"]').trigger('click'); }); it('trigger seek event with the correct time', function () { - expect(videoPlayer.currentTime).toEqual(15); + expect(state.videoPlayer.currentTime).toEqual(15); }); }); }); describe('toggle', function () { beforeEach(function () { - initialize(); - spyOn(videoPlayer, 'log'); + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); + + spyOn(state.videoPlayer, 'log'); $('.subtitles li[data-index=1]').addClass('current'); }); describe('when the caption is visible', function () { beforeEach(function () { state.el.removeClass('closed'); - videoCaption.toggle(jQuery.Event('click')); + state.videoCaption.toggle(jQuery.Event('click')); }); it('log the hide_transcript event', function () { - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'hide_transcript', { - currentTime: videoPlayer.currentTime + currentTime: state.videoPlayer.currentTime } ); }); @@ -643,16 +680,16 @@ describe('when the caption is hidden', function () { beforeEach(function () { state.el.addClass('closed'); - videoCaption.toggle(jQuery.Event('click')); + state.videoCaption.toggle(jQuery.Event('click')); jasmine.Clock.useMock(); }); it('log the show_transcript event', function () { - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'show_transcript', { - currentTime: videoPlayer.currentTime + currentTime: state.videoPlayer.currentTime } ); }); @@ -685,12 +722,16 @@ describe('caption accessibility', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + videoControl = state.videoControl; + + $.fn.scrollTo.reset(); }); describe('when getting focus through TAB key', function () { beforeEach(function () { - videoCaption.isMouseFocus = false; + state.videoCaption.isMouseFocus = false; $('.subtitles li[data-index=0]').trigger( jQuery.Event('focus') ); @@ -702,7 +743,7 @@ }); it('has automatic scrolling disabled', function () { - expect(videoCaption.autoScrolling).toBe(false); + expect(state.videoCaption.autoScrolling).toBe(false); }); }); @@ -719,7 +760,7 @@ }); it('has automatic scrolling enabled', function () { - expect(videoCaption.autoScrolling).toBe(true); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); @@ -729,7 +770,7 @@ function () { beforeEach(function () { - videoCaption.isMouseFocus = false; + state.videoCaption.isMouseFocus = false; $('.subtitles li[data-index=0]') .trigger(jQuery.Event('focus')); $('.subtitles li[data-index=0]') @@ -742,7 +783,7 @@ }); it('has automatic scrolling enabled', function () { - expect(videoCaption.autoScrolling).toBe(true); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); @@ -757,12 +798,12 @@ subDataLiIdx__0 = $('.subtitles li[data-index=0]'); subDataLiIdx__1 = $('.subtitles li[data-index=1]'); - videoCaption.isMouseFocus = false; + state.videoCaption.isMouseFocus = false; subDataLiIdx__0.trigger(jQuery.Event('focus')); subDataLiIdx__0.trigger(jQuery.Event('blur')); - videoCaption.isMouseFocus = true; + state.videoCaption.isMouseFocus = true; subDataLiIdx__1.trigger(jQuery.Event('mousedown')); }); @@ -776,7 +817,7 @@ }); it('has automatic scrolling enabled', function () { - expect(videoCaption.autoScrolling).toBe(true); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js index 246430a28b..20dfdebce1 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js @@ -1,292 +1,310 @@ -(function() { - describe('VideoControl', function() { - var state, videoControl, oldOTBD; +(function (undefined) { + describe('VideoControl', function () { + var state, oldOTBD; - function initialize(fixture) { - if (fixture) { - loadFixtures(fixture); - } else { - loadFixtures('video_all.html'); - } - state = new Video('#example'); - videoControl = state.videoControl; - } + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine + .createSpy('onTouchBasedDevice').andReturn(null); + }); - function initializeYouTube() { - initialize('video.html'); - } + afterEach(function () { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; + }); - beforeEach(function(){ - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null); + describe('constructor', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + }); + + it('render the video controls', function () { + expect($('.video-controls')).toContain( + [ + '.slider', + 'ul.vcr', + 'a.play', + '.vidtime', + '.add-fullscreen' + ].join(',') + ); + + expect($('.video-controls').find('.vidtime')) + .toHaveText('0:00 / 0:00'); + }); + + it('add ARIA attributes to time control', function () { + var timeControl = $('div.slider>a'); + + expect(timeControl).toHaveAttrs({ + 'role': 'slider', + 'title': 'video position', + 'aria-disabled': 'false' + }); + + expect(timeControl).toHaveAttr('aria-valuetext'); + }); + + it('add ARIA attributes to play control', function () { + var playControl = $('ul.vcr a'); + + expect(playControl).toHaveAttrs({ + 'role': 'button', + 'title': 'Play', + 'aria-disabled': 'false' + }); + }); + + it('add ARIA attributes to fullscreen control', function () { + var fullScreenControl = $('a.add-fullscreen'); + + expect(fullScreenControl).toHaveAttrs({ + 'role': 'button', + 'title': 'Fill browser', + 'aria-disabled': 'false' + }); + }); + + it('bind the playback button', function () { + expect($('.video_control')).toHandleWith( + 'click', + state.videoControl.togglePlayback + ); + }); + + describe('when on a non-touch based device', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + }); + + it('add the play class to video control', function () { + expect($('.video_control')).toHaveClass('play'); + expect($('.video_control')).toHaveAttr( + 'title', 'Play' + ); + }); + }); + + describe('when on a touch based device', function () { + beforeEach(function () { + window.onTouchBasedDevice.andReturn(['iPad']); + state = jasmine.initializePlayer(); + }); + + it( + 'does not add the play class to video control', + function () + { + expect($('.video_control')).toHaveClass('play'); + expect($('.video_control')).toHaveAttr( + 'title', 'Play' + ); + }); + }); + }); + + describe('play', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + state.videoControl.play(); + }); + + it('switch playback button to play state', function () { + expect($('.video_control')).not.toHaveClass('play'); + expect($('.video_control')).toHaveClass('pause'); + expect($('.video_control')).toHaveAttr('title', 'Pause'); + }); + }); + + describe('pause', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + state.videoControl.pause(); + }); + + it('switch playback button to pause state', function () { + expect($('.video_control')).not.toHaveClass('pause'); + expect($('.video_control')).toHaveClass('play'); + expect($('.video_control')).toHaveAttr('title', 'Play'); + }); + }); + + describe('togglePlayback', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + }); + + describe( + 'when the control does not have play or pause class', + function () + { + beforeEach(function () { + $('.video_control').removeClass('play') + .removeClass('pause'); + }); + + describe('when the video is playing', function () { + beforeEach(function () { + $('.video_control').addClass('play'); + spyOnEvent(state.videoControl, 'pause'); + state.videoControl.togglePlayback(jQuery.Event('click')); + }); + + it('does not trigger the pause event', function () { + expect('pause').not + .toHaveBeenTriggeredOn(state.videoControl); + }); + }); + + describe('when the video is paused', function () { + beforeEach(function () { + $('.video_control').addClass('pause'); + spyOnEvent(state.videoControl, 'play'); + state.videoControl.togglePlayback(jQuery.Event('click')); + }); + + it('does not trigger the play event', function () { + expect('play').not + .toHaveBeenTriggeredOn(state.videoControl); + }); + }); + }); + }); + + describe('Play placeholder', function () { + var cases = [ + { + name: 'PC', + isShown: false, + isTouch: null + }, { + name: 'iPad', + isShown: true, + isTouch: ['iPad'] + }, { + name: 'Android', + isShown: true, + isTouch: ['Android'] + }, { + name: 'iPhone', + isShown: false, + isTouch: ['iPhone'] + } + ]; + + beforeEach(function () { + jasmine.stubRequests(); + + spyOn(window.YT, 'Player').andCallThrough(); + }); + + it ('works correctly on calling proper methods', function () { + var btnPlay; + + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); + + state.videoControl.showPlayPlaceholder(); + + expect(btnPlay).not.toHaveClass('is-hidden'); + expect(btnPlay).toHaveAttrs({ + 'aria-hidden': 'false', + 'tabindex': 0 + }); + + state.videoControl.hidePlayPlaceholder(); + + expect(btnPlay).toHaveClass('is-hidden'); + expect(btnPlay).toHaveAttrs({ + 'aria-hidden': 'true', + 'tabindex': -1 + }); + }); + + $.each(cases, function (index, data) { + var message = [ + (data.isShown) ? 'is' : 'is not', + ' shown on', + data.name + ].join(''); + + it(message, function () { + var btnPlay; + + window.onTouchBasedDevice.andReturn(data.isTouch); + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); + + if (data.isShown) { + expect(btnPlay).not.toHaveClass('is-hidden'); + } else { + expect(btnPlay).toHaveClass('is-hidden'); + } + }); + }); + + $.each(['iPad', 'Android'], function (index, device) { + it( + 'is shown on paused video on ' + device + + ' in HTML5 player', + function () + { + var btnPlay; + + window.onTouchBasedDevice.andReturn([device]); + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); + + state.videoControl.play(); + state.videoControl.pause(); + + expect(btnPlay).not.toHaveClass('is-hidden'); + }); + + it( + 'is hidden on playing video on ' + device + + ' in HTML5 player', + function () + { + var btnPlay; + + window.onTouchBasedDevice.andReturn([device]); + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); + + state.videoControl.play(); + + expect(btnPlay).toHaveClass('is-hidden'); + }); + + it( + 'is hidden on paused video on ' + device + + ' in YouTube player', + function () + { + var btnPlay; + + window.onTouchBasedDevice.andReturn([device]); + state = jasmine.initializePlayerYouTube(); + btnPlay = state.el.find('.btn-play'); + + state.videoControl.play(); + state.videoControl.pause(); + + expect(btnPlay).toHaveClass('is-hidden'); + }); + }); + }); + + it('show', function () { + var controls; + + state = jasmine.initializePlayer(); + controls = state.el.find('.video-controls'); + controls.addClass('is-hidden'); + + state.videoControl.show(); + expect(controls).not.toHaveClass('is-hidden'); + }); }); - - afterEach(function() { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - }); - - describe('constructor', function() { - beforeEach(function() { - initialize(); - }); - - it('render the video controls', function() { - expect($('.video-controls')).toContain( - ['.slider', 'ul.vcr', 'a.play', '.vidtime', '.add-fullscreen'].join(',') - ); - expect($('.video-controls').find('.vidtime')).toHaveText('0:00 / 0:00'); - }); - - it('add ARIA attributes to time control', function () { - var timeControl = $('div.slider>a'); - expect(timeControl).toHaveAttrs({ - 'role': 'slider', - 'title': 'video position', - 'aria-disabled': 'false' - }); - expect(timeControl).toHaveAttr('aria-valuetext'); - }); - - it('add ARIA attributes to play control', function () { - var playControl = $('ul.vcr a'); - expect(playControl).toHaveAttrs({ - 'role': 'button', - 'title': 'Play', - 'aria-disabled': 'false' - }); - }); - - it('add ARIA attributes to fullscreen control', function () { - var fullScreenControl = $('a.add-fullscreen'); - expect(fullScreenControl).toHaveAttrs({ - 'role': 'button', - 'title': 'Fill browser', - 'aria-disabled': 'false' - }); - }); - - it('bind the playback button', function() { - expect($('.video_control')).toHandleWith('click', videoControl.togglePlayback); - }); - - describe('when on a non-touch based device', function() { - beforeEach(function() { - initialize(); - }); - - it('add the play class to video control', function() { - expect($('.video_control')).toHaveClass('play'); - expect($('.video_control')).toHaveAttr('title', 'Play'); - }); - }); - - describe('when on a touch based device', function() { - beforeEach(function() { - window.onTouchBasedDevice.andReturn(['iPad']); - initialize(); - }); - - it('does not add the play class to video control', function() { - expect($('.video_control')).toHaveClass('play'); - expect($('.video_control')).toHaveAttr('title', 'Play'); - }); - }); - }); - - describe('play', function() { - beforeEach(function() { - initialize(); - videoControl.play(); - }); - - it('switch playback button to play state', function() { - expect($('.video_control')).not.toHaveClass('play'); - expect($('.video_control')).toHaveClass('pause'); - expect($('.video_control')).toHaveAttr('title', 'Pause'); - }); - }); - - describe('pause', function() { - beforeEach(function() { - initialize(); - videoControl.pause(); - }); - - it('switch playback button to pause state', function() { - expect($('.video_control')).not.toHaveClass('pause'); - expect($('.video_control')).toHaveClass('play'); - expect($('.video_control')).toHaveAttr('title', 'Play'); - }); - }); - - describe('togglePlayback', function() { - beforeEach(function() { - initialize(); - }); - - describe('when the control does not have play or pause class', function() { - beforeEach(function() { - $('.video_control').removeClass('play').removeClass('pause'); - }); - - describe('when the video is playing', function() { - beforeEach(function() { - $('.video_control').addClass('play'); - spyOnEvent(videoControl, 'pause'); - videoControl.togglePlayback(jQuery.Event('click')); - }); - - it('does not trigger the pause event', function() { - expect('pause').not.toHaveBeenTriggeredOn(videoControl); - }); - }); - - describe('when the video is paused', function() { - beforeEach(function() { - $('.video_control').addClass('pause'); - spyOnEvent(videoControl, 'play'); - videoControl.togglePlayback(jQuery.Event('click')); - }); - - it('does not trigger the play event', function() { - expect('play').not.toHaveBeenTriggeredOn(videoControl); - }); - }); - }); - }); - - describe('Play placeholder', function () { - - beforeEach(function () { - this.oldYT = window.YT; - - jasmine.stubRequests(); - window.YT = { - Player: function () { - return { getDuration: function () { return 60; } }; - }, - PlayerState: this.oldYT.PlayerState, - ready: function (callback) { - callback(); - } - }; - - spyOn(window.YT, 'Player').andCallThrough(); - }); - - afterEach(function () { - window.YT = this.oldYT; - }); - - - it ('works correctly on calling proper methods', function () { - initialize(); - var btnPlay = state.el.find('.btn-play'); - - videoControl.showPlayPlaceholder(); - - expect(btnPlay).not.toHaveClass('is-hidden'); - expect(btnPlay).toHaveAttrs({ - 'aria-hidden': 'false', - 'tabindex': 0 - }); - - videoControl.hidePlayPlaceholder(); - - expect(btnPlay).toHaveClass('is-hidden'); - expect(btnPlay).toHaveAttrs({ - 'aria-hidden': 'true', - 'tabindex': -1 - }); - }); - - var cases = [ - { - name: 'PC', - isShown: false, - isTouch: null - }, - { - name: 'iPad', - isShown: true, - isTouch: ['iPad'] - }, - { - name: 'Android', - isShown: true, - isTouch: ['Android'] - }, - { - name: 'iPhone', - isShown: false, - isTouch: ['iPhone'] - } - ]; - - $.each(cases, function(index, data) { - var message = [ - (data.isShown) ? 'is' : 'is not', - ' shown on', - data.name - ].join(''); - - it(message, function () { - window.onTouchBasedDevice.andReturn(data.isTouch); - initialize(); - var btnPlay = state.el.find('.btn-play'); - - if (data.isShown) { - expect(btnPlay).not.toHaveClass('is-hidden'); - } else { - expect(btnPlay).toHaveClass('is-hidden'); - } - }); - }); - - $.each(['iPad', 'Android'], function(index, device) { - it('is shown on paused video on '+ device +' in HTML5 player', function () { - window.onTouchBasedDevice.andReturn([device]); - initialize(); - var btnPlay = state.el.find('.btn-play'); - - videoControl.play(); - videoControl.pause(); - - expect(btnPlay).not.toHaveClass('is-hidden'); - }); - - it('is hidden on playing video on '+ device +' in HTML5 player', function () { - window.onTouchBasedDevice.andReturn([device]); - initialize(); - var btnPlay = state.el.find('.btn-play'); - - videoControl.play(); - - expect(btnPlay).toHaveClass('is-hidden'); - }); - - it('is hidden on paused video on '+ device +' in YouTube player', function () { - window.onTouchBasedDevice.andReturn([device]); - initializeYouTube(); - var btnPlay = state.el.find('.btn-play'); - - videoControl.play(); - videoControl.pause(); - - expect(btnPlay).toHaveClass('is-hidden'); - }); - }); - }); - - it('show', function () { - initialize(); - var controls = state.el.find('.video-controls'); - controls.addClass('is-hidden'); - - videoControl.show(); - expect(controls).not.toHaveClass('is-hidden'); - }); - }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js index 71cf4f45c4..ab3c12df6f 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js @@ -1,4 +1,4 @@ -(function () { +(function (undefined) { describe('Video FocusGrabber', function () { var state; diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js index 47ddf7d57d..fcbfac2f70 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js @@ -1,58 +1,6 @@ -(function () { +(function (undefined) { describe('VideoPlayer', function () { - var state, videoPlayer, player, videoControl, videoCaption, - videoProgressSlider, videoSpeedControl, videoVolumeControl, - oldOTBD; - - function initialize(fixture, params) { - if (_.isString(fixture)) { - loadFixtures(fixture); - } else { - if (_.isObject(fixture)) { - params = fixture; - } - - loadFixtures('video_all.html'); - } - - if (_.isObject(params)) { - $('#example') - .find('#video_id') - .data(params); - } - - state = new Video('#example'); - - state.videoEl = $('video, iframe'); - videoPlayer = state.videoPlayer; - player = videoPlayer.player; - videoControl = state.videoControl; - videoCaption = state.videoCaption; - videoProgressSlider = state.videoProgressSlider; - videoSpeedControl = state.videoSpeedControl; - videoVolumeControl = state.videoVolumeControl; - - state.resizer = (function () { - var methods = [ - 'align', - 'alignByWidthOnly', - 'alignByHeightOnly', - 'setParams', - 'setMode' - ], - obj = {}; - - $.each(methods, function (index, method) { - obj[method] = jasmine.createSpy(method).andReturn(obj); - }); - - return obj; - }()); - } - - function initializeYouTube() { - initialize('video.html'); - } + var state, oldOTBD; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; @@ -68,11 +16,13 @@ describe('constructor', function () { describe('always', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); }); it('instanticate current time to zero', function () { - expect(videoPlayer.currentTime).toEqual(0); + expect(state.videoPlayer.currentTime).toEqual(0); }); it('set the element', function () { @@ -80,12 +30,12 @@ }); it('create video control', function () { - expect(videoControl).toBeDefined(); - expect(videoControl.el).toHaveClass('video-controls'); + expect(state.videoControl).toBeDefined(); + expect(state.videoControl.el).toHaveClass('video-controls'); }); it('create video caption', function () { - expect(videoCaption).toBeDefined(); + expect(state.videoCaption).toBeDefined(); expect(state.youtubeId()).toEqual('Z5KLxerq05Y'); expect(state.speed).toEqual('1.0'); expect(state.config.caption_asset_path) @@ -93,16 +43,16 @@ }); it('create video speed control', function () { - expect(videoSpeedControl).toBeDefined(); - expect(videoSpeedControl.el).toHaveClass('speeds'); - expect(videoSpeedControl.speeds) + expect(state.videoSpeedControl).toBeDefined(); + expect(state.videoSpeedControl.el).toHaveClass('speeds'); + expect(state.videoSpeedControl.speeds) .toEqual([ '0.75', '1.0', '1.25', '1.50' ]); expect(state.speed).toEqual('1.0'); }); it('create video progress slider', function () { - expect(videoProgressSlider).toBeDefined(); - expect(videoProgressSlider.el).toHaveClass('slider'); + expect(state.videoProgressSlider).toBeDefined(); + expect(state.videoProgressSlider.el).toHaveClass('slider'); }); // All the toHandleWith() expect tests are not necessary for @@ -112,28 +62,20 @@ }); it('create Youtube player', function () { - var oldYT = window.YT, events; + var events; jasmine.stubRequests(); - window.YT = { - Player: function () { - return { getDuration: function () { return 60; } }; - }, - PlayerState: oldYT.PlayerState, - ready: function (callback) { - callback(); - } - }; - spyOn(window.YT, 'Player').andCallThrough(); - initializeYouTube(); + state = jasmine.initializePlayerYouTube(); + + state.videoEl = $('video, iframe'); events = { - onReady: videoPlayer.onReady, - onStateChange: videoPlayer.onStateChange, - onPlaybackQualityChange: videoPlayer + onReady: state.videoPlayer.onReady, + onStateChange: state.videoPlayer.onStateChange, + onPlaybackQualityChange: state.videoPlayer .onPlaybackQualityChange }; @@ -150,8 +92,6 @@ videoId: 'cogebirgzzM', events: events }); - - window.YT = oldYT; }); // We can't test the invocation of HTML5Video because it is not @@ -159,11 +99,14 @@ // JS. describe('when on a touch based device', function () { - $.each(['iPad', 'Android'], function(index, device) { - it('create video volume control on' + device, function() { + $.each(['iPad', 'Android'], function (index, device) { + it('create video volume control on' + device, function () { window.onTouchBasedDevice.andReturn([device]); - initialize(); - expect(videoVolumeControl).toBeUndefined(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + expect(state.videoVolumeControl).toBeUndefined(); expect(state.el.find('div.volume')).not.toExist(); }); }); @@ -173,52 +116,58 @@ var oldOTBD; beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); }); it('controls are in paused state', function () { - expect(videoControl.isPlaying).toBe(false); + expect(state.videoControl.isPlaying).toBe(false); }); }); }); describe('onReady', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoPlayer, 'log').andCallThrough(); - spyOn(videoPlayer, 'play').andCallThrough(); - videoPlayer.onReady(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'log').andCallThrough(); + spyOn(state.videoPlayer, 'play').andCallThrough(); + state.videoPlayer.onReady(); }); it('log the load_video event', function () { - expect(videoPlayer.log).toHaveBeenCalledWith('load_video'); + expect(state.videoPlayer.log).toHaveBeenCalledWith('load_video'); }); it('autoplay the first video', function () { - expect(videoPlayer.play).not.toHaveBeenCalled(); + expect(state.videoPlayer.play).not.toHaveBeenCalled(); }); }); describe('onStateChange', function () { describe('when the video is unstarted', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoControl, 'pause').andCallThrough(); - spyOn(videoCaption, 'pause').andCallThrough(); + state.videoEl = $('video, iframe'); - videoPlayer.onStateChange({ - data: YT.PlayerState.PAUSED + spyOn(state.videoControl, 'pause').andCallThrough(); + spyOn(state.videoCaption, 'pause').andCallThrough(); + + state.videoPlayer.onStateChange({ + data: YT.PlayerState.PAUSED }); }); it('pause the video control', function () { - expect(videoControl.pause).toHaveBeenCalled(); + expect(state.videoControl.pause).toHaveBeenCalled(); }); it('pause the video caption', function () { - expect(videoCaption.pause).toHaveBeenCalled(); + expect(state.videoCaption.pause).toHaveBeenCalled(); }); }); @@ -227,26 +176,28 @@ beforeEach(function () { // Create the first instance of the player. - initialize(); + state = jasmine.initializePlayer(); oldState = state; spyOn(oldState.videoPlayer, 'onPause').andCallThrough(); // Now initialize a second instance. - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoPlayer, 'log').andCallThrough(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'log').andCallThrough(); spyOn(window, 'setInterval').andReturn(100); - spyOn(videoControl, 'play'); - spyOn(videoCaption, 'play'); + spyOn(state.videoControl, 'play'); + spyOn(state.videoCaption, 'play'); - videoPlayer.onStateChange({ + state.videoPlayer.onStateChange({ data: YT.PlayerState.PLAYING }); }); it('log the play_video event', function () { - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'play_video', { currentTime: 0 } ); }); @@ -257,17 +208,17 @@ it('set update interval', function () { expect(window.setInterval).toHaveBeenCalledWith( - videoPlayer.update, 200 + state.videoPlayer.update, 200 ); - expect(videoPlayer.updateInterval).toEqual(100); + expect(state.videoPlayer.updateInterval).toEqual(100); }); it('play the video control', function () { - expect(videoControl.play).toHaveBeenCalled(); + expect(state.videoControl.play).toHaveBeenCalled(); }); it('play the video caption', function () { - expect(videoCaption.play).toHaveBeenCalled(); + expect(state.videoCaption.play).toHaveBeenCalled(); }); }); @@ -275,90 +226,96 @@ var currentUpdateIntrval; beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoPlayer, 'log').andCallThrough(); - spyOn(videoControl, 'pause').andCallThrough(); - spyOn(videoCaption, 'pause').andCallThrough(); + state.videoEl = $('video, iframe'); - videoPlayer.onStateChange({ + spyOn(state.videoPlayer, 'log').andCallThrough(); + spyOn(state.videoControl, 'pause').andCallThrough(); + spyOn(state.videoCaption, 'pause').andCallThrough(); + + state.videoPlayer.onStateChange({ data: YT.PlayerState.PLAYING }); - currentUpdateIntrval = videoPlayer.updateInterval; + currentUpdateIntrval = state.videoPlayer.updateInterval; - videoPlayer.onStateChange({ + state.videoPlayer.onStateChange({ data: YT.PlayerState.PAUSED }); }); it('log the pause_video event', function () { - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'pause_video', { currentTime: 0 } ); }); it('clear update interval', function () { - expect(videoPlayer.updateInterval).toBeUndefined(); + expect(state.videoPlayer.updateInterval).toBeUndefined(); }); it('pause the video control', function () { - expect(videoControl.pause).toHaveBeenCalled(); + expect(state.videoControl.pause).toHaveBeenCalled(); }); it('pause the video caption', function () { - expect(videoCaption.pause).toHaveBeenCalled(); + expect(state.videoCaption.pause).toHaveBeenCalled(); }); }); describe('when the video is ended', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoControl, 'pause').andCallThrough(); - spyOn(videoCaption, 'pause').andCallThrough(); + state.videoEl = $('video, iframe'); - videoPlayer.onStateChange({ + spyOn(state.videoControl, 'pause').andCallThrough(); + spyOn(state.videoCaption, 'pause').andCallThrough(); + + state.videoPlayer.onStateChange({ data: YT.PlayerState.ENDED }); }); it('pause the video control', function () { - expect(videoControl.pause).toHaveBeenCalled(); + expect(state.videoControl.pause).toHaveBeenCalled(); }); it('pause the video caption', function () { - expect(videoCaption.pause).toHaveBeenCalled(); + expect(state.videoCaption.pause).toHaveBeenCalled(); }); }); }); describe('onSeek', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); runs(function () { state.videoPlayer.play(); }); waitsFor(function () { - duration = videoPlayer.duration(); + duration = state.videoPlayer.duration(); - return duration > 0 && videoPlayer.isPlaying(); + return duration > 0 && state.videoPlayer.isPlaying(); }, 'video begins playing', WAIT_TIMEOUT); }); it('Slider event causes log update', function () { runs(function () { - var currentTime = videoPlayer.currentTime; + var currentTime = state.videoPlayer.currentTime; - spyOn(videoPlayer, 'log'); - videoProgressSlider.onSlide( + spyOn(state.videoPlayer, 'log'); + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 2 } ); - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'seek_video', { old_time: currentTime, @@ -371,24 +328,24 @@ it('seek the player', function () { runs(function () { - spyOn(videoPlayer.player, 'seekTo'); - videoProgressSlider.onSlide( + spyOn(state.videoPlayer.player, 'seekTo'); + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 60 } ); - expect(videoPlayer.player.seekTo) + expect(state.videoPlayer.player.seekTo) .toHaveBeenCalledWith(60, true); }); }); it('call updatePlayTime on player', function () { runs(function () { - spyOn(videoPlayer, 'updatePlayTime'); - videoProgressSlider.onSlide( + spyOn(state.videoPlayer, 'updatePlayTime'); + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 60 } ); - expect(videoPlayer.updatePlayTime) + expect(state.videoPlayer.updatePlayTime) .toHaveBeenCalledWith(60); }); }); @@ -399,16 +356,16 @@ function () { runs(function () { - videoProgressSlider.onSlide( + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 20 } ); - videoPlayer.pause(); - videoProgressSlider.onSlide( + state.videoPlayer.pause(); + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 10 } ); waitsFor(function () { - return Math.round(videoPlayer.currentTime) === 10; + return Math.round(state.videoPlayer.currentTime) === 10; }, 'currentTime got updated', 10000); }); }); @@ -416,26 +373,28 @@ describe('onSpeedChange', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); spyOn(state, 'setSpeed').andCallThrough(); - spyOn(videoPlayer, 'log').andCallThrough(); - spyOn(videoPlayer.player, 'setPlaybackRate').andCallThrough(); + spyOn(state.videoPlayer, 'log').andCallThrough(); + spyOn(state.videoPlayer.player, 'setPlaybackRate').andCallThrough(); }); describe('always', function () { beforeEach(function () { - videoPlayer.currentTime = 60; - videoPlayer.onSpeedChange('0.75', false); + state.videoPlayer.currentTime = 60; + state.videoPlayer.onSpeedChange('0.75', false); }); it('check if speed_change_video is logged', function () { - expect(videoPlayer.log).toHaveBeenCalledWith( + expect(state.videoPlayer.log).toHaveBeenCalledWith( 'speed_change_video', { - current_time: videoPlayer.currentTime, + current_time: state.videoPlayer.currentTime, old_speed: '1.0', new_speed: '0.75' } @@ -443,7 +402,7 @@ }); it('convert the current time to the new speed', function () { - expect(videoPlayer.currentTime).toEqual(60); + expect(state.videoPlayer.currentTime).toEqual(60); }); it('set video speed to the new speed', function () { @@ -453,75 +412,82 @@ describe('when the video is playing', function () { beforeEach(function () { - videoPlayer.currentTime = 60; - videoPlayer.play(); - videoPlayer.onSpeedChange('0.75', false); + state.videoPlayer.currentTime = 60; + state.videoPlayer.play(); + state.videoPlayer.onSpeedChange('0.75', false); }); it('trigger updatePlayTime event', function () { - expect(videoPlayer.player.setPlaybackRate) + expect(state.videoPlayer.player.setPlaybackRate) .toHaveBeenCalledWith('0.75'); }); }); describe('when the video is not playing', function () { beforeEach(function () { - videoPlayer.onSpeedChange('0.75', false); + state.videoPlayer.onSpeedChange('0.75', false); }); it('trigger updatePlayTime event', function () { - expect(videoPlayer.player.setPlaybackRate) + expect(state.videoPlayer.player.setPlaybackRate) .toHaveBeenCalledWith('0.75'); }); it('video has a correct speed', function () { - spyOn(videoPlayer, 'onSpeedChange'); + spyOn(state.videoPlayer, 'onSpeedChange'); state.speed = '2.0'; - videoPlayer.onPlay(); - expect(videoPlayer.onSpeedChange).toHaveBeenCalledWith('2.0'); - videoPlayer.onPlay(); - expect(videoPlayer.onSpeedChange.calls.length).toEqual(1); + state.videoPlayer.onPlay(); + expect(state.videoPlayer.onSpeedChange) + .toHaveBeenCalledWith('2.0'); + state.videoPlayer.onPlay(); + expect(state.videoPlayer.onSpeedChange.calls.length).toEqual(1); }); it('video has a correct volume', function () { - spyOn(videoPlayer.player, 'setVolume'); + spyOn(state.videoPlayer.player, 'setVolume'); state.currentVolume = '0.26'; - videoPlayer.onPlay(); - expect(videoPlayer.player.setVolume).toHaveBeenCalledWith('0.26'); + state.videoPlayer.onPlay(); + expect(state.videoPlayer.player.setVolume) + .toHaveBeenCalledWith('0.26'); }); }); }); describe('onVolumeChange', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); }); it('set the volume on player', function () { - spyOn(videoPlayer.player, 'setVolume'); - videoPlayer.onVolumeChange(60); - expect(videoPlayer.player.setVolume).toHaveBeenCalledWith(60); + spyOn(state.videoPlayer.player, 'setVolume'); + state.videoPlayer.onVolumeChange(60); + expect(state.videoPlayer.player.setVolume).toHaveBeenCalledWith(60); }); describe('when the video is not playing', function () { beforeEach(function () { - videoPlayer.player.setVolume('1'); + state.videoPlayer.player.setVolume('1'); }); it('video has a correct volume', function () { - spyOn(videoPlayer.player, 'setVolume'); + spyOn(state.videoPlayer.player, 'setVolume'); state.currentVolume = '0.26'; - videoPlayer.onPlay(); - expect(videoPlayer.player.setVolume).toHaveBeenCalledWith('0.26'); + state.videoPlayer.onPlay(); + expect(state.videoPlayer.player.setVolume) + .toHaveBeenCalledWith('0.26'); }); }); }); describe('update', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); }); describe( @@ -529,14 +495,14 @@ function () { beforeEach(function () { - videoPlayer.player.getCurrentTime = function () { + state.videoPlayer.player.getCurrentTime = function () { return NaN; }; - videoPlayer.update(); + state.videoPlayer.update(); }); it('does not trigger updatePlayTime event', function () { - expect(videoPlayer.updatePlayTime).not.toHaveBeenCalled(); + expect(state.videoPlayer.updatePlayTime).not.toHaveBeenCalled(); }); }); @@ -545,14 +511,14 @@ function () { beforeEach(function () { - videoPlayer.player.getCurrentTime = function () { + state.videoPlayer.player.getCurrentTime = function () { return 60; }; - videoPlayer.update(); + state.videoPlayer.update(); }); it('trigger updatePlayTime event', function () { - expect(videoPlayer.updatePlayTime) + expect(state.videoPlayer.updatePlayTime) .toHaveBeenCalledWith(60); }); }); @@ -563,34 +529,44 @@ var START_TIME = 1, END_TIME = 2; beforeEach(function () { - initialize({start: START_TIME, end: END_TIME}); + state = jasmine.initializePlayer( + { + start: START_TIME, + end: END_TIME + } + ); - spyOn(videoPlayer, 'update').andCallThrough(); - spyOn(videoPlayer, 'pause').andCallThrough(); - spyOn(videoProgressSlider, 'notifyThroughHandleEnd') + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'update').andCallThrough(); + spyOn(state.videoPlayer, 'pause').andCallThrough(); + spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd') .andCallThrough(); }); - it('video is paused on first endTime, start & end time are reset', function () { + it( + 'video is paused on first endTime, start & end time are reset', + function () + { var duration; - videoProgressSlider.notifyThroughHandleEnd.reset(); - videoPlayer.pause.reset(); - videoPlayer.play(); + state.videoProgressSlider.notifyThroughHandleEnd.reset(); + state.videoPlayer.pause.reset(); + state.videoPlayer.play(); waitsFor(function () { - duration = Math.round(videoPlayer.currentTime); + duration = Math.round(state.videoPlayer.currentTime); - return videoPlayer.pause.calls.length === 1; + return state.videoPlayer.pause.calls.length === 1; }, 'pause() has been called', WAIT_TIMEOUT); runs(function () { - expect(videoPlayer.startTime).toBe(0); - expect(videoPlayer.endTime).toBe(null); + expect(state.videoPlayer.startTime).toBe(0); + expect(state.videoPlayer.endTime).toBe(null); expect(duration).toBe(END_TIME); - expect(videoProgressSlider.notifyThroughHandleEnd) + expect(state.videoProgressSlider.notifyThroughHandleEnd) .toHaveBeenCalledWith({end: true}); }); }); @@ -598,17 +574,19 @@ describe('updatePlayTime', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOn(videoCaption, 'updatePlayTime').andCallThrough(); - spyOn(videoProgressSlider, 'updatePlayTime').andCallThrough(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoCaption, 'updatePlayTime').andCallThrough(); + spyOn(state.videoProgressSlider, 'updatePlayTime').andCallThrough(); }); it('update the video playback time', function () { var duration = 0; waitsFor(function () { - duration = videoPlayer.duration(); + duration = state.videoPlayer.duration(); if (duration > 0) { return true; @@ -620,7 +598,7 @@ runs(function () { var htmlStr; - videoPlayer.updatePlayTime(60); + state.videoPlayer.updatePlayTime(60); htmlStr = $('.vidtime').html(); @@ -643,13 +621,13 @@ it('update the playback time on caption', function () { waitsFor(function () { - return videoPlayer.duration() > 0; + return state.videoPlayer.duration() > 0; }, 'Video is fully loaded.', WAIT_TIMEOUT); runs(function () { - videoPlayer.updatePlayTime(60); + state.videoPlayer.updatePlayTime(60); - expect(videoCaption.updatePlayTime) + expect(state.videoCaption.updatePlayTime) .toHaveBeenCalledWith(60); }); }); @@ -658,15 +636,15 @@ var duration = 0; waitsFor(function () { - duration = videoPlayer.duration(); + duration = state.videoPlayer.duration(); return duration > 0; }, 'Video is fully loaded.', WAIT_TIMEOUT); runs(function () { - videoPlayer.updatePlayTime(60); + state.videoPlayer.updatePlayTime(60); - expect(videoProgressSlider.updatePlayTime) + expect(state.videoProgressSlider.updatePlayTime) .toHaveBeenCalledWith({ time: 60, duration: duration @@ -676,68 +654,93 @@ }); // Disabled 1/13/14 due to flakiness observed in master - xdescribe('updatePlayTime when start & end times are defined', function () { + xdescribe( + 'updatePlayTime when start & end times are defined', + function () + { var START_TIME = 1, END_TIME = 2; beforeEach(function () { - initialize({start: START_TIME, end: END_TIME}); + state = jasmine.initializePlayer( + { + start: START_TIME, + end: END_TIME + } + ); - spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); - spyOn(videoPlayer.player, 'seekTo').andCallThrough(); - spyOn(videoProgressSlider, 'updateStartEndTimeRegion') + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); + spyOn(state.videoPlayer.player, 'seekTo').andCallThrough(); + spyOn(state.videoProgressSlider, 'updateStartEndTimeRegion') .andCallThrough(); }); - it('when duration becomes available, updatePlayTime() is called', function () { + it( + 'when duration becomes available, updatePlayTime() is called', + function () + { var duration; - expect(videoPlayer.initialSeekToStartTime).toBeTruthy(); - expect(videoPlayer.seekToStartTimeOldSpeed).toBe('void'); + expect(state.videoPlayer.initialSeekToStartTime).toBeTruthy(); + expect(state.videoPlayer.seekToStartTimeOldSpeed).toBe('void'); - videoPlayer.play(); + state.videoPlayer.play(); waitsFor(function () { - duration = videoPlayer.duration(); + duration = state.videoPlayer.duration(); - return videoPlayer.isPlaying() && - videoPlayer.initialSeekToStartTime === false; + return state.videoPlayer.isPlaying() && + state.videoPlayer.initialSeekToStartTime === false; }, 'duration becomes available', WAIT_TIMEOUT); runs(function () { - expect(videoPlayer.startTime).toBe(START_TIME); - expect(videoPlayer.endTime).toBe(END_TIME); + expect(state.videoPlayer.startTime).toBe(START_TIME); + expect(state.videoPlayer.endTime).toBe(END_TIME); - expect(videoPlayer.player.seekTo).toHaveBeenCalledWith(START_TIME); + expect(state.videoPlayer.player.seekTo) + .toHaveBeenCalledWith(START_TIME); - expect(videoProgressSlider.updateStartEndTimeRegion) + expect(state.videoProgressSlider.updateStartEndTimeRegion) .toHaveBeenCalledWith({duration: duration}); - expect(videoPlayer.seekToStartTimeOldSpeed).toBe(state.speed); + expect(state.videoPlayer.seekToStartTimeOldSpeed) + .toBe(state.speed); }); }); }); describe('updatePlayTime with invalid endTime', function () { beforeEach(function () { - initialize({end: 100000}); + state = jasmine.initializePlayer( + { + end: 100000 + } + ); - spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); }); it('invalid endTime is reset to null', function () { var duration; - videoPlayer.updatePlayTime.reset(); - videoPlayer.play(); + state.videoPlayer.updatePlayTime.reset(); + state.videoPlayer.play(); - waitsFor(function () { - return videoPlayer.isPlaying() && - videoPlayer.initialSeekToStartTime === false; - }, 'updatePlayTime was invoked and duration is set', WAIT_TIMEOUT); + waitsFor( + function () { + return state.videoPlayer.isPlaying() && + state.videoPlayer.initialSeekToStartTime === false; + }, + 'updatePlayTime was invoked and duration is set', + WAIT_TIMEOUT + ); runs(function () { - expect(videoPlayer.endTime).toBe(null); + expect(state.videoPlayer.endTime).toBe(null); }); }); }); @@ -745,9 +748,12 @@ describe('toggleFullScreen', function () { describe('when the video player is not full screen', function () { beforeEach(function () { - initialize(); - spyOn(videoCaption, 'resize').andCallThrough(); - videoControl.toggleFullScreen(jQuery.Event('click')); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoCaption, 'resize').andCallThrough(); + state.videoControl.toggleFullScreen(jQuery.Event('click')); }); it('replace the full screen button tooltip', function () { @@ -760,22 +766,25 @@ }); it('tell VideoCaption to resize', function () { - expect(videoCaption.resize).toHaveBeenCalled(); + expect(state.videoCaption.resize).toHaveBeenCalled(); expect(state.resizer.setMode).toHaveBeenCalled(); }); }); describe('when the video player already full screen', function () { beforeEach(function () { - initialize(); - spyOn(videoCaption, 'resize').andCallThrough(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoCaption, 'resize').andCallThrough(); state.el.addClass('video-fullscreen'); - videoControl.fullScreenState = true; + state.videoControl.fullScreenState = true; isFullScreen = true; - videoControl.fullScreenEl.attr('title', 'Exit-fullscreen'); + state.videoControl.fullScreenEl.attr('title', 'Exit-fullscreen'); - videoControl.toggleFullScreen(jQuery.Event('click')); + state.videoControl.toggleFullScreen(jQuery.Event('click')); }); it('replace the full screen button tooltip', function () { @@ -788,7 +797,7 @@ }); it('tell VideoCaption to resize', function () { - expect(videoCaption.resize).toHaveBeenCalled(); + expect(state.videoCaption.resize).toHaveBeenCalled(); expect(state.resizer.setMode) .toHaveBeenCalledWith('width'); }); @@ -797,112 +806,114 @@ describe('play', function () { beforeEach(function () { - initialize(); - spyOn(player, 'playVideo').andCallThrough(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer.player, 'playVideo').andCallThrough(); }); describe('when the player is not ready', function () { beforeEach(function () { - player.playVideo = void 0; - videoPlayer.play(); + state.videoPlayer.player.playVideo = void 0; + state.videoPlayer.play(); }); it('does nothing', function () { - expect(player.playVideo).toBeUndefined(); + expect(state.videoPlayer.player.playVideo).toBeUndefined(); }); }); describe('when the player is ready', function () { beforeEach(function () { - player.playVideo.andReturn(true); - videoPlayer.play(); + state.videoPlayer.player.playVideo.andReturn(true); + state.videoPlayer.play(); }); it('delegate to the player', function () { - expect(player.playVideo).toHaveBeenCalled(); + expect(state.videoPlayer.player.playVideo).toHaveBeenCalled(); }); }); }); describe('isPlaying', function () { beforeEach(function () { - initialize(); - spyOn(player, 'getPlayerState').andCallThrough(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer.player, 'getPlayerState').andCallThrough(); }); describe('when the video is playing', function () { beforeEach(function () { - player.getPlayerState.andReturn(YT.PlayerState.PLAYING); + state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PLAYING); }); it('return true', function () { - expect(videoPlayer.isPlaying()).toBeTruthy(); + expect(state.videoPlayer.isPlaying()).toBeTruthy(); }); }); describe('when the video is not playing', function () { beforeEach(function () { - player.getPlayerState.andReturn(YT.PlayerState.PAUSED); + state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PAUSED); }); it('return false', function () { - expect(videoPlayer.isPlaying()).toBeFalsy(); + expect(state.videoPlayer.isPlaying()).toBeFalsy(); }); }); }); describe('pause', function () { beforeEach(function () { - initialize(); - spyOn(player, 'pauseVideo').andCallThrough(); - videoPlayer.pause(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer.player, 'pauseVideo').andCallThrough(); + state.videoPlayer.pause(); }); it('delegate to the player', function () { - expect(player.pauseVideo).toHaveBeenCalled(); + expect(state.videoPlayer.player.pauseVideo).toHaveBeenCalled(); }); }); describe('duration', function () { beforeEach(function () { - initialize(); - spyOn(player, 'getDuration').andCallThrough(); - videoPlayer.duration(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer.player, 'getDuration').andCallThrough(); + state.videoPlayer.duration(); }); it('delegate to the player', function () { - expect(player.getDuration).toHaveBeenCalled(); + expect(state.videoPlayer.player.getDuration).toHaveBeenCalled(); }); }); describe('getDuration', function () { - var oldYT; - beforeEach(function () { - oldYT = window.YT; - + // We need to make sure that metadata is returned via an AJAX + // request. Without the jasmine.stubRequests() below we will + // get the error: + // + // this.metadata[this.youtubeId(...)] is undefined jasmine.stubRequests(); - window.YT = { - Player: function () { - return { getDuration: function () { return 60; } }; - }, - PlayerState: oldYT.PlayerState, - ready: function (callback) { - callback(); - } - }; + state = jasmine.initializePlayerYouTube(); - spyOn(window.YT, 'Player').andCallThrough(); - - initializeYouTube(); + state.videoEl = $('video, iframe'); spyOn(state, 'getDuration').andCallThrough(); - spyOn(state.videoPlayer.player, 'getDuration').andReturn(0); - }); - afterEach(function () { - window.YT = oldYT; + // When `state.videoPlayer.player.getDuration()` returns a `0`, + // the fall-back function `state.getDuration()` will be called. + state.videoPlayer.player.getDuration.andReturn(0); }); it('getDuration is called as a fall-back', function () { @@ -914,27 +925,33 @@ describe('playback rate', function () { beforeEach(function () { - initialize(); - player.setPlaybackRate(1.5); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + state.videoPlayer.player.setPlaybackRate(1.5); }); it('set the player playback rate', function () { - expect(player.video.playbackRate).toEqual(1.5); + expect(state.videoPlayer.player.video.playbackRate).toEqual(1.5); }); }); describe('volume', function () { beforeEach(function () { - initialize(); - spyOn(player, 'getVolume').andCallThrough(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + spyOn(state.videoPlayer.player, 'getVolume').andCallThrough(); }); it('set the player volume', function () { var expectedValue = 60, realValue; - player.setVolume(60); - realValue = Math.round(player.getVolume()*100); + state.videoPlayer.player.setVolume(60); + realValue = Math.round(state.videoPlayer.player.getVolume()*100); expect(realValue).toEqual(expectedValue); }); @@ -942,9 +959,14 @@ describe('on Touch devices', function () { it('`is-touch` class name is added to container', function () { - $.each(['iPad', 'Android', 'iPhone'], function(index, device) { + $.each( + ['iPad', 'Android', 'iPhone'], + function (index, device) + { window.onTouchBasedDevice.andReturn([device]); - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); expect(state.el).toHaveClass('is-touch'); }); @@ -952,11 +974,13 @@ it('modules are not initialized on iPhone', function () { window.onTouchBasedDevice.andReturn(['iPhone']); - initialize(); + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); var modules = [ - videoControl, videoCaption, videoProgressSlider, - videoSpeedControl, videoVolumeControl + state.videoControl, state.videoCaption, state.videoProgressSlider, + state.videoSpeedControl, state.videoVolumeControl ]; $.each(modules, function (index, module) { @@ -964,37 +988,42 @@ }); }); - $.each(['iPad', 'Android'], function(index, device) { - var message = 'controls become visible after playing starts on ' + - device; - it(message, function() { - var controls; - window.onTouchBasedDevice.andReturn([device]); + $.each(['iPad', 'Android'], function (index, device) { + var message = 'controls become visible after playing starts ' + + 'on ' + device; - runs(function () { - initialize(); - controls = state.el.find('.video-controls'); + it(message, function () { + var controls; + + window.onTouchBasedDevice.andReturn([device]); + + runs(function () { + state = jasmine.initializePlayer(); + + state.videoEl = $('video, iframe'); + + controls = state.el.find('.video-controls'); + }); + + waitsFor(function () { + return state.el.hasClass('is-initialized'); + },'Video is not initialized.' , WAIT_TIMEOUT); + + runs(function () { + expect(controls).toHaveClass('is-hidden'); + state.videoPlayer.play(); + }); + + waitsFor(function () { + duration = state.videoPlayer.duration(); + + return duration > 0 && state.videoPlayer.isPlaying(); + },'Video does not play.' , WAIT_TIMEOUT); + + runs(function () { + expect(controls).not.toHaveClass('is-hidden'); + }); }); - - waitsFor(function () { - return state.el.hasClass('is-initialized'); - },'Video is not initialized.' , WAIT_TIMEOUT); - - runs(function () { - expect(controls).toHaveClass('is-hidden'); - videoPlayer.play(); - }); - - waitsFor(function () { - duration = videoPlayer.duration(); - - return duration > 0 && videoPlayer.isPlaying(); - },'Video does not play.' , WAIT_TIMEOUT); - - runs(function () { - expect(controls).not.toHaveClass('is-hidden'); - }); - }); }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js index 60f1149831..8963adc287 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js @@ -1,84 +1,81 @@ -(function() { - describe('VideoProgressSlider', function() { - var state, videoPlayer, videoProgressSlider, oldOTBD; +(function (undefined) { + describe('VideoProgressSlider', function () { + var state, oldOTBD; - function initialize() { - loadFixtures('video_all.html'); - state = new Video('#example'); - videoPlayer = state.videoPlayer; - videoProgressSlider = state.videoProgressSlider; - } - - beforeEach(function() { + beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .andReturn(null); }); - afterEach(function() { + afterEach(function () { $('source').remove(); window.onTouchBasedDevice = oldOTBD; }); - describe('constructor', function() { - describe('on a non-touch based device', function() { - beforeEach(function() { + describe('constructor', function () { + describe('on a non-touch based device', function () { + beforeEach(function () { spyOn($.fn, 'slider').andCallThrough(); - initialize(); + + state = jasmine.initializePlayer(); }); - it('build the slider', function() { - expect(videoProgressSlider.slider).toBe('.slider'); + it('build the slider', function () { + expect(state.videoProgressSlider.slider).toBe('.slider'); expect($.fn.slider).toHaveBeenCalledWith({ range: 'min', - change: videoProgressSlider.onChange, - slide: videoProgressSlider.onSlide, - stop: videoProgressSlider.onStop + change: state.videoProgressSlider.onChange, + slide: state.videoProgressSlider.onSlide, + stop: state.videoProgressSlider.onStop }); }); - it('build the seek handle', function() { - expect(videoProgressSlider.handle) + it('build the seek handle', function () { + expect(state.videoProgressSlider.handle) .toBe('.slider .ui-slider-handle'); }); }); - describe('on a touch-based device', function() { - it('does not build the slider on iPhone', function() { + describe('on a touch-based device', function () { + it('does not build the slider on iPhone', function () { window.onTouchBasedDevice.andReturn(['iPhone']); - initialize(); - expect(videoProgressSlider).toBeUndefined(); + state = jasmine.initializePlayer(); + + expect(state.videoProgressSlider).toBeUndefined(); // We can't expect $.fn.slider not to have been called, // because sliders are used in other parts of Video. }); - $.each(['iPad', 'Android'], function(index, device) { - it('build the slider on ' + device, function() { + $.each(['iPad', 'Android'], function (index, device) { + it('build the slider on ' + device, function () { window.onTouchBasedDevice.andReturn([device]); - initialize(); - expect(videoProgressSlider.slider).toBeDefined(); + + state = jasmine.initializePlayer(); + + expect(state.videoProgressSlider.slider).toBeDefined(); }); }); }); }); - describe('play', function() { - beforeEach(function() { - initialize(); + describe('play', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); }); - describe('when the slider was already built', function() { + describe('when the slider was already built', function () { var spy; - beforeEach(function() { - spy = spyOn(videoProgressSlider, 'buildSlider'); + beforeEach(function () { + spy = spyOn(state.videoProgressSlider, 'buildSlider'); spy.andCallThrough(); - videoPlayer.play(); + state.videoPlayer.play(); }); - it('does not build the slider', function() { + it('does not build the slider', function () { expect(spy.callCount).toEqual(0); }); }); @@ -86,40 +83,40 @@ // Currently, the slider is not rebuilt if it does not exist. }); - describe('updatePlayTime', function() { - beforeEach(function() { - initialize(); + describe('updatePlayTime', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); }); - describe('when frozen', function() { - beforeEach(function() { + describe('when frozen', function () { + beforeEach(function () { spyOn($.fn, 'slider').andCallThrough(); - videoProgressSlider.frozen = true; - videoProgressSlider.updatePlayTime(20, 120); + state.videoProgressSlider.frozen = true; + state.videoProgressSlider.updatePlayTime(20, 120); }); - it('does not update the slider', function() { + it('does not update the slider', function () { expect($.fn.slider).not.toHaveBeenCalled(); }); }); - describe('when not frozen', function() { - beforeEach(function() { + describe('when not frozen', function () { + beforeEach(function () { spyOn($.fn, 'slider').andCallThrough(); - videoProgressSlider.frozen = false; - videoProgressSlider.updatePlayTime({ + state.videoProgressSlider.frozen = false; + state.videoProgressSlider.updatePlayTime({ time: 20, duration: 120 }); }); - it('update the max value of the slider', function() { + it('update the max value of the slider', function () { expect($.fn.slider).toHaveBeenCalledWith( 'option', 'max', 120 ); }); - it('update current value of the slider', function() { + it('update current value of the slider', function () { expect($.fn.slider).toHaveBeenCalledWith( 'option', 'value', 20 ); @@ -127,72 +124,74 @@ }); }); - describe('onSlide', function() { - beforeEach(function() { - initialize(); + describe('onSlide', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + spyOn($.fn, 'slider').andCallThrough(); - spyOn(videoPlayer, 'onSlideSeek').andCallThrough(); + spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough(); }); // Disabled 12/30/13 due to flakiness in master - xit('freeze the slider', function() { - videoProgressSlider.onSlide( + xit('freeze the slider', function () { + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 20 } ); - expect(videoProgressSlider.frozen).toBeTruthy(); + expect(state.videoProgressSlider.frozen).toBeTruthy(); }); // Disabled 12/30/13 due to flakiness in master - xit('trigger seek event', function() { - videoProgressSlider.onSlide( + xit('trigger seek event', function () { + state.videoProgressSlider.onSlide( jQuery.Event('slide'), { value: 20 } ); - expect(videoPlayer.onSlideSeek).toHaveBeenCalled(); + expect(state.videoPlayer.onSlideSeek).toHaveBeenCalled(); }); }); - describe('onStop', function() { + describe('onStop', function () { - beforeEach(function() { + beforeEach(function () { jasmine.Clock.useMock(); - initialize(); - spyOn(videoPlayer, 'onSlideSeek').andCallThrough(); + state = jasmine.initializePlayer(); + + spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough(); }); // Disabled 12/30/13 due to flakiness in master - xit('freeze the slider', function() { - videoProgressSlider.onStop( + xit('freeze the slider', function () { + state.videoProgressSlider.onStop( jQuery.Event('stop'), { value: 20 } ); - expect(videoProgressSlider.frozen).toBeTruthy(); + expect(state.videoProgressSlider.frozen).toBeTruthy(); }); // Disabled 12/30/13 due to flakiness in master - xit('trigger seek event', function() { - videoProgressSlider.onStop( + xit('trigger seek event', function () { + state.videoProgressSlider.onStop( jQuery.Event('stop'), { value: 20 } ); - expect(videoPlayer.onSlideSeek).toHaveBeenCalled(); + expect(state.videoPlayer.onSlideSeek).toHaveBeenCalled(); }); // Disabled 12/30/13 due to flakiness in master - xit('set timeout to unfreeze the slider', function() { - videoProgressSlider.onStop( + xit('set timeout to unfreeze the slider', function () { + state.videoProgressSlider.onStop( jQuery.Event('stop'), { value: 20 } ); jasmine.Clock.tick(200); - expect(videoProgressSlider.frozen).toBeFalsy(); + expect(state.videoProgressSlider.frozen).toBeFalsy(); }); }); - it('getRangeParams' , function() { + it('getRangeParams' , function () { var testCases = [ { startTime: 10, @@ -211,9 +210,9 @@ } ]; - initialize(); + state = jasmine.initializePlayer(); - $.each(testCases, function(index, testCase) { + $.each(testCases, function (index, testCase) { var step = 100/testCase.duration, left = testCase.startTime*step, width = testCase.endTime*step - left, @@ -221,7 +220,7 @@ left: left + '%', width: width + '%' }, - params = videoProgressSlider.getRangeParams( + params = state.videoProgressSlider.getRangeParams( testCase.startTime, testCase.endTime, testCase.duration ); @@ -231,40 +230,44 @@ describe('notifyThroughHandleEnd', function () { beforeEach(function () { - initialize(); + state = jasmine.initializePlayer(); - spyOnEvent(videoProgressSlider.handle, 'focus'); - spyOn(videoProgressSlider, 'notifyThroughHandleEnd') + spyOnEvent(state.videoProgressSlider.handle, 'focus'); + spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd') .andCallThrough(); }); it('params.end = true', function () { - videoProgressSlider.notifyThroughHandleEnd({end: true}); + state.videoProgressSlider.notifyThroughHandleEnd({end: true}); - expect(videoProgressSlider.handle.attr('title')) + expect(state.videoProgressSlider.handle.attr('title')) .toBe('video ended'); - expect('focus').toHaveBeenTriggeredOn(videoProgressSlider.handle); + expect('focus').toHaveBeenTriggeredOn( + state.videoProgressSlider.handle + ); }); it('params.end = false', function () { - videoProgressSlider.notifyThroughHandleEnd({end: false}); + state.videoProgressSlider.notifyThroughHandleEnd({end: false}); - expect(videoProgressSlider.handle.attr('title')) + expect(state.videoProgressSlider.handle.attr('title')) .toBe('video position'); - expect('focus').not.toHaveBeenTriggeredOn(videoProgressSlider.handle); + expect('focus').not.toHaveBeenTriggeredOn( + state.videoProgressSlider.handle + ); }); it('is called when video plays', function () { - videoPlayer.play(); + state.videoPlayer.play(); waitsFor(function () { - return videoPlayer.isPlaying(); + return state.videoPlayer.isPlaying(); }, 'duration is set, video is playing', 5000); runs(function () { - expect(videoProgressSlider.notifyThroughHandleEnd) + expect(state.videoProgressSlider.notifyThroughHandleEnd) .toHaveBeenCalledWith({end: false}); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js index 3aad51e7fe..3ead4a7c15 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js @@ -1,64 +1,45 @@ -(function() { - describe('VideoQualityControl', function() { - var state, videoControl, videoQualityControl, oldOTBD; +(function (undefined) { + describe('VideoQualityControl', function () { + var state, oldOTBD; - function initialize() { - loadFixtures('video.html'); - state = new Video('#example'); - videoControl = state.videoControl; - videoQualityControl = state.videoQualityControl; - } - - beforeEach(function() { - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice') - .andReturn(null); - }); - - afterEach(function() { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - }); - - describe('constructor', function() { - var oldYT = window.YT; - - beforeEach(function() { - window.YT = { - Player: function () { - return { getDuration: function () { return 60; } }; - }, - PlayerState: oldYT.PlayerState, - ready: function(f){f();} - }; - - initialize(); - }); - - afterEach(function () { - window.YT = oldYT; - }); - - it('render the quality control', function() { - var container = videoControl.secondaryControlsEl; - expect(container).toContain('a.quality_control'); - }); - - it('add ARIA attributes to quality control', function () { - var qualityControl = $('a.quality_control'); - expect(qualityControl).toHaveAttrs({ - 'role': 'button', - 'title': 'HD off', - 'aria-disabled': 'false' + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine + .createSpy('onTouchBasedDevice') + .andReturn(null); }); - }); - it('bind the quality control', function() { - var handler = videoQualityControl.toggleQuality; - expect($('a.quality_control')).toHandleWith('click', handler); - }); + afterEach(function () { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; + }); + + describe('constructor', function () { + beforeEach(function () { + state = jasmine.initializePlayer('video.html'); + }); + + it('render the quality control', function () { + var container = state.videoControl.secondaryControlsEl; + + expect(container).toContain('a.quality_control'); + }); + + it('add ARIA attributes to quality control', function () { + var qualityControl = $('a.quality_control'); + + expect(qualityControl).toHaveAttrs({ + 'role': 'button', + 'title': 'HD off', + 'aria-disabled': 'false' + }); + }); + + it('bind the quality control', function () { + var handler = state.videoQualityControl.toggleQuality; + + expect($('a.quality_control')).toHandleWith('click', handler); + }); + }); }); - }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js index f012dc21e3..afef36c7d0 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js @@ -1,183 +1,208 @@ -(function() { - describe('VideoSpeedControl', function() { - var state, videoPlayer, videoControl, videoSpeedControl; +(function (undefined) { + describe('VideoSpeedControl', function () { + var state, oldOTBD; - function initialize() { - loadFixtures('video_all.html'); - state = new Video('#example'); - videoPlayer = state.videoPlayer; - videoControl = state.videoControl; - videoSpeedControl = state.videoSpeedControl; - } + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') + .andReturn(null); + }); - beforeEach(function() { - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null); + afterEach(function () { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; + }); + + describe('constructor', function () { + describe('always', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + }); + + it('add the video speed control to player', function () { + var li, secondaryControls; + + 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', state.videoSpeedControl.currentSpeed + ); + expect(li.length).toBe(state.videoSpeedControl.speeds.length); + + $.each(li.toArray().reverse(), function (index, link) { + expect($(link)).toHaveData( + 'speed', state.videoSpeedControl.speeds[index] + ); + expect($(link).find('a').text()).toBe( + state.videoSpeedControl.speeds[index] + 'x' + ); + }); + }); + + it('add ARIA attributes to speed control', function () { + var speedControl = $('div.speeds>a'); + + expect(speedControl).toHaveAttrs({ + 'role': 'button', + 'title': 'Speeds', + 'aria-disabled': 'false' + }); + }); + + it('bind to change video speed link', function () { + expect($('.video_speeds a')).toHandleWith( + 'click', state.videoSpeedControl.changeVideoSpeed + ); + }); + }); + + describe('when running on touch based device', function () { + $.each(['iPad', 'Android'], function (index, device) { + it('is not rendered on' + device, function () { + window.onTouchBasedDevice.andReturn([device]); + state = jasmine.initializePlayer(); + + expect(state.el.find('div.speeds')).not.toExist(); + }); + }); + }); + + describe('when running on non-touch based device', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + }); + + it('open the speed toggle on hover', function () { + $('.speeds').mouseenter(); + expect($('.speeds')).toHaveClass('open'); + + $('.speeds').mouseleave(); + expect($('.speeds')).not.toHaveClass('open'); + }); + + it('close the speed toggle on mouse out', function () { + $('.speeds').mouseenter().mouseleave(); + + expect($('.speeds')).not.toHaveClass('open'); + }); + + it('close the speed toggle on click', function () { + $('.speeds').mouseenter().click(); + + expect($('.speeds')).not.toHaveClass('open'); + }); + + // Tabbing depends on the following order: + // 1. Play anchor + // 2. Speed anchor + // 3. A number of speed entry anchors + // 4. Volume anchor + // If another focusable element is inserted or if the order is + // changed, things will malfunction as a flag, + // state.previousFocus, is set in the 1,3,4 elements and is + // used to determine the behavior of foucus() and blur() for + // the speed anchor. + it( + 'checks for a certain order in focusable elements in ' + + 'video controls', + function () + { + var foundFirst = false, + playIndex, speedIndex, firstSpeedEntry, lastSpeedEntry, + volumeIndex; + + $('.video-controls').find('a, :focusable').each( + function (index) + { + if ($(this).hasClass('video_control')) { + playIndex = index; + } else if ($(this).parent().hasClass('speeds')) { + speedIndex = index; + } else if ($(this).hasClass('speed_link')) { + if (!foundFirst) { + firstSpeedEntry = index; + foundFirst = true; + } + + lastSpeedEntry = index; + } else if ($(this).parent().hasClass('volume')) { + volumeIndex = index; + } + }); + + expect(playIndex+1).toEqual(speedIndex); + expect(speedIndex+1).toEqual(firstSpeedEntry); + expect(lastSpeedEntry+1).toEqual(volumeIndex); + }); + }); + }); + + describe('changeVideoSpeed', function () { + // This is an unnecessary test. The internal browser API, and + // YouTube API detect (and do not do anything) if there is a + // request for a speed that is already set. + // + // describe("when new speed is the same") ... + + describe('when new speed is not the same', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + state.videoSpeedControl.setSpeed(1.0); + spyOn(state.videoPlayer, 'onSpeedChange').andCallThrough(); + + $('li[data-speed="0.75"] a').click(); + }); + + it('trigger speedChange event', function () { + expect(state.videoPlayer.onSpeedChange).toHaveBeenCalled(); + expect(state.videoSpeedControl.currentSpeed).toEqual(0.75); + }); + }); + + describe( + 'make sure the speed control gets the focus afterwards', + function () + { + var anchor; + + beforeEach(function () { + state = jasmine.initializePlayer(); + anchor= $('.speeds > a').first(); + state.videoSpeedControl.setSpeed(1.0); + spyOnEvent(anchor, 'focus'); + }); + + it('when the speed is the same', function () { + $('li[data-speed="1.0"] a').click(); + expect('focus').toHaveBeenTriggeredOn(anchor); + }); + + it('when the speed is not the same', function () { + $('li[data-speed="0.75"] a').click(); + expect('focus').toHaveBeenTriggeredOn(anchor); + }); + }); + }); + + describe('onSpeedChange', function () { + beforeEach(function () { + state = jasmine.initializePlayer(); + $('li[data-speed="1.0"] a').addClass('active'); + state.videoSpeedControl.setSpeed(0.75); + }); + + it('set the new speed as active', function () { + expect($('.video_speeds li[data-speed="1.0"]')) + .not.toHaveClass('active'); + expect($('.video_speeds li[data-speed="0.75"]')) + .toHaveClass('active'); + expect($('.speeds p.active')).toHaveHtml('0.75x'); + }); + }); }); - - - afterEach(function() { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - }); - - describe('constructor', function() { - describe('always', function() { - beforeEach(function() { - initialize(); - }); - - it('add the video speed control to player', function() { - var li, secondaryControls; - 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', videoSpeedControl.currentSpeed); - expect(li.length).toBe(videoSpeedControl.speeds.length); - $.each(li.toArray().reverse(), function(index, link) { - expect($(link)).toHaveData('speed', videoSpeedControl.speeds[index]); - expect($(link).find('a').text()).toBe(videoSpeedControl.speeds[index] + 'x'); - }); - }); - - it('add ARIA attributes to speed control', function () { - var speedControl = $('div.speeds>a'); - expect(speedControl).toHaveAttrs({ - 'role': 'button', - 'title': 'Speeds', - 'aria-disabled': 'false' - }); - }); - - it('bind to change video speed link', function() { - expect($('.video_speeds a')).toHandleWith('click', videoSpeedControl.changeVideoSpeed); - }); - }); - - describe('when running on touch based device', function() { - $.each(['iPad', 'Android'], function(index, device) { - it('is not rendered on' + device, function() { - window.onTouchBasedDevice.andReturn([device]); - initialize(); - expect(state.el.find('div.speeds')).not.toExist(); - }); - }); - }); - - describe('when running on non-touch based device', function() { - beforeEach(function() { - initialize(); - }); - - it('open the speed toggle on hover', function() { - $('.speeds').mouseenter(); - expect($('.speeds')).toHaveClass('open'); - $('.speeds').mouseleave(); - expect($('.speeds')).not.toHaveClass('open'); - }); - - it('close the speed toggle on mouse out', function() { - $('.speeds').mouseenter().mouseleave(); - expect($('.speeds')).not.toHaveClass('open'); - }); - - it('close the speed toggle on click', function() { - $('.speeds').mouseenter().click(); - expect($('.speeds')).not.toHaveClass('open'); - }); - // Tabbing depends on the following order: - // 1. Play anchor - // 2. Speed anchor - // 3. A number of speed entry anchors - // 4. Volume anchor - // If another focusable element is inserted or if the order is changed, things will - // malfunction as a flag, state.previousFocus, is set in the 1,3,4 elements and is - // used to determine the behavior of foucus() and blur() for the speed anchor. - it('checks for a certain order in focusable elements in video controls', function() { - var playIndex, speedIndex, firstSpeedEntry, lastSpeedEntry, volumeIndex, foundFirst = false; - $('.video-controls').find('a, :focusable').each(function(index) { - if ($(this).hasClass('video_control')) { - playIndex = index; - } - else if ($(this).parent().hasClass('speeds')) { - speedIndex = index; - } - else if ($(this).hasClass('speed_link')) { - if (!foundFirst) { - firstSpeedEntry = index; - foundFirst = true; - } - lastSpeedEntry = index; - } - else if ($(this).parent().hasClass('volume')) { - volumeIndex = index; - } - }); - expect(playIndex+1).toEqual(speedIndex); - expect(speedIndex+1).toEqual(firstSpeedEntry); - expect(lastSpeedEntry+1).toEqual(volumeIndex); - }); - }); - }); - - describe('changeVideoSpeed', function() { - // This is an unnecessary test. The internal browser API, and YouTube API - // detect (and do not do anything) if there is a request for a speed that - // is already set. - // - // describe("when new speed is the same") ... - - describe('when new speed is not the same', function() { - beforeEach(function() { - initialize(); - videoSpeedControl.setSpeed(1.0); - spyOn(videoPlayer, 'onSpeedChange').andCallThrough(); - - $('li[data-speed="0.75"] a').click(); - }); - - it('trigger speedChange event', function() { - expect(videoPlayer.onSpeedChange).toHaveBeenCalled(); - expect(videoSpeedControl.currentSpeed).toEqual(0.75); - }); - }); - - describe('make sure the speed control gets the focus afterwards', function() { - var anchor; - beforeEach(function() { - initialize(); - anchor= $('.speeds > a').first(); - videoSpeedControl.setSpeed(1.0); - spyOnEvent(anchor, 'focus'); - }); - - it('when the speed is the same', function() { - $('li[data-speed="1.0"] a').click(); - expect('focus').toHaveBeenTriggeredOn(anchor); - }); - - it('when the speed is not the same', function() { - $('li[data-speed="0.75"] a').click(); - expect('focus').toHaveBeenTriggeredOn(anchor); - }); - }); - }); - - describe('onSpeedChange', function() { - beforeEach(function() { - initialize(); - $('li[data-speed="1.0"] a').addClass('active'); - videoSpeedControl.setSpeed(0.75); - }); - - it('set the new speed as active', function() { - expect($('.video_speeds li[data-speed="1.0"]')).not.toHaveClass('active'); - expect($('.video_speeds li[data-speed="0.75"]')).toHaveClass('active'); - expect($('.speeds p.active')).toHaveHtml('0.75x'); - }); - }); - }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js index 8f09030189..b07a441220 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js @@ -1,212 +1,209 @@ -(function() { - describe('VideoVolumeControl', function() { - var state, videoControl, videoVolumeControl, oldOTBD; +(function (undefined) { + describe('VideoVolumeControl', function () { + var state, oldOTBD; - function initialize() { - loadFixtures('video_all.html'); - state = new Video('#example'); - videoControl = state.videoControl; - videoVolumeControl = state.videoVolumeControl; - } + beforeEach(function () { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') + .andReturn(null); - beforeEach(function() { - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null); - }); - - afterEach(function() { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - }); - - describe('constructor', function() { - beforeEach(function() { - spyOn($.fn, 'slider').andCallThrough(); - $.cookie.andReturn('75'); - initialize(); - }); - - it('initialize currentVolume to 75', function() { - expect(state.videoVolumeControl.currentVolume).toEqual(75); - }); - - it('render the volume control', function() { - expect(videoControl.secondaryControlsEl.html()).toContain("