Commit b6e5db02 by Valera Rozuvan

Addressing comments for PR 2176.

BLD-529.
parent b3f0d1b2
......@@ -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))
......
# 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'
(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);
(function () {
(function (undefined) {
describe('VideoPlayer Events', 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;
describe('HTML5', function () {
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('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();
}
};
state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
});
afterEach(function () {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
window.YT = this.oldYT;
});
it('initialize', function(){
runs(function () {
initialize();
});
it('initialize', function () {
waitsFor(function () {
return state.el.hasClass('is-initialized');
}, 'Player is not initialized.', WAIT_TIMEOUT);
......@@ -95,11 +31,7 @@
});
});
it('ready', function() {
runs(function () {
initialize();
});
it('ready', function () {
waitsFor(function () {
return state.el.hasClass('is-initialized');
}, 'Player is not initialized.', WAIT_TIMEOUT);
......@@ -109,43 +41,31 @@
});
});
it('play', function() {
initialize();
videoPlayer.play();
it('play', function () {
state.videoPlayer.play();
expect('play').not.toHaveBeenTriggeredOn('.video');
});
it('pause', function() {
initialize();
videoPlayer.play();
videoPlayer.pause();
it('pause', function () {
state.videoPlayer.play();
state.videoPlayer.pause();
expect('pause').not.toHaveBeenTriggeredOn('.video');
});
it('volumechange', function() {
initialize();
videoPlayer.onVolumeChange(60);
it('volumechange', function () {
state.videoPlayer.onVolumeChange(60);
expect('volumechange').not.toHaveBeenTriggeredOn('.video');
});
it('speedchange', function() {
initialize();
videoPlayer.onSpeedChange('2.0');
it('speedchange', function () {
state.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({
it('seek', function () {
state.videoPlayer.onCaptionSeek({
time: 1,
type: 'any'
});
......@@ -153,13 +73,36 @@
expect('seek').not.toHaveBeenTriggeredOn('.video');
});
it('ended', function() {
initialize();
videoPlayer.onEnded();
it('ended', function () {
state.videoPlayer.onEnded();
expect('ended').not.toHaveBeenTriggeredOn('.video');
});
});
describe('YouTube', function () {
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine
.createSpy('onTouchBasedDevice')
.andReturn(null);
jasmine.stubRequests();
state = jasmine.initializePlayerYouTube();
});
afterEach(function () {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
it('qualitychange', function () {
state.videoPlayer.onPlaybackQualityChange();
expect('qualitychange').not.toHaveBeenTriggeredOn('.video');
});
});
});
}).call(this);
(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');
});
......
(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');
});
......
(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
......
(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);
});
});
});
......
(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;
}
function initializeYouTube() {
initialize('video.html');
}
beforeEach(function(){
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
window.onTouchBasedDevice = jasmine
.createSpy('onTouchBasedDevice').andReturn(null);
});
afterEach(function() {
afterEach(function () {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() {
beforeEach(function() {
initialize();
describe('constructor', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('render the video controls', function() {
it('render the video controls', function () {
expect($('.video-controls')).toContain(
['.slider', 'ul.vcr', 'a.play', '.vidtime', '.add-fullscreen'].join(',')
[
'.slider',
'ul.vcr',
'a.play',
'.vidtime',
'.add-fullscreen'
].join(',')
);
expect($('.video-controls').find('.vidtime')).toHaveText('0:00 / 0:00');
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',
......@@ -59,6 +57,7 @@
it('add ARIA attributes to fullscreen control', function () {
var fullScreenControl = $('a.add-fullscreen');
expect(fullScreenControl).toHaveAttrs({
'role': 'button',
'title': 'Fill browser',
......@@ -66,125 +65,146 @@
});
});
it('bind the playback button', function() {
expect($('.video_control')).toHandleWith('click', videoControl.togglePlayback);
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() {
initialize();
describe('when on a non-touch based device', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('add the play class to video control', function() {
it('add the play class to video control', function () {
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr('title', 'Play');
expect($('.video_control')).toHaveAttr(
'title', 'Play'
);
});
});
describe('when on a touch based device', function() {
beforeEach(function() {
describe('when on a touch based device', function () {
beforeEach(function () {
window.onTouchBasedDevice.andReturn(['iPad']);
initialize();
state = jasmine.initializePlayer();
});
it('does not add the play class to video control', function() {
it(
'does not add the play class to video control',
function ()
{
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr('title', 'Play');
expect($('.video_control')).toHaveAttr(
'title', 'Play'
);
});
});
});
describe('play', function() {
beforeEach(function() {
initialize();
videoControl.play();
describe('play', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
state.videoControl.play();
});
it('switch playback button to play state', function() {
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();
describe('pause', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
state.videoControl.pause();
});
it('switch playback button to pause state', function() {
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('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 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() {
describe('when the video is playing', function () {
beforeEach(function () {
$('.video_control').addClass('play');
spyOnEvent(videoControl, 'pause');
videoControl.togglePlayback(jQuery.Event('click'));
spyOnEvent(state.videoControl, 'pause');
state.videoControl.togglePlayback(jQuery.Event('click'));
});
it('does not trigger the pause event', function() {
expect('pause').not.toHaveBeenTriggeredOn(videoControl);
it('does not trigger the pause event', function () {
expect('pause').not
.toHaveBeenTriggeredOn(state.videoControl);
});
});
describe('when the video is paused', function() {
beforeEach(function() {
describe('when the video is paused', function () {
beforeEach(function () {
$('.video_control').addClass('pause');
spyOnEvent(videoControl, 'play');
videoControl.togglePlayback(jQuery.Event('click'));
spyOnEvent(state.videoControl, 'play');
state.videoControl.togglePlayback(jQuery.Event('click'));
});
it('does not trigger the play event', function() {
expect('play').not.toHaveBeenTriggeredOn(videoControl);
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 () {
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');
var btnPlay;
videoControl.showPlayPlaceholder();
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
state.videoControl.showPlayPlaceholder();
expect(btnPlay).not.toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
......@@ -192,7 +212,7 @@
'tabindex': 0
});
videoControl.hidePlayPlaceholder();
state.videoControl.hidePlayPlaceholder();
expect(btnPlay).toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
......@@ -201,30 +221,7 @@
});
});
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) {
$.each(cases, function (index, data) {
var message = [
(data.isShown) ? 'is' : 'is not',
' shown on',
......@@ -232,9 +229,11 @@
].join('');
it(message, function () {
var btnPlay;
window.onTouchBasedDevice.andReturn(data.isTouch);
initialize();
var btnPlay = state.el.find('.btn-play');
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
if (data.isShown) {
expect(btnPlay).not.toHaveClass('is-hidden');
......@@ -244,35 +243,53 @@
});
});
$.each(['iPad', 'Android'], function(index, device) {
it('is shown on paused video on '+ device +' in HTML5 player', function () {
$.each(['iPad', 'Android'], function (index, device) {
it(
'is shown on paused video on ' + device +
' in HTML5 player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
initialize();
var btnPlay = state.el.find('.btn-play');
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
videoControl.play();
videoControl.pause();
state.videoControl.play();
state.videoControl.pause();
expect(btnPlay).not.toHaveClass('is-hidden');
});
it('is hidden on playing video on '+ device +' in HTML5 player', function () {
it(
'is hidden on playing video on ' + device +
' in HTML5 player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
initialize();
var btnPlay = state.el.find('.btn-play');
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
videoControl.play();
state.videoControl.play();
expect(btnPlay).toHaveClass('is-hidden');
});
it('is hidden on paused video on '+ device +' in YouTube player', function () {
it(
'is hidden on paused video on ' + device +
' in YouTube player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
initializeYouTube();
var btnPlay = state.el.find('.btn-play');
state = jasmine.initializePlayerYouTube();
btnPlay = state.el.find('.btn-play');
videoControl.play();
videoControl.pause();
state.videoControl.play();
state.videoControl.pause();
expect(btnPlay).toHaveClass('is-hidden');
});
......@@ -280,13 +297,14 @@
});
it('show', function () {
initialize();
var controls = state.el.find('.video-controls');
var controls;
state = jasmine.initializePlayer();
controls = state.el.find('.video-controls');
controls.addClass('is-hidden');
videoControl.show();
state.videoControl.show();
expect(controls).not.toHaveClass('is-hidden');
});
});
}).call(this);
(function () {
(function (undefined) {
describe('Video FocusGrabber', function () {
var state;
......
(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();
state.videoEl = $('video, iframe');
spyOn(videoControl, 'pause').andCallThrough();
spyOn(videoCaption, 'pause').andCallThrough();
spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(state.videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({
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();
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'log').andCallThrough();
spyOn(videoControl, 'pause').andCallThrough();
spyOn(videoCaption, 'pause').andCallThrough();
spyOn(state.videoPlayer, 'log').andCallThrough();
spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(state.videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({
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');
spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(state.videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({
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();
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
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
}
);
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'update').andCallThrough();
spyOn(videoPlayer, 'pause').andCallThrough();
spyOn(videoProgressSlider, 'notifyThroughHandleEnd')
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
}
);
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
spyOn(videoPlayer.player, 'seekTo').andCallThrough();
spyOn(videoProgressSlider, 'updateStartEndTimeRegion')
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
}
);
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
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();
}
};
spyOn(window.YT, 'Player').andCallThrough();
state = jasmine.initializePlayerYouTube();
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,15 +988,20 @@
});
});
$.each(['iPad', 'Android'], function(index, device) {
var message = 'controls become visible after playing starts on ' +
device;
it(message, function() {
$.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]);
runs(function () {
initialize();
state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
controls = state.el.find('.video-controls');
});
......@@ -982,13 +1011,13 @@
runs(function () {
expect(controls).toHaveClass('is-hidden');
videoPlayer.play();
state.videoPlayer.play();
});
waitsFor(function () {
duration = videoPlayer.duration();
duration = state.videoPlayer.duration();
return duration > 0 && videoPlayer.isPlaying();
return duration > 0 && state.videoPlayer.isPlaying();
},'Video does not play.' , WAIT_TIMEOUT);
runs(function () {
......
(function() {
describe('VideoProgressSlider', function() {
var state, videoPlayer, videoProgressSlider, oldOTBD;
function initialize() {
loadFixtures('video_all.html');
state = new Video('#example');
videoPlayer = state.videoPlayer;
videoProgressSlider = state.videoProgressSlider;
}
(function (undefined) {
describe('VideoProgressSlider', function () {
var state, oldOTBD;
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});
});
});
......
(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() {
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine
.createSpy('onTouchBasedDevice')
.andReturn(null);
});
afterEach(function() {
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();
describe('constructor', function () {
beforeEach(function () {
state = jasmine.initializePlayer('video.html');
});
afterEach(function () {
window.YT = oldYT;
});
it('render the quality control', function () {
var container = state.videoControl.secondaryControlsEl;
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',
......@@ -54,11 +35,11 @@
});
});
it('bind the quality control', function() {
var handler = videoQualityControl.toggleQuality;
it('bind the quality control', function () {
var handler = state.videoQualityControl.toggleQuality;
expect($('a.quality_control')).toHandleWith('click', handler);
});
});
});
}).call(this);
(function() {
describe('VideoSpeedControl', function() {
var state, videoPlayer, videoControl, videoSpeedControl;
function initialize() {
loadFixtures('video_all.html');
state = new Video('#example');
videoPlayer = state.videoPlayer;
videoControl = state.videoControl;
videoSpeedControl = state.videoSpeedControl;
}
(function (undefined) {
describe('VideoSpeedControl', function () {
var state, oldOTBD;
beforeEach(function() {
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null);
});
afterEach(function() {
afterEach(function () {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() {
describe('always', function() {
beforeEach(function() {
initialize();
describe('constructor', function () {
describe('always', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('add the video speed control to player', function() {
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');
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',
......@@ -51,70 +54,87 @@
});
});
it('bind to change video speed link', function() {
expect($('.video_speeds a')).toHandleWith('click', videoSpeedControl.changeVideoSpeed);
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() {
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();
state = jasmine.initializePlayer();
expect(state.el.find('div.speeds')).not.toExist();
});
});
});
describe('when running on non-touch based device', function() {
beforeEach(function() {
initialize();
describe('when running on non-touch based device', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('open the speed toggle on hover', function() {
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() {
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() {
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 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')) {
} else if ($(this).parent().hasClass('speeds')) {
speedIndex = index;
}
else if ($(this).hasClass('speed_link')) {
} else if ($(this).hasClass('speed_link')) {
if (!foundFirst) {
firstSpeedEntry = index;
foundFirst = true;
}
lastSpeedEntry = index;
}
else if ($(this).parent().hasClass('volume')) {
} else if ($(this).parent().hasClass('volume')) {
volumeIndex = index;
}
});
expect(playIndex+1).toEqual(speedIndex);
expect(speedIndex+1).toEqual(firstSpeedEntry);
expect(lastSpeedEntry+1).toEqual(volumeIndex);
......@@ -122,62 +142,67 @@
});
});
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('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();
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(videoPlayer.onSpeedChange).toHaveBeenCalled();
expect(videoSpeedControl.currentSpeed).toEqual(0.75);
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() {
describe(
'make sure the speed control gets the focus afterwards',
function ()
{
var anchor;
beforeEach(function() {
initialize();
beforeEach(function () {
state = jasmine.initializePlayer();
anchor= $('.speeds > a').first();
videoSpeedControl.setSpeed(1.0);
state.videoSpeedControl.setSpeed(1.0);
spyOnEvent(anchor, 'focus');
});
it('when the speed is the same', function() {
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() {
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();
describe('onSpeedChange', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
$('li[data-speed="1.0"] a').addClass('active');
videoSpeedControl.setSpeed(0.75);
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');
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);
(function() {
describe('VideoVolumeControl', function() {
var state, videoControl, videoVolumeControl, oldOTBD;
function initialize() {
loadFixtures('video_all.html');
state = new Video('#example');
videoControl = state.videoControl;
videoVolumeControl = state.videoVolumeControl;
}
beforeEach(function() {
(function (undefined) {
describe('VideoVolumeControl', function () {
var state, oldOTBD;
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
});
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null);
afterEach(function() {
afterEach(function () {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() {
beforeEach(function() {
describe('constructor', function () {
beforeEach(function () {
spyOn($.fn, 'slider').andCallThrough();
$.cookie.andReturn('75');
initialize();
state = jasmine.initializePlayer();
});
it('initialize currentVolume to 75', function() {
expect(state.videoVolumeControl.currentVolume).toEqual(75);
it('initialize currentVolume to 100%', function () {
// Please note that:
// 0% -> 0
// 100% -> 1.0
expect(state.videoVolumeControl.currentVolume).toEqual(1);
});
it('render the volume control', function() {
expect(videoControl.secondaryControlsEl.html()).toContain("<div class=\"volume\">\n");
it('render the volume control', function () {
expect(state.videoControl.secondaryControlsEl.html())
.toContain("<div class=\"volume\">\n");
});
it('create the slider', function() {
it('create the slider', function () {
expect($.fn.slider).toHaveBeenCalledWith({
orientation: "vertical",
range: "min",
min: 0,
max: 100,
value: videoVolumeControl.currentVolume,
change: videoVolumeControl.onChange,
slide: videoVolumeControl.onChange
value: state.videoVolumeControl.currentVolume,
change: state.videoVolumeControl.onChange,
slide: state.videoVolumeControl.onChange
});
});
it('add ARIA attributes to slider handle', function () {
var sliderHandle = $('div.volume-slider>a.ui-slider-handle'),
arr = ['muted', 'very low', 'low', 'average', 'loud', 'very loud',
'maximum'];
arr = [
'muted', 'very low', 'low', 'average', 'loud',
'very loud', 'maximum'
];
expect(sliderHandle).toHaveAttrs({
'role': 'slider',
'title': 'volume',
......@@ -59,11 +58,11 @@
});
expect(sliderHandle.attr('aria-valuenow')).toBeInRange(0, 100);
expect(sliderHandle.attr('aria-valuetext')).toBeInArray(arr);
});
it('add ARIA attributes to volume control', function () {
var volumeControl = $('div.volume>a');
expect(volumeControl).toHaveAttrs({
'role': 'button',
'title': 'Volume',
......@@ -71,101 +70,100 @@
});
});
it('bind the volume control', function() {
expect($('.volume>a')).toHandleWith('click', videoVolumeControl.toggleMute);
it('bind the volume control', function () {
expect($('.volume>a')).toHandleWith(
'click', state.videoVolumeControl.toggleMute
);
expect($('.volume')).not.toHaveClass('open');
$('.volume').mouseenter();
expect($('.volume')).toHaveClass('open');
$('.volume').mouseleave();
expect($('.volume')).not.toHaveClass('open');
});
});
describe('onChange', function() {
beforeEach(function() {
initialize();
});
describe('when the new volume is more than 0', function() {
beforeEach(function() {
videoVolumeControl.onChange(void 0, {
value: 60
});
});
it('set the player volume', function() {
expect(videoVolumeControl.currentVolume).toEqual(60);
});
it('remote muted class', function() {
expect($('.volume')).not.toHaveClass('muted');
});
});
describe('when the new volume is 0', function() {
beforeEach(function() {
videoVolumeControl.onChange(void 0, {
value: 0
});
});
it('set the player volume', function() {
expect(videoVolumeControl.currentVolume).toEqual(0);
});
it('add muted class', function() {
expect($('.volume')).toHaveClass('muted');
});
});
var initialData = [
{
describe('onChange', function () {
var initialData = [{
range: 'muted',
value: 0,
expectation: 'muted'
},
{
}, {
range: 'in ]0,20]',
value: 10,
expectation: 'very low'
},
{
}, {
range: 'in ]20,40]',
value: 30,
expectation: 'low'
},
{
}, {
range: 'in ]40,60]',
value: 50,
expectation: 'average'
},
{
}, {
range: 'in ]60,80]',
value: 70,
expectation: 'loud'
},
{
}, {
range: 'in ]80,100[',
value: 90,
expectation: 'very loud'
},
{
}, {
range: 'maximum',
value: 100,
expectation: 'maximum'
}
];
}];
beforeEach(function () {
state = jasmine.initializePlayer();
});
describe('when the new volume is more than 0', function () {
beforeEach(function () {
state.videoVolumeControl.onChange(void 0, {
value: 60
});
});
it('set the player volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(60);
});
$.each(initialData, function(index, data) {
describe('when the new volume is ' + data.range, function() {
beforeEach(function() {
videoVolumeControl.onChange(void 0, {
it('remote muted class', function () {
expect($('.volume')).not.toHaveClass('muted');
});
});
describe('when the new volume is 0', function () {
beforeEach(function () {
state.videoVolumeControl.onChange(void 0, {
value: 0
});
});
it('set the player volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(0);
});
it('add muted class', function () {
expect($('.volume')).toHaveClass('muted');
});
});
$.each(initialData, function (index, data) {
describe('when the new volume is ' + data.range, function () {
beforeEach(function () {
state.videoVolumeControl.onChange(void 0, {
value: data.value
});
});
it('changes ARIA attributes', function () {
var sliderHandle = $('div.volume-slider>a.ui-slider-handle');
var sliderHandle = $(
'div.volume-slider>a.ui-slider-handle'
);
expect(sliderHandle).toHaveAttrs({
'aria-valuenow': data.value.toString(10),
'aria-valuetext': data.expectation
......@@ -175,38 +173,37 @@
});
});
describe('toggleMute', function() {
beforeEach(function() {
initialize();
describe('toggleMute', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
describe('when the current volume is more than 0', function() {
beforeEach(function() {
videoVolumeControl.currentVolume = 60;
videoVolumeControl.buttonEl.trigger('click');
describe('when the current volume is more than 0', function () {
beforeEach(function () {
state.videoVolumeControl.currentVolume = 60;
state.videoVolumeControl.buttonEl.trigger('click');
});
it('save the previous volume', function() {
expect(videoVolumeControl.previousVolume).toEqual(60);
it('save the previous volume', function () {
expect(state.videoVolumeControl.previousVolume).toEqual(60);
});
it('set the player volume', function() {
expect(videoVolumeControl.currentVolume).toEqual(0);
it('set the player volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(0);
});
});
describe('when the current volume is 0', function() {
beforeEach(function() {
videoVolumeControl.currentVolume = 0;
videoVolumeControl.previousVolume = 60;
videoVolumeControl.buttonEl.trigger('click');
describe('when the current volume is 0', function () {
beforeEach(function () {
state.videoVolumeControl.currentVolume = 0;
state.videoVolumeControl.previousVolume = 60;
state.videoVolumeControl.buttonEl.trigger('click');
});
it('set the player volume to previous volume', function() {
expect(videoVolumeControl.currentVolume).toEqual(60);
it('set the player volume to previous volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(60);
});
});
});
});
}).call(this);
......@@ -559,16 +559,32 @@ function (VideoPlayer) {
// example the length of the video can be determined from the meta
// data.
function fetchMetadata() {
var _this = this;
var _this = this,
metadataXHRs = [];
this.metadata = {};
$.each(this.videos, function (speed, url) {
_this.getVideoMetadata(url, function (data) {
var xhr = _this.getVideoMetadata(url, function (data) {
if (data.data) {
_this.metadata[data.data.id] = data.data;
}
});
metadataXHRs.push(xhr);
});
$.when.apply(this, metadataXHRs).done(function () {
_this.el.trigger('metadata_received');
// Not only do we trigger the "metadata_received" event, we also
// set a flag to notify that metadata has been received. This
// allows for code that will miss the "metadata_received" event
// to know that metadata has been received. This is important in
// cases when some code will subscribe to the "metadata_received"
// event after it has been triggered.
_this.youtubeMetadataReceived = true;
});
}
......
......@@ -176,27 +176,32 @@ function (HTML5Video, Resizer) {
_resize(state, videoWidth, videoHeight);
// After initialization, update the VCR with total time.
// At this point only the metadata duration is available (not
// very precise), but it is better than having 00:00:00 for
// total time.
if (state.youtubeMetadataReceived) {
// Metadata was already received, and is available.
_updateVcrAndRegion(state);
} else {
// We wait for metadata to arrive, before we request the update
// of the VCR video time, and of the start-end time region.
// Metadata contains duration of the video. We wait for 2
// seconds, and then abandon our attempts to update the VCR
// video time (and the start-end time region) using metadata.
(function () {
var checkInterval = window.setInterval(
checkForMetadata, 50
),
numberOfChecks = 0;
// Metadata contains duration of the video.
state.el.on('metadata_received', function () {
_updateVcrAndRegion(state);
});
}
});
}
return;
if (state.isTouch) {
dfd.resolve();
}
}
function checkForMetadata() {
if (state.metadata && state.metadata[state.youtubeId()]) {
duration = state.videoPlayer.duration();
function _updateVcrAndRegion(state) {
var duration = state.videoPlayer.duration();
// After initialization, update the VCR with total time.
// At this point only the metadata duration is available (not
// very precise), but it is better than having 00:00:00 for
// total time.
state.trigger(
'videoControl.updateVcrVidTime',
{
......@@ -211,26 +216,9 @@ function (HTML5Video, Resizer) {
duration: duration
}
);
window.clearInterval(checkInterval);
} else {
numberOfChecks += 1;
if (numberOfChecks === 40) {
window.clearInterval(checkInterval);
}
}
}
}());
});
}
if (state.isTouch) {
dfd.resolve();
}
}
function _resize (state, videoWidth, videoHeight) {
function _resize(state, videoWidth, videoHeight) {
state.resizer = new Resizer({
element: state.videoEl,
elementRatio: videoWidth/videoHeight,
......@@ -783,7 +771,17 @@ function (HTML5Video, Resizer) {
* This instability is internal to the player API (or browser internals).
*/
function duration() {
var dur = this.videoPlayer.player.getDuration();
var dur;
// Sometimes the YouTube API doesn't finish instantiating all of it's
// methods, but the execution point arrives here.
//
// This happens when you have start and end times set, and click "Edit"
// in Studio, and then "Save". The Video editor dialog closes, the
// video reloads, but the start-end range is not visible.
if (this.videoPlayer.player.getDuration) {
dur = this.videoPlayer.player.getDuration();
}
// For YouTube videos, before the video starts playing, the API
// function player.getDuration() will return 0. This means that the VCR
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment