Commit b6e5db02 by Valera Rozuvan

Addressing comments for PR 2176.

BLD-529.
parent b3f0d1b2
...@@ -83,7 +83,7 @@ class StubYouTubeHandler(StubHttpRequestHandler): ...@@ -83,7 +83,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
'duration': 60, '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.send_response(200, content=response, headers={'Content-type': 'text/html'})
self.log_message("Youtube: sent response {}".format(message)) 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 () { describe('VideoPlayer Events', function () {
var state, videoPlayer, player, videoControl, videoCaption, var state, oldOTBD;
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; describe('HTML5', function () {
}()); beforeEach(function () {
} oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine
function initializeYouTube() { .createSpy('onTouchBasedDevice')
initialize('video.html'); .andReturn(null);
}
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null);
this.oldYT = window.YT;
jasmine.stubRequests();
window.YT = {
Player: function () {
return {
getPlaybackQuality: function () {},
getDuration: function () { return 60; }
};
},
PlayerState: this.oldYT.PlayerState,
ready: function (callback) {
callback();
}
};
});
afterEach(function () { jasmine.stubRequests();
$('source').remove();
window.onTouchBasedDevice = oldOTBD; state = jasmine.initializePlayer();
window.YT = this.oldYT;
});
it('initialize', function(){ state.videoEl = $('video, iframe');
runs(function () {
initialize();
}); });
waitsFor(function () { afterEach(function () {
return state.el.hasClass('is-initialized'); $('source').remove();
}, 'Player is not initialized.', WAIT_TIMEOUT); window.onTouchBasedDevice = oldOTBD;
});
it('initialize', function () {
waitsFor(function () {
return state.el.hasClass('is-initialized');
}, 'Player is not initialized.', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect('initialize').not.toHaveBeenTriggeredOn('.video'); expect('initialize').not.toHaveBeenTriggeredOn('.video');
});
}); });
});
it('ready', function() { it('ready', function () {
runs(function () { waitsFor(function () {
initialize(); return state.el.hasClass('is-initialized');
}, 'Player is not initialized.', WAIT_TIMEOUT);
runs(function () {
expect('ready').not.toHaveBeenTriggeredOn('.video');
});
}); });
waitsFor(function () { it('play', function () {
return state.el.hasClass('is-initialized'); state.videoPlayer.play();
}, 'Player is not initialized.', WAIT_TIMEOUT); expect('play').not.toHaveBeenTriggeredOn('.video');
});
runs(function () { it('pause', function () {
expect('ready').not.toHaveBeenTriggeredOn('.video'); state.videoPlayer.play();
state.videoPlayer.pause();
expect('pause').not.toHaveBeenTriggeredOn('.video');
}); });
});
it('play', function() { it('volumechange', function () {
initialize(); state.videoPlayer.onVolumeChange(60);
videoPlayer.play();
expect('play').not.toHaveBeenTriggeredOn('.video');
});
it('pause', function() { expect('volumechange').not.toHaveBeenTriggeredOn('.video');
initialize(); });
videoPlayer.play();
videoPlayer.pause();
expect('pause').not.toHaveBeenTriggeredOn('.video');
});
it('volumechange', function() { it('speedchange', function () {
initialize(); state.videoPlayer.onSpeedChange('2.0');
videoPlayer.onVolumeChange(60);
expect('volumechange').not.toHaveBeenTriggeredOn('.video'); expect('speedchange').not.toHaveBeenTriggeredOn('.video');
}); });
it('speedchange', function() { it('seek', function () {
initialize(); state.videoPlayer.onCaptionSeek({
videoPlayer.onSpeedChange('2.0'); time: 1,
type: 'any'
});
expect('speedchange').not.toHaveBeenTriggeredOn('.video'); expect('seek').not.toHaveBeenTriggeredOn('.video');
}); });
it('qualitychange', function() { it('ended', function () {
initializeYouTube(); state.videoPlayer.onEnded();
videoPlayer.onPlaybackQualityChange();
expect('qualitychange').not.toHaveBeenTriggeredOn('.video'); expect('ended').not.toHaveBeenTriggeredOn('.video');
});
}); });
it('seek', function() { describe('YouTube', function () {
initialize(); beforeEach(function () {
videoPlayer.onCaptionSeek({ oldOTBD = window.onTouchBasedDevice;
time: 1, window.onTouchBasedDevice = jasmine
type: 'any' .createSpy('onTouchBasedDevice')
.andReturn(null);
jasmine.stubRequests();
state = jasmine.initializePlayerYouTube();
}); });
expect('seek').not.toHaveBeenTriggeredOn('.video'); afterEach(function () {
}); $('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
it('ended', function() { it('qualitychange', function () {
initialize(); state.videoPlayer.onPlaybackQualityChange();
videoPlayer.onEnded();
expect('ended').not.toHaveBeenTriggeredOn('.video'); expect('qualitychange').not.toHaveBeenTriggeredOn('.video');
});
}); });
}); });
}).call(this); }).call(this);
(function () { (function (undefined) {
describe('Video', function () { describe('Video', function () {
var oldOTBD; var oldOTBD;
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
}); });
afterEach(function () { afterEach(function () {
window.OldVideoPlayer = undefined;
$('source').remove(); $('source').remove();
}); });
...@@ -30,10 +29,6 @@ ...@@ -30,10 +29,6 @@
expect(this.state.videoType).toEqual('youtube'); expect(this.state.videoType).toEqual('youtube');
}); });
it('reset the current video player', function () {
expect(window.OldVideoPlayer).toBeUndefined();
});
it('set the elements', function () { it('set the elements', function () {
expect(this.state.el).toBe('#video_id'); expect(this.state.el).toBe('#video_id');
}); });
...@@ -76,10 +71,6 @@ ...@@ -76,10 +71,6 @@
expect(state.videoType).toEqual('html5'); expect(state.videoType).toEqual('html5');
}); });
it('reset the current video player', function () {
expect(window.OldVideoPlayer).toBeUndefined();
});
it('set the elements', function () { it('set the elements', function () {
expect(state.el).toBe('#video_id'); expect(state.el).toBe('#video_id');
}); });
......
(function () { (function (undefined) {
describe('Video HTML5Video', function () { describe('Video HTML5Video', function () {
var state, player, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5]; var state, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5];
function initialize() {
loadFixtures('video_html5.html');
state = new Video('#example');
player = state.videoPlayer.player;
}
beforeEach(function () { beforeEach(function () {
oldOTBD = window.onTouchBasedDevice; oldOTBD = window.onTouchBasedDevice;
...@@ -14,7 +8,7 @@ ...@@ -14,7 +8,7 @@
.createSpy('onTouchBasedDevice').andReturn(null); .createSpy('onTouchBasedDevice').andReturn(null);
}); });
afterEach(function() { afterEach(function () {
state = undefined; state = undefined;
$.fn.scrollTo.reset(); $.fn.scrollTo.reset();
$('.subtitles').remove(); $('.subtitles').remove();
...@@ -24,48 +18,46 @@ ...@@ -24,48 +18,46 @@
describe('on non-Touch devices', function () { describe('on non-Touch devices', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer('video_html5.html');
player.config.events.onReady = jasmine.createSpy('onReady');
state.videoPlayer.player.config.events.onReady = jasmine.createSpy('onReady');
}); });
describe('events:', function () { describe('events:', function () {
beforeEach(function () { beforeEach(function () {
spyOn(player, 'callStateChangeCallback').andCallThrough(); spyOn(state.videoPlayer.player, 'callStateChangeCallback').andCallThrough();
}); });
describe('[click]', function () { describe('[click]', function () {
describe('when player is paused', function () { describe('when player is paused', function () {
beforeEach(function () { beforeEach(function () {
spyOn(player.video, 'play').andCallThrough(); spyOn(state.videoPlayer.player.video, 'play').andCallThrough();
player.playerState = STATUS.PAUSED; state.videoPlayer.player.playerState = STATUS.PAUSED;
$(player.videoEl).trigger('click'); $(state.videoPlayer.player.videoEl).trigger('click');
}); });
it('native play event was called', function () { 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 () { it('player state was changed', function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.PAUSED; return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.getPlayerState()) expect(state.videoPlayer.player.getPlayerState())
.toBe(STATUS.PLAYING); .toBe(STATUS.PLAYING);
}); });
}); });
it('callback was called', function () { it('callback was called', function () {
waitsFor(function () { waitsFor(function () {
var stateStatus = state.videoPlayer.player return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED;
.getPlayerState();
return stateStatus !== STATUS.PAUSED;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.callStateChangeCallback) expect(state.videoPlayer.player.callStateChangeCallback)
.toHaveBeenCalled(); .toHaveBeenCalled();
}); });
}); });
...@@ -73,33 +65,33 @@ ...@@ -73,33 +65,33 @@
describe('[player is playing]', function () { describe('[player is playing]', function () {
beforeEach(function () { beforeEach(function () {
spyOn(player.video, 'pause').andCallThrough(); spyOn(state.videoPlayer.player.video, 'pause').andCallThrough();
player.playerState = STATUS.PLAYING; state.videoPlayer.player.playerState = STATUS.PLAYING;
$(player.videoEl).trigger('click'); $(state.videoPlayer.player.videoEl).trigger('click');
}); });
it('native event was called', function () { it('native event was called', function () {
expect(player.video.pause).toHaveBeenCalled(); expect(state.videoPlayer.player.video.pause).toHaveBeenCalled();
}); });
it('player state was changed', function () { it('player state was changed', function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.PLAYING; return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.getPlayerState()) expect(state.videoPlayer.player.getPlayerState())
.toBe(STATUS.PAUSED); .toBe(STATUS.PAUSED);
}); });
}); });
it('callback was called', function () { it('callback was called', function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.PLAYING; return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.callStateChangeCallback) expect(state.videoPlayer.player.callStateChangeCallback)
.toHaveBeenCalled(); .toHaveBeenCalled();
}); });
}); });
...@@ -108,37 +100,34 @@ ...@@ -108,37 +100,34 @@
describe('[play]', function () { describe('[play]', function () {
beforeEach(function () { beforeEach(function () {
spyOn(player.video, 'play').andCallThrough(); spyOn(state.videoPlayer.player.video, 'play').andCallThrough();
player.playerState = STATUS.PAUSED; state.videoPlayer.player.playerState = STATUS.PAUSED;
player.playVideo(); state.videoPlayer.player.playVideo();
}); });
it('native event was called', function () { it('native event was called', function () {
expect(player.video.play).toHaveBeenCalled(); expect(state.videoPlayer.player.video.play).toHaveBeenCalled();
}); });
it('player state was changed', function () { it('player state was changed', function () {
waitsFor(function () { waitsFor(function () {
var state = player.getPlayerState(); return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED;
return state !== STATUS.PAUSED;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.getPlayerState()).toBe(STATUS.PLAYING); expect(state.videoPlayer.player.getPlayerState())
.toBe(STATUS.PLAYING);
}); });
}); });
it('callback was called', function () { it('callback was called', function () {
waitsFor(function () { waitsFor(function () {
var state = player.getPlayerState(); return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED;
return state !== STATUS.PAUSED;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.callStateChangeCallback) expect(state.videoPlayer.player.callStateChangeCallback)
.toHaveBeenCalled(); .toHaveBeenCalled();
}); });
}); });
...@@ -146,35 +135,36 @@ ...@@ -146,35 +135,36 @@
describe('[pause]', function () { describe('[pause]', function () {
beforeEach(function () { beforeEach(function () {
spyOn(player.video, 'pause').andCallThrough(); spyOn(state.videoPlayer.player.video, 'pause').andCallThrough();
player.playerState = STATUS.UNSTARTED; state.videoPlayer.player.playerState = STATUS.UNSTARTED;
player.playVideo(); state.videoPlayer.player.playVideo();
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.UNSTARTED; return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED;
}, 'Video never started playing', WAIT_TIMEOUT); }, 'Video never started playing', WAIT_TIMEOUT);
player.pauseVideo(); state.videoPlayer.player.pauseVideo();
}); });
it('native event was called', function () { it('native event was called', function () {
expect(player.video.pause).toHaveBeenCalled(); expect(state.videoPlayer.player.video.pause).toHaveBeenCalled();
}); });
it('player state was changed', function () { it('player state was changed', function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.PLAYING; return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.getPlayerState()).toBe(STATUS.PAUSED); expect(state.videoPlayer.player.getPlayerState())
.toBe(STATUS.PAUSED);
}); });
}); });
it('callback was called', function () { it('callback was called', function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.PLAYING; return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING;
}, 'Player state should be changed', WAIT_TIMEOUT); }, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.callStateChangeCallback) expect(state.videoPlayer.player.callStateChangeCallback)
.toHaveBeenCalled(); .toHaveBeenCalled();
}); });
}); });
...@@ -186,13 +176,14 @@ ...@@ -186,13 +176,14 @@
'onReady called', function () 'onReady called', function ()
{ {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.UNSTARTED; return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED;
}, 'Video cannot be played', WAIT_TIMEOUT); }, 'Video cannot be played', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(player.getPlayerState()).toBe(STATUS.PAUSED); expect(state.videoPlayer.player.getPlayerState())
expect(player.video.currentTime).toBe(0); .toBe(STATUS.PAUSED);
expect(player.config.events.onReady) expect(state.videoPlayer.player.video.currentTime).toBe(0);
expect(state.videoPlayer.player.config.events.onReady)
.toHaveBeenCalled(); .toHaveBeenCalled();
}); });
}); });
...@@ -201,20 +192,21 @@ ...@@ -201,20 +192,21 @@
describe('[ended]', function () { describe('[ended]', function () {
beforeEach(function () { beforeEach(function () {
waitsFor(function () { waitsFor(function () {
return player.getPlayerState() !== STATUS.UNSTARTED; return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED;
}, 'Video cannot be played', WAIT_TIMEOUT); }, 'Video cannot be played', WAIT_TIMEOUT);
}); });
it('player state was changed', function () { it('player state was changed', function () {
runs(function () { runs(function () {
jasmine.fireEvent(player.video, 'ended'); jasmine.fireEvent(state.videoPlayer.player.video, 'ended');
expect(player.getPlayerState()).toBe(STATUS.ENDED); expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED);
}); });
}); });
it('callback was called', function () { it('callback was called', function () {
jasmine.fireEvent(player.video, 'ended'); jasmine.fireEvent(state.videoPlayer.player.video, 'ended');
expect(player.callStateChangeCallback).toHaveBeenCalled(); expect(state.videoPlayer.player.callStateChangeCallback)
.toHaveBeenCalled();
}); });
}); });
}); });
...@@ -224,36 +216,36 @@ ...@@ -224,36 +216,36 @@
beforeEach(function () { beforeEach(function () {
waitsFor(function () { waitsFor(function () {
volume = player.video.volume; volume = state.videoPlayer.player.video.volume;
seek = player.video.currentTime; seek = state.videoPlayer.player.video.currentTime;
return player.playerState === STATUS.PAUSED; return state.videoPlayer.player.playerState === STATUS.PAUSED;
}, 'Video cannot be played', WAIT_TIMEOUT); }, 'Video cannot be played', WAIT_TIMEOUT);
}); });
it('pauseVideo', function () { it('pauseVideo', function () {
runs(function () { runs(function () {
spyOn(player.video, 'pause').andCallThrough(); spyOn(state.videoPlayer.player.video, 'pause').andCallThrough();
player.pauseVideo(); state.videoPlayer.player.pauseVideo();
expect(player.video.pause).toHaveBeenCalled(); expect(state.videoPlayer.player.video.pause).toHaveBeenCalled();
}); });
}); });
describe('seekTo', function () { describe('seekTo', function () {
it('set new correct value', function () { it('set new correct value', function () {
runs(function () { runs(function () {
player.seekTo(2); state.videoPlayer.player.seekTo(2);
expect(player.getCurrentTime()).toBe(2); expect(state.videoPlayer.player.getCurrentTime()).toBe(2);
}); });
}); });
it('set new inccorrect values', function () { it('set new inccorrect values', function () {
runs(function () { runs(function () {
player.seekTo(-50); state.videoPlayer.player.seekTo(-50);
expect(player.getCurrentTime()).toBe(seek); expect(state.videoPlayer.player.getCurrentTime()).toBe(seek);
player.seekTo('5'); state.videoPlayer.player.seekTo('5');
expect(player.getCurrentTime()).toBe(seek); expect(state.videoPlayer.player.getCurrentTime()).toBe(seek);
player.seekTo(500000); state.videoPlayer.player.seekTo(500000);
expect(player.getCurrentTime()).toBe(seek); expect(state.videoPlayer.player.getCurrentTime()).toBe(seek);
}); });
}); });
}); });
...@@ -261,88 +253,89 @@ ...@@ -261,88 +253,89 @@
describe('setVolume', function () { describe('setVolume', function () {
it('set new correct value', function () { it('set new correct value', function () {
runs(function () { runs(function () {
player.setVolume(50); state.videoPlayer.player.setVolume(50);
expect(player.getVolume()).toBe(50 * 0.01); expect(state.videoPlayer.player.getVolume()).toBe(50 * 0.01);
}); });
}); });
it('set new incorrect values', function () { it('set new incorrect values', function () {
runs(function () { runs(function () {
player.setVolume(-50); state.videoPlayer.player.setVolume(-50);
expect(player.getVolume()).toBe(volume); expect(state.videoPlayer.player.getVolume()).toBe(volume);
player.setVolume('5'); state.videoPlayer.player.setVolume('5');
expect(player.getVolume()).toBe(volume); expect(state.videoPlayer.player.getVolume()).toBe(volume);
player.setVolume(500000); state.videoPlayer.player.setVolume(500000);
expect(player.getVolume()).toBe(volume); expect(state.videoPlayer.player.getVolume()).toBe(volume);
}); });
}); });
}); });
it('getCurrentTime', function () { it('getCurrentTime', function () {
runs(function () { runs(function () {
player.video.currentTime = 3; state.videoPlayer.player.video.currentTime = 3;
expect(player.getCurrentTime()) expect(state.videoPlayer.player.getCurrentTime())
.toBe(player.video.currentTime); .toBe(state.videoPlayer.player.video.currentTime);
}); });
}); });
it('playVideo', function () { it('playVideo', function () {
runs(function () { runs(function () {
spyOn(player.video, 'play').andCallThrough(); spyOn(state.videoPlayer.player.video, 'play').andCallThrough();
player.playVideo(); state.videoPlayer.player.playVideo();
expect(player.video.play).toHaveBeenCalled(); expect(state.videoPlayer.player.video.play).toHaveBeenCalled();
}); });
}); });
it('getPlayerState', function () { it('getPlayerState', function () {
runs(function () { runs(function () {
player.playerState = STATUS.PLAYING; state.videoPlayer.player.playerState = STATUS.PLAYING;
expect(player.getPlayerState()).toBe(STATUS.PLAYING); expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.PLAYING);
player.playerState = STATUS.ENDED; state.videoPlayer.player.playerState = STATUS.ENDED;
expect(player.getPlayerState()).toBe(STATUS.ENDED); expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED);
}); });
}); });
it('getVolume', function () { it('getVolume', function () {
runs(function () { runs(function () {
volume = player.video.volume = 0.5; volume = state.videoPlayer.player.video.volume = 0.5;
expect(player.getVolume()).toBe(volume); expect(state.videoPlayer.player.getVolume()).toBe(volume);
}); });
}); });
it('getDuration', function () { it('getDuration', function () {
runs(function () { runs(function () {
duration = player.video.duration; duration = state.videoPlayer.player.video.duration;
expect(player.getDuration()).toBe(duration); expect(state.videoPlayer.player.getDuration()).toBe(duration);
}); });
}); });
describe('setPlaybackRate', function () { describe('setPlaybackRate', function () {
it('set a correct value', function () { it('set a correct value', function () {
playbackRate = 1.5; playbackRate = 1.5;
player.setPlaybackRate(playbackRate); state.videoPlayer.player.setPlaybackRate(playbackRate);
expect(player.video.playbackRate).toBe(playbackRate); expect(state.videoPlayer.player.video.playbackRate).toBe(playbackRate);
}); });
it('set NaN value', function () { 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 // When we try setting the playback rate to some
// non-numerical value, nothing should happen. // non-numerical value, nothing should happen.
playbackRate = NaN; playbackRate = NaN;
player.setPlaybackRate(playbackRate); state.videoPlayer.player.setPlaybackRate(playbackRate);
expect(player.video.playbackRate).toBe(oldPlaybackRate); expect(state.videoPlayer.player.video.playbackRate)
.toBe(oldPlaybackRate);
}); });
}); });
it('getAvailablePlaybackRates', function () { it('getAvailablePlaybackRates', function () {
expect(player.getAvailablePlaybackRates()) expect(state.videoPlayer.player.getAvailablePlaybackRates())
.toEqual(playbackRates); .toEqual(playbackRates);
}); });
it('_getLogs', function () { it('_getLogs', function () {
runs(function () { runs(function () {
var logs = player._getLogs(); var logs = state.videoPlayer.player._getLogs();
expect(logs).toEqual(jasmine.any(Array)); expect(logs).toEqual(jasmine.any(Array));
expect(logs.length).toBeGreaterThan(0); expect(logs.length).toBeGreaterThan(0);
}); });
...@@ -352,8 +345,10 @@ ...@@ -352,8 +345,10 @@
it('native controls are used on iPhone', function () { it('native controls are used on iPhone', function () {
window.onTouchBasedDevice.andReturn(['iPhone']); 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'); expect($('video')).toHaveAttr('controls');
}); });
......
(function (requirejs, require, define) { (function (requirejs, require, define, undefined) {
require( require(
['video/00_resizer.js'], ['video/00_resizer.js'],
...@@ -104,7 +104,7 @@ function (Resizer) { ...@@ -104,7 +104,7 @@ function (Resizer) {
beforeEach(function () { beforeEach(function () {
var spiesCount = _.range(3); var spiesCount = _.range(3);
spiesList = $.map(spiesCount, function() { spiesList = $.map(spiesCount, function () {
return jasmine.createSpy(); return jasmine.createSpy();
}); });
...@@ -113,13 +113,13 @@ function (Resizer) { ...@@ -113,13 +113,13 @@ function (Resizer) {
it('callbacks are called', function () { it('callbacks are called', function () {
$.each(spiesList, function(index, spy) { $.each(spiesList, function (index, spy) {
resizer.callbacks.add(spy); resizer.callbacks.add(spy);
}); });
resizer.align(); resizer.align();
$.each(spiesList, function(index, spy) { $.each(spiesList, function (index, spy) {
expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalled();
}); });
}); });
...@@ -135,20 +135,20 @@ function (Resizer) { ...@@ -135,20 +135,20 @@ function (Resizer) {
}); });
it('All callbacks are removed', function () { it('All callbacks are removed', function () {
$.each(spiesList, function(index, spy) { $.each(spiesList, function (index, spy) {
resizer.callbacks.add(spy); resizer.callbacks.add(spy);
}); });
resizer.callbacks.removeAll(); resizer.callbacks.removeAll();
resizer.align(); resizer.align();
$.each(spiesList, function(index, spy) { $.each(spiesList, function (index, spy) {
expect(spy).not.toHaveBeenCalled(); expect(spy).not.toHaveBeenCalled();
}); });
}); });
it('Specific callback is removed', function () { it('Specific callback is removed', function () {
$.each(spiesList, function(index, spy) { $.each(spiesList, function (index, spy) {
resizer.callbacks.add(spy); resizer.callbacks.add(spy);
}); });
...@@ -158,14 +158,17 @@ function (Resizer) { ...@@ -158,14 +158,17 @@ function (Resizer) {
expect(spiesList[1]).not.toHaveBeenCalled(); 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'], var methods = ['add', 'once'],
errorMessage = 'TypeError: Argument is not a function.', errorMessage = 'TypeError: Argument is not a function.',
arg = {}; arg = {};
spyOn(console, 'error'); spyOn(console, 'error');
$.each(methods, function(index, methodName) { $.each(methods, function (index, methodName) {
resizer.callbacks[methodName](arg); resizer.callbacks[methodName](arg);
expect(console.error).toHaveBeenCalledWith(errorMessage); expect(console.error).toHaveBeenCalledWith(errorMessage);
//reset spy //reset spy
......
(function () { (function (undefined) {
describe('VideoCaption', function () { describe('VideoCaption', function () {
var state, videoPlayer, videoCaption, videoSpeedControl, oldOTBD; var state, 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();
}
beforeEach(function () { beforeEach(function () {
oldOTBD = window.onTouchBasedDevice; oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null); .andReturn(null);
initialize();
state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
afterEach(function () { afterEach(function () {
YT.Player = undefined;
$('.subtitles').remove(); $('.subtitles').remove();
// `source` tags should be removed to avoid memory leak bug that we // `source` tags should be removed to avoid memory leak bug that we
...@@ -35,7 +29,12 @@ ...@@ -35,7 +29,12 @@
describe('always', function () { describe('always', function () {
beforeEach(function () { beforeEach(function () {
spyOn($, 'ajaxWithPrefix').andCallThrough(); spyOn($, 'ajaxWithPrefix').andCallThrough();
initialize();
state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
it('create the caption element', function () { it('create the caption element', function () {
...@@ -57,7 +56,7 @@ ...@@ -57,7 +56,7 @@
it('fetch the caption', function () { it('fetch the caption', function () {
waitsFor(function () { waitsFor(function () {
if (videoCaption.loaded === true) { if (state.videoCaption.loaded === true) {
return true; return true;
} }
...@@ -66,7 +65,7 @@ ...@@ -66,7 +65,7 @@
runs(function () { runs(function () {
expect($.ajaxWithPrefix).toHaveBeenCalledWith({ expect($.ajaxWithPrefix).toHaveBeenCalledWith({
url: videoCaption.captionURL(), url: state.videoCaption.captionURL(),
notifyOnError: false, notifyOnError: false,
success: jasmine.any(Function), success: jasmine.any(Function),
error: jasmine.any(Function) error: jasmine.any(Function)
...@@ -76,37 +75,37 @@ ...@@ -76,37 +75,37 @@
it('bind window resize event', function () { it('bind window resize event', function () {
expect($(window)).toHandleWith( expect($(window)).toHandleWith(
'resize', videoCaption.resize 'resize', state.videoCaption.resize
); );
}); });
it('bind the hide caption button', function () { it('bind the hide caption button', function () {
expect($('.hide-subtitles')).toHandleWith( expect($('.hide-subtitles')).toHandleWith(
'click', videoCaption.toggle 'click', state.videoCaption.toggle
); );
}); });
it('bind the mouse movement', function () { it('bind the mouse movement', function () {
expect($('.subtitles')).toHandleWith( expect($('.subtitles')).toHandleWith(
'mouseover', videoCaption.onMouseEnter 'mouseover', state.videoCaption.onMouseEnter
); );
expect($('.subtitles')).toHandleWith( expect($('.subtitles')).toHandleWith(
'mouseout', videoCaption.onMouseLeave 'mouseout', state.videoCaption.onMouseLeave
); );
expect($('.subtitles')).toHandleWith( expect($('.subtitles')).toHandleWith(
'mousemove', videoCaption.onMovement 'mousemove', state.videoCaption.onMovement
); );
expect($('.subtitles')).toHandleWith( expect($('.subtitles')).toHandleWith(
'mousewheel', videoCaption.onMovement 'mousewheel', state.videoCaption.onMovement
); );
expect($('.subtitles')).toHandleWith( expect($('.subtitles')).toHandleWith(
'DOMMouseScroll', videoCaption.onMovement 'DOMMouseScroll', state.videoCaption.onMovement
); );
}); });
it('bind the scroll', function () { it('bind the scroll', function () {
expect($('.subtitles')) expect($('.subtitles'))
.toHandleWith('scroll', videoCaption.autoShowCaptions); .toHandleWith('scroll', state.videoCaption.autoShowCaptions);
expect($('.subtitles')) expect($('.subtitles'))
.toHandleWith('scroll', videoControl.showControls); .toHandleWith('scroll', videoControl.showControls);
}); });
...@@ -114,7 +113,11 @@ ...@@ -114,7 +113,11 @@
describe('when on a non touch-based device', function () { describe('when on a non touch-based device', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
it('render the caption', function () { it('render the caption', function () {
...@@ -145,38 +148,43 @@ ...@@ -145,38 +148,43 @@
function (index, link) { function (index, link) {
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mouseover', videoCaption.captionMouseOverOut 'mouseover', state.videoCaption.captionMouseOverOut
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mouseout', videoCaption.captionMouseOverOut 'mouseout', state.videoCaption.captionMouseOverOut
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mousedown', videoCaption.captionMouseDown 'mousedown', state.videoCaption.captionMouseDown
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'click', videoCaption.captionClick 'click', state.videoCaption.captionClick
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'focus', videoCaption.captionFocus 'focus', state.videoCaption.captionFocus
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'blur', videoCaption.captionBlur 'blur', state.videoCaption.captionBlur
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'keydown', videoCaption.captionKeyDown 'keydown', state.videoCaption.captionKeyDown
); );
}); });
}); });
it('set rendered to true', function () { it('set rendered to true', function () {
expect(videoCaption.rendered).toBeTruthy(); expect(state.videoCaption.rendered).toBeTruthy();
}); });
}); });
describe('when on a touch-based device', function () { describe('when on a touch-based device', function () {
beforeEach(function () { beforeEach(function () {
window.onTouchBasedDevice.andReturn(['iPad']); window.onTouchBasedDevice.andReturn(['iPad']);
initialize();
state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
it('show explaination message', function () { it('show explaination message', function () {
...@@ -187,7 +195,7 @@ ...@@ -187,7 +195,7 @@
}); });
it('does not set rendered to true', function () { it('does not set rendered to true', function () {
expect(videoCaption.rendered).toBeFalsy(); expect(state.videoCaption.rendered).toBeFalsy();
}); });
}); });
...@@ -199,11 +207,10 @@ ...@@ -199,11 +207,10 @@
$('#example').find('#video_id').data('sub', ''); $('#example').find('#video_id').data('sub', '');
state = new Video('#example'); state = new Video('#example');
videoCaption = state.videoCaption;
}); });
it('captions panel is not shown', function () { it('captions panel is not shown', function () {
expect(videoCaption.hideSubtitlesEl).toBeHidden(); expect(state.videoCaption.hideSubtitlesEl).toBeHidden();
}); });
}); });
}); });
...@@ -221,20 +228,20 @@ ...@@ -221,20 +228,20 @@
}); });
it('does not set freezing timeout', function () { 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 () { describe('when cursor is in the caption box', function () {
beforeEach(function () { beforeEach(function () {
spyOn(videoCaption, 'onMouseLeave'); spyOn(state.videoCaption, 'onMouseLeave');
$('.subtitles').trigger(jQuery.Event('mouseenter')); $('.subtitles').trigger(jQuery.Event('mouseenter'));
jasmine.Clock.tick(state.config.captionsFreezeTime); jasmine.Clock.tick(state.config.captionsFreezeTime);
}); });
it('set the freezing timeout', function () { it('set the freezing timeout', function () {
expect(videoCaption.frozen).not.toBeFalsy(); expect(state.videoCaption.frozen).not.toBeFalsy();
expect(videoCaption.onMouseLeave).toHaveBeenCalled(); expect(state.videoCaption.onMouseLeave).toHaveBeenCalled();
}); });
describe('when the cursor is moving', function () { describe('when the cursor is moving', function () {
...@@ -263,7 +270,7 @@ ...@@ -263,7 +270,7 @@
function () { function () {
beforeEach(function () { beforeEach(function () {
videoCaption.frozen = 100; state.videoCaption.frozen = 100;
$.fn.scrollTo.reset(); $.fn.scrollTo.reset();
}); });
...@@ -277,13 +284,13 @@ ...@@ -277,13 +284,13 @@
}); });
it('unfreeze the caption', function () { it('unfreeze the caption', function () {
expect(videoCaption.frozen).toBeNull(); expect(state.videoCaption.frozen).toBeNull();
}); });
}); });
describe('when the player is playing', function () { describe('when the player is playing', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.playing = true; state.videoCaption.playing = true;
$('.subtitles li[data-index]:first') $('.subtitles li[data-index]:first')
.addClass('current'); .addClass('current');
$('.subtitles').trigger(jQuery.Event('mouseout')); $('.subtitles').trigger(jQuery.Event('mouseout'));
...@@ -296,7 +303,7 @@ ...@@ -296,7 +303,7 @@
describe('when the player is not playing', function () { describe('when the player is not playing', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.playing = false; state.videoCaption.playing = false;
$('.subtitles').trigger(jQuery.Event('mouseout')); $('.subtitles').trigger(jQuery.Event('mouseout'));
}); });
...@@ -309,12 +316,12 @@ ...@@ -309,12 +316,12 @@
describe('search', function () { describe('search', function () {
it('return a correct caption index', function () { it('return a correct caption index', function () {
expect(videoCaption.search(0)).toEqual(-1); expect(state.videoCaption.search(0)).toEqual(-1);
expect(videoCaption.search(3120)).toEqual(1); expect(state.videoCaption.search(3120)).toEqual(1);
expect(videoCaption.search(6270)).toEqual(2); expect(state.videoCaption.search(6270)).toEqual(2);
expect(videoCaption.search(8490)).toEqual(2); expect(state.videoCaption.search(8490)).toEqual(2);
expect(videoCaption.search(21620)).toEqual(4); expect(state.videoCaption.search(21620)).toEqual(4);
expect(videoCaption.search(24920)).toEqual(5); expect(state.videoCaption.search(24920)).toEqual(5);
}); });
}); });
...@@ -322,8 +329,14 @@ ...@@ -322,8 +329,14 @@
describe('when the caption was not rendered', function () { describe('when the caption was not rendered', function () {
beforeEach(function () { beforeEach(function () {
window.onTouchBasedDevice.andReturn(['iPad']); window.onTouchBasedDevice.andReturn(['iPad']);
initialize();
videoCaption.play(); state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
state.videoCaption.play();
}); });
it('render the caption', function () { it('render the caption', function () {
...@@ -352,78 +365,78 @@ ...@@ -352,78 +365,78 @@
function (index, link) { function (index, link) {
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mouseover', videoCaption.captionMouseOverOut 'mouseover', state.videoCaption.captionMouseOverOut
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mouseout', videoCaption.captionMouseOverOut 'mouseout', state.videoCaption.captionMouseOverOut
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'mousedown', videoCaption.captionMouseDown 'mousedown', state.videoCaption.captionMouseDown
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'click', videoCaption.captionClick 'click', state.videoCaption.captionClick
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'focus', videoCaption.captionFocus 'focus', state.videoCaption.captionFocus
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'blur', videoCaption.captionBlur 'blur', state.videoCaption.captionBlur
); );
expect($(link)).toHandleWith( expect($(link)).toHandleWith(
'keydown', videoCaption.captionKeyDown 'keydown', state.videoCaption.captionKeyDown
); );
}); });
}); });
it('set rendered to true', function () { it('set rendered to true', function () {
expect(videoCaption.rendered).toBeTruthy(); expect(state.videoCaption.rendered).toBeTruthy();
}); });
it('set playing to true', function () { it('set playing to true', function () {
expect(videoCaption.playing).toBeTruthy(); expect(state.videoCaption.playing).toBeTruthy();
}); });
}); });
}); });
describe('pause', function () { describe('pause', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.playing = true; state.videoCaption.playing = true;
videoCaption.pause(); state.videoCaption.pause();
}); });
it('set playing to false', function () { it('set playing to false', function () {
expect(videoCaption.playing).toBeFalsy(); expect(state.videoCaption.playing).toBeFalsy();
}); });
}); });
describe('updatePlayTime', function () { describe('updatePlayTime', function () {
describe('when the video speed is 1.0x', function () { describe('when the video speed is 1.0x', function () {
beforeEach(function () { beforeEach(function () {
videoSpeedControl.currentSpeed = '1.0'; state.videoSpeedControl.currentSpeed = '1.0';
videoCaption.updatePlayTime(25.000); state.videoCaption.updatePlayTime(25.000);
}); });
it('search the caption based on time', function () { 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 () { describe('when the video speed is not 1.0x', function () {
beforeEach(function () { beforeEach(function () {
videoSpeedControl.currentSpeed = '0.75'; state.videoSpeedControl.currentSpeed = '0.75';
videoCaption.updatePlayTime(25.000); state.videoCaption.updatePlayTime(25.000);
}); });
it('search the caption based on 1.0x speed', function () { 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 () { describe('when the index is not the same', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.currentIndex = 1; state.videoCaption.currentIndex = 1;
$('.subtitles li[data-index=5]').addClass('current'); $('.subtitles li[data-index=5]').addClass('current');
videoCaption.updatePlayTime(25.000); state.videoCaption.updatePlayTime(25.000);
}); });
it('deactivate the previous caption', function () { it('deactivate the previous caption', function () {
...@@ -437,7 +450,7 @@ ...@@ -437,7 +450,7 @@
}); });
it('save new index', function () { 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 // Disabled 11/25/13 due to flakiness in master
...@@ -448,9 +461,9 @@ ...@@ -448,9 +461,9 @@
describe('when the index is the same', function () { describe('when the index is the same', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.currentIndex = 1; state.videoCaption.currentIndex = 1;
$('.subtitles li[data-index=3]').addClass('current'); $('.subtitles li[data-index=3]').addClass('current');
videoCaption.updatePlayTime(15.000); state.videoCaption.updatePlayTime(15.000);
}); });
it('does not change current subtitle', function () { it('does not change current subtitle', function () {
...@@ -462,9 +475,14 @@ ...@@ -462,9 +475,14 @@
describe('resize', function () { describe('resize', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.resize(); state.videoCaption.resize();
}); });
describe('set the height of caption container', function () { describe('set the height of caption container', function () {
...@@ -484,7 +502,7 @@ ...@@ -484,7 +502,7 @@
controlHeight, shouldBeHeight; controlHeight, shouldBeHeight;
state.captionsHidden = true; state.captionsHidden = true;
videoCaption.setSubtitlesHeight(); state.videoCaption.setSubtitlesHeight();
realHeight = parseInt( realHeight = parseInt(
$('.subtitles').css('maxHeight'), 10 $('.subtitles').css('maxHeight'), 10
...@@ -510,9 +528,9 @@ ...@@ -510,9 +528,9 @@
$('.subtitles .spacing:last').css('height'), 10 $('.subtitles .spacing:last').css('height'), 10
)); ));
expect(firstSpacing - videoCaption.topSpacingHeight()) expect(firstSpacing - state.videoCaption.topSpacingHeight())
.toBeLessThan(1); .toBeLessThan(1);
expect(lastSpacing - videoCaption.bottomSpacingHeight()) expect(lastSpacing - state.videoCaption.bottomSpacingHeight())
.toBeLessThan(1); .toBeLessThan(1);
}); });
...@@ -524,14 +542,18 @@ ...@@ -524,14 +542,18 @@
// Disabled 11/25/13 due to flakiness in master // Disabled 11/25/13 due to flakiness in master
xdescribe('scrollCaption', function () { xdescribe('scrollCaption', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
describe('when frozen', function () { describe('when frozen', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.frozen = true; state.videoCaption.frozen = true;
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.scrollCaption(); state.videoCaption.scrollCaption();
}); });
it('does not scroll the caption', function () { it('does not scroll the caption', function () {
...@@ -541,12 +563,12 @@ ...@@ -541,12 +563,12 @@
describe('when not frozen', function () { describe('when not frozen', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.frozen = false; state.videoCaption.frozen = false;
}); });
describe('when there is no current caption', function () { describe('when there is no current caption', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.scrollCaption(); state.videoCaption.scrollCaption();
}); });
it('does not scroll the caption', function () { it('does not scroll the caption', function () {
...@@ -557,7 +579,7 @@ ...@@ -557,7 +579,7 @@
describe('when there is a current caption', function () { describe('when there is a current caption', function () {
beforeEach(function () { beforeEach(function () {
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.scrollCaption(); state.videoCaption.scrollCaption();
}); });
it('scroll to current caption', function () { it('scroll to current caption', function () {
...@@ -571,24 +593,29 @@ ...@@ -571,24 +593,29 @@
xdescribe('seekPlayer', function () { xdescribe('seekPlayer', function () {
describe('when the video speed is 1.0x', function () { describe('when the video speed is 1.0x', function () {
beforeEach(function () { beforeEach(function () {
videoSpeedControl.currentSpeed = '1.0'; state.videoSpeedControl.currentSpeed = '1.0';
$('.subtitles li[data-start="14910"]').trigger('click'); $('.subtitles li[data-start="14910"]').trigger('click');
}); });
it('trigger seek event with the correct time', function () { 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 () { describe('when the video speed is not 1.0x', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoSpeedControl.currentSpeed = '0.75';
videoControl = state.videoControl;
$.fn.scrollTo.reset();
state.videoSpeedControl.currentSpeed = '0.75';
$('.subtitles li[data-start="14910"]').trigger('click'); $('.subtitles li[data-start="14910"]').trigger('click');
}); });
it('trigger seek event with the correct time', function () { 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 @@ ...@@ -596,36 +623,46 @@
function () { function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoSpeedControl.currentSpeed = '0.75';
videoControl = state.videoControl;
$.fn.scrollTo.reset();
state.videoSpeedControl.currentSpeed = '0.75';
state.currentPlayerMode = 'flash'; state.currentPlayerMode = 'flash';
$('.subtitles li[data-start="14910"]').trigger('click'); $('.subtitles li[data-start="14910"]').trigger('click');
}); });
it('trigger seek event with the correct time', function () { it('trigger seek event with the correct time', function () {
expect(videoPlayer.currentTime).toEqual(15); expect(state.videoPlayer.currentTime).toEqual(15);
}); });
}); });
}); });
describe('toggle', function () { describe('toggle', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoPlayer, 'log');
videoControl = state.videoControl;
$.fn.scrollTo.reset();
spyOn(state.videoPlayer, 'log');
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
}); });
describe('when the caption is visible', function () { describe('when the caption is visible', function () {
beforeEach(function () { beforeEach(function () {
state.el.removeClass('closed'); state.el.removeClass('closed');
videoCaption.toggle(jQuery.Event('click')); state.videoCaption.toggle(jQuery.Event('click'));
}); });
it('log the hide_transcript event', function () { it('log the hide_transcript event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'hide_transcript', 'hide_transcript',
{ {
currentTime: videoPlayer.currentTime currentTime: state.videoPlayer.currentTime
} }
); );
}); });
...@@ -643,16 +680,16 @@ ...@@ -643,16 +680,16 @@
describe('when the caption is hidden', function () { describe('when the caption is hidden', function () {
beforeEach(function () { beforeEach(function () {
state.el.addClass('closed'); state.el.addClass('closed');
videoCaption.toggle(jQuery.Event('click')); state.videoCaption.toggle(jQuery.Event('click'));
jasmine.Clock.useMock(); jasmine.Clock.useMock();
}); });
it('log the show_transcript event', function () { it('log the show_transcript event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'show_transcript', 'show_transcript',
{ {
currentTime: videoPlayer.currentTime currentTime: state.videoPlayer.currentTime
} }
); );
}); });
...@@ -685,12 +722,16 @@ ...@@ -685,12 +722,16 @@
describe('caption accessibility', function () { describe('caption accessibility', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
}); });
describe('when getting focus through TAB key', function () { describe('when getting focus through TAB key', function () {
beforeEach(function () { beforeEach(function () {
videoCaption.isMouseFocus = false; state.videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]').trigger( $('.subtitles li[data-index=0]').trigger(
jQuery.Event('focus') jQuery.Event('focus')
); );
...@@ -702,7 +743,7 @@ ...@@ -702,7 +743,7 @@
}); });
it('has automatic scrolling disabled', function () { it('has automatic scrolling disabled', function () {
expect(videoCaption.autoScrolling).toBe(false); expect(state.videoCaption.autoScrolling).toBe(false);
}); });
}); });
...@@ -719,7 +760,7 @@ ...@@ -719,7 +760,7 @@
}); });
it('has automatic scrolling enabled', function () { it('has automatic scrolling enabled', function () {
expect(videoCaption.autoScrolling).toBe(true); expect(state.videoCaption.autoScrolling).toBe(true);
}); });
}); });
...@@ -729,7 +770,7 @@ ...@@ -729,7 +770,7 @@
function () { function () {
beforeEach(function () { beforeEach(function () {
videoCaption.isMouseFocus = false; state.videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]') $('.subtitles li[data-index=0]')
.trigger(jQuery.Event('focus')); .trigger(jQuery.Event('focus'));
$('.subtitles li[data-index=0]') $('.subtitles li[data-index=0]')
...@@ -742,7 +783,7 @@ ...@@ -742,7 +783,7 @@
}); });
it('has automatic scrolling enabled', function () { it('has automatic scrolling enabled', function () {
expect(videoCaption.autoScrolling).toBe(true); expect(state.videoCaption.autoScrolling).toBe(true);
}); });
}); });
...@@ -757,12 +798,12 @@ ...@@ -757,12 +798,12 @@
subDataLiIdx__0 = $('.subtitles li[data-index=0]'); subDataLiIdx__0 = $('.subtitles li[data-index=0]');
subDataLiIdx__1 = $('.subtitles li[data-index=1]'); 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('focus'));
subDataLiIdx__0.trigger(jQuery.Event('blur')); subDataLiIdx__0.trigger(jQuery.Event('blur'));
videoCaption.isMouseFocus = true; state.videoCaption.isMouseFocus = true;
subDataLiIdx__1.trigger(jQuery.Event('mousedown')); subDataLiIdx__1.trigger(jQuery.Event('mousedown'));
}); });
...@@ -776,7 +817,7 @@ ...@@ -776,7 +817,7 @@
}); });
it('has automatic scrolling enabled', function () { it('has automatic scrolling enabled', function () {
expect(videoCaption.autoScrolling).toBe(true); expect(state.videoCaption.autoScrolling).toBe(true);
}); });
}); });
}); });
......
(function() { (function (undefined) {
describe('VideoControl', function() { describe('VideoControl', function () {
var state, videoControl, oldOTBD; var state, oldOTBD;
function initialize(fixture) { beforeEach(function () {
if (fixture) { oldOTBD = window.onTouchBasedDevice;
loadFixtures(fixture); window.onTouchBasedDevice = jasmine
} else { .createSpy('onTouchBasedDevice').andReturn(null);
loadFixtures('video_all.html');
}
state = new Video('#example');
videoControl = state.videoControl;
}
function initializeYouTube() {
initialize('video.html');
}
beforeEach(function(){
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
});
afterEach(function() {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() {
beforeEach(function() {
initialize();
});
it('render the video controls', function() {
expect($('.video-controls')).toContain(
['.slider', 'ul.vcr', 'a.play', '.vidtime', '.add-fullscreen'].join(',')
);
expect($('.video-controls').find('.vidtime')).toHaveText('0:00 / 0:00');
});
it('add ARIA attributes to time control', function () {
var timeControl = $('div.slider>a');
expect(timeControl).toHaveAttrs({
'role': 'slider',
'title': 'video position',
'aria-disabled': 'false'
});
expect(timeControl).toHaveAttr('aria-valuetext');
});
it('add ARIA attributes to play control', function () {
var playControl = $('ul.vcr a');
expect(playControl).toHaveAttrs({
'role': 'button',
'title': 'Play',
'aria-disabled': 'false'
});
});
it('add ARIA attributes to fullscreen control', function () {
var fullScreenControl = $('a.add-fullscreen');
expect(fullScreenControl).toHaveAttrs({
'role': 'button',
'title': 'Fill browser',
'aria-disabled': 'false'
});
});
it('bind the playback button', function() {
expect($('.video_control')).toHandleWith('click', videoControl.togglePlayback);
});
describe('when on a non-touch based device', function() {
beforeEach(function() {
initialize();
});
it('add the play class to video control', function() {
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr('title', 'Play');
});
});
describe('when on a touch based device', function() {
beforeEach(function() {
window.onTouchBasedDevice.andReturn(['iPad']);
initialize();
});
it('does not add the play class to video control', function() {
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr('title', 'Play');
});
});
});
describe('play', function() {
beforeEach(function() {
initialize();
videoControl.play();
});
it('switch playback button to play state', function() {
expect($('.video_control')).not.toHaveClass('play');
expect($('.video_control')).toHaveClass('pause');
expect($('.video_control')).toHaveAttr('title', 'Pause');
});
});
describe('pause', function() {
beforeEach(function() {
initialize();
videoControl.pause();
});
it('switch playback button to pause state', function() {
expect($('.video_control')).not.toHaveClass('pause');
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr('title', 'Play');
});
});
describe('togglePlayback', function() {
beforeEach(function() {
initialize();
});
describe('when the control does not have play or pause class', function() {
beforeEach(function() {
$('.video_control').removeClass('play').removeClass('pause');
}); });
describe('when the video is playing', function() { afterEach(function () {
beforeEach(function() { $('source').remove();
$('.video_control').addClass('play'); window.onTouchBasedDevice = oldOTBD;
spyOnEvent(videoControl, 'pause');
videoControl.togglePlayback(jQuery.Event('click'));
});
it('does not trigger the pause event', function() {
expect('pause').not.toHaveBeenTriggeredOn(videoControl);
});
}); });
describe('when the video is paused', function() { describe('constructor', function () {
beforeEach(function() { beforeEach(function () {
$('.video_control').addClass('pause'); state = jasmine.initializePlayer();
spyOnEvent(videoControl, 'play'); });
videoControl.togglePlayback(jQuery.Event('click'));
}); it('render the video controls', function () {
expect($('.video-controls')).toContain(
it('does not trigger the play event', function() { [
expect('play').not.toHaveBeenTriggeredOn(videoControl); '.slider',
}); 'ul.vcr',
'a.play',
'.vidtime',
'.add-fullscreen'
].join(',')
);
expect($('.video-controls').find('.vidtime'))
.toHaveText('0:00 / 0:00');
});
it('add ARIA attributes to time control', function () {
var timeControl = $('div.slider>a');
expect(timeControl).toHaveAttrs({
'role': 'slider',
'title': 'video position',
'aria-disabled': 'false'
});
expect(timeControl).toHaveAttr('aria-valuetext');
});
it('add ARIA attributes to play control', function () {
var playControl = $('ul.vcr a');
expect(playControl).toHaveAttrs({
'role': 'button',
'title': 'Play',
'aria-disabled': 'false'
});
});
it('add ARIA attributes to fullscreen control', function () {
var fullScreenControl = $('a.add-fullscreen');
expect(fullScreenControl).toHaveAttrs({
'role': 'button',
'title': 'Fill browser',
'aria-disabled': 'false'
});
});
it('bind the playback button', function () {
expect($('.video_control')).toHandleWith(
'click',
state.videoControl.togglePlayback
);
});
describe('when on a non-touch based device', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('add the play class to video control', function () {
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr(
'title', 'Play'
);
});
});
describe('when on a touch based device', function () {
beforeEach(function () {
window.onTouchBasedDevice.andReturn(['iPad']);
state = jasmine.initializePlayer();
});
it(
'does not add the play class to video control',
function ()
{
expect($('.video_control')).toHaveClass('play');
expect($('.video_control')).toHaveAttr(
'title', 'Play'
);
});
});
}); });
});
});
describe('Play placeholder', function () {
beforeEach(function () {
this.oldYT = window.YT;
jasmine.stubRequests();
window.YT = {
Player: function () {
return { getDuration: function () { return 60; } };
},
PlayerState: this.oldYT.PlayerState,
ready: function (callback) {
callback();
}
};
spyOn(window.YT, 'Player').andCallThrough();
});
afterEach(function () {
window.YT = this.oldYT;
});
it ('works correctly on calling proper methods', function () {
initialize();
var btnPlay = state.el.find('.btn-play');
videoControl.showPlayPlaceholder(); describe('play', function () {
beforeEach(function () {
expect(btnPlay).not.toHaveClass('is-hidden'); state = jasmine.initializePlayer();
expect(btnPlay).toHaveAttrs({ state.videoControl.play();
'aria-hidden': 'false', });
'tabindex': 0
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');
});
}); });
videoControl.hidePlayPlaceholder(); describe('pause', function () {
beforeEach(function () {
expect(btnPlay).toHaveClass('is-hidden'); state = jasmine.initializePlayer();
expect(btnPlay).toHaveAttrs({ state.videoControl.pause();
'aria-hidden': 'true', });
'tabindex': -1
}); it('switch playback button to pause state', function () {
}); expect($('.video_control')).not.toHaveClass('pause');
expect($('.video_control')).toHaveClass('play');
var cases = [ expect($('.video_control')).toHaveAttr('title', 'Play');
{ });
name: 'PC',
isShown: false,
isTouch: null
},
{
name: 'iPad',
isShown: true,
isTouch: ['iPad']
},
{
name: 'Android',
isShown: true,
isTouch: ['Android']
},
{
name: 'iPhone',
isShown: false,
isTouch: ['iPhone']
}
];
$.each(cases, function(index, data) {
var message = [
(data.isShown) ? 'is' : 'is not',
' shown on',
data.name
].join('');
it(message, function () {
window.onTouchBasedDevice.andReturn(data.isTouch);
initialize();
var btnPlay = state.el.find('.btn-play');
if (data.isShown) {
expect(btnPlay).not.toHaveClass('is-hidden');
} else {
expect(btnPlay).toHaveClass('is-hidden');
}
}); });
});
$.each(['iPad', 'Android'], function(index, device) { describe('togglePlayback', function () {
it('is shown on paused video on '+ device +' in HTML5 player', function () { beforeEach(function () {
window.onTouchBasedDevice.andReturn([device]); state = jasmine.initializePlayer();
initialize(); });
var btnPlay = state.el.find('.btn-play');
describe(
videoControl.play(); 'when the control does not have play or pause class',
videoControl.pause(); function ()
{
expect(btnPlay).not.toHaveClass('is-hidden'); beforeEach(function () {
$('.video_control').removeClass('play')
.removeClass('pause');
});
describe('when the video is playing', function () {
beforeEach(function () {
$('.video_control').addClass('play');
spyOnEvent(state.videoControl, 'pause');
state.videoControl.togglePlayback(jQuery.Event('click'));
});
it('does not trigger the pause event', function () {
expect('pause').not
.toHaveBeenTriggeredOn(state.videoControl);
});
});
describe('when the video is paused', function () {
beforeEach(function () {
$('.video_control').addClass('pause');
spyOnEvent(state.videoControl, 'play');
state.videoControl.togglePlayback(jQuery.Event('click'));
});
it('does not trigger the play event', function () {
expect('play').not
.toHaveBeenTriggeredOn(state.videoControl);
});
});
});
}); });
it('is hidden on playing video on '+ device +' in HTML5 player', function () { describe('Play placeholder', function () {
window.onTouchBasedDevice.andReturn([device]); var cases = [
initialize(); {
var btnPlay = state.el.find('.btn-play'); name: 'PC',
isShown: false,
videoControl.play(); isTouch: null
}, {
expect(btnPlay).toHaveClass('is-hidden'); name: 'iPad',
isShown: true,
isTouch: ['iPad']
}, {
name: 'Android',
isShown: true,
isTouch: ['Android']
}, {
name: 'iPhone',
isShown: false,
isTouch: ['iPhone']
}
];
beforeEach(function () {
jasmine.stubRequests();
spyOn(window.YT, 'Player').andCallThrough();
});
it ('works correctly on calling proper methods', function () {
var btnPlay;
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
state.videoControl.showPlayPlaceholder();
expect(btnPlay).not.toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
'aria-hidden': 'false',
'tabindex': 0
});
state.videoControl.hidePlayPlaceholder();
expect(btnPlay).toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
'aria-hidden': 'true',
'tabindex': -1
});
});
$.each(cases, function (index, data) {
var message = [
(data.isShown) ? 'is' : 'is not',
' shown on',
data.name
].join('');
it(message, function () {
var btnPlay;
window.onTouchBasedDevice.andReturn(data.isTouch);
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
if (data.isShown) {
expect(btnPlay).not.toHaveClass('is-hidden');
} else {
expect(btnPlay).toHaveClass('is-hidden');
}
});
});
$.each(['iPad', 'Android'], function (index, device) {
it(
'is shown on paused video on ' + device +
' in HTML5 player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
state.videoControl.play();
state.videoControl.pause();
expect(btnPlay).not.toHaveClass('is-hidden');
});
it(
'is hidden on playing video on ' + device +
' in HTML5 player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
state = jasmine.initializePlayer();
btnPlay = state.el.find('.btn-play');
state.videoControl.play();
expect(btnPlay).toHaveClass('is-hidden');
});
it(
'is hidden on paused video on ' + device +
' in YouTube player',
function ()
{
var btnPlay;
window.onTouchBasedDevice.andReturn([device]);
state = jasmine.initializePlayerYouTube();
btnPlay = state.el.find('.btn-play');
state.videoControl.play();
state.videoControl.pause();
expect(btnPlay).toHaveClass('is-hidden');
});
});
}); });
it('is hidden on paused video on '+ device +' in YouTube player', function () { it('show', function () {
window.onTouchBasedDevice.andReturn([device]); var controls;
initializeYouTube();
var btnPlay = state.el.find('.btn-play');
videoControl.play(); state = jasmine.initializePlayer();
videoControl.pause(); controls = state.el.find('.video-controls');
controls.addClass('is-hidden');
expect(btnPlay).toHaveClass('is-hidden'); state.videoControl.show();
expect(controls).not.toHaveClass('is-hidden');
}); });
});
}); });
it('show', function () {
initialize();
var controls = state.el.find('.video-controls');
controls.addClass('is-hidden');
videoControl.show();
expect(controls).not.toHaveClass('is-hidden');
});
});
}).call(this); }).call(this);
(function () { (function (undefined) {
describe('Video FocusGrabber', function () { describe('Video FocusGrabber', function () {
var state; var state;
......
(function () { (function (undefined) {
describe('VideoPlayer', function () { describe('VideoPlayer', function () {
var state, videoPlayer, player, videoControl, videoCaption, var state, oldOTBD;
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');
}
beforeEach(function () { beforeEach(function () {
oldOTBD = window.onTouchBasedDevice; oldOTBD = window.onTouchBasedDevice;
...@@ -68,11 +16,13 @@ ...@@ -68,11 +16,13 @@
describe('constructor', function () { describe('constructor', function () {
describe('always', function () { describe('always', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
}); });
it('instanticate current time to zero', function () { it('instanticate current time to zero', function () {
expect(videoPlayer.currentTime).toEqual(0); expect(state.videoPlayer.currentTime).toEqual(0);
}); });
it('set the element', function () { it('set the element', function () {
...@@ -80,12 +30,12 @@ ...@@ -80,12 +30,12 @@
}); });
it('create video control', function () { it('create video control', function () {
expect(videoControl).toBeDefined(); expect(state.videoControl).toBeDefined();
expect(videoControl.el).toHaveClass('video-controls'); expect(state.videoControl.el).toHaveClass('video-controls');
}); });
it('create video caption', function () { it('create video caption', function () {
expect(videoCaption).toBeDefined(); expect(state.videoCaption).toBeDefined();
expect(state.youtubeId()).toEqual('Z5KLxerq05Y'); expect(state.youtubeId()).toEqual('Z5KLxerq05Y');
expect(state.speed).toEqual('1.0'); expect(state.speed).toEqual('1.0');
expect(state.config.caption_asset_path) expect(state.config.caption_asset_path)
...@@ -93,16 +43,16 @@ ...@@ -93,16 +43,16 @@
}); });
it('create video speed control', function () { it('create video speed control', function () {
expect(videoSpeedControl).toBeDefined(); expect(state.videoSpeedControl).toBeDefined();
expect(videoSpeedControl.el).toHaveClass('speeds'); expect(state.videoSpeedControl.el).toHaveClass('speeds');
expect(videoSpeedControl.speeds) expect(state.videoSpeedControl.speeds)
.toEqual([ '0.75', '1.0', '1.25', '1.50' ]); .toEqual([ '0.75', '1.0', '1.25', '1.50' ]);
expect(state.speed).toEqual('1.0'); expect(state.speed).toEqual('1.0');
}); });
it('create video progress slider', function () { it('create video progress slider', function () {
expect(videoProgressSlider).toBeDefined(); expect(state.videoProgressSlider).toBeDefined();
expect(videoProgressSlider.el).toHaveClass('slider'); expect(state.videoProgressSlider.el).toHaveClass('slider');
}); });
// All the toHandleWith() expect tests are not necessary for // All the toHandleWith() expect tests are not necessary for
...@@ -112,28 +62,20 @@ ...@@ -112,28 +62,20 @@
}); });
it('create Youtube player', function () { it('create Youtube player', function () {
var oldYT = window.YT, events; var events;
jasmine.stubRequests(); jasmine.stubRequests();
window.YT = {
Player: function () {
return { getDuration: function () { return 60; } };
},
PlayerState: oldYT.PlayerState,
ready: function (callback) {
callback();
}
};
spyOn(window.YT, 'Player').andCallThrough(); spyOn(window.YT, 'Player').andCallThrough();
initializeYouTube(); state = jasmine.initializePlayerYouTube();
state.videoEl = $('video, iframe');
events = { events = {
onReady: videoPlayer.onReady, onReady: state.videoPlayer.onReady,
onStateChange: videoPlayer.onStateChange, onStateChange: state.videoPlayer.onStateChange,
onPlaybackQualityChange: videoPlayer onPlaybackQualityChange: state.videoPlayer
.onPlaybackQualityChange .onPlaybackQualityChange
}; };
...@@ -150,8 +92,6 @@ ...@@ -150,8 +92,6 @@
videoId: 'cogebirgzzM', videoId: 'cogebirgzzM',
events: events events: events
}); });
window.YT = oldYT;
}); });
// We can't test the invocation of HTML5Video because it is not // We can't test the invocation of HTML5Video because it is not
...@@ -159,11 +99,14 @@ ...@@ -159,11 +99,14 @@
// JS. // JS.
describe('when on a touch based device', function () { describe('when on a touch based device', function () {
$.each(['iPad', 'Android'], function(index, device) { $.each(['iPad', 'Android'], function (index, device) {
it('create video volume control on' + device, function() { it('create video volume control on' + device, function () {
window.onTouchBasedDevice.andReturn([device]); window.onTouchBasedDevice.andReturn([device]);
initialize(); state = jasmine.initializePlayer();
expect(videoVolumeControl).toBeUndefined();
state.videoEl = $('video, iframe');
expect(state.videoVolumeControl).toBeUndefined();
expect(state.el.find('div.volume')).not.toExist(); expect(state.el.find('div.volume')).not.toExist();
}); });
}); });
...@@ -173,52 +116,58 @@ ...@@ -173,52 +116,58 @@
var oldOTBD; var oldOTBD;
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
}); });
it('controls are in paused state', function () { it('controls are in paused state', function () {
expect(videoControl.isPlaying).toBe(false); expect(state.videoControl.isPlaying).toBe(false);
}); });
}); });
}); });
describe('onReady', function () { describe('onReady', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoPlayer, 'log').andCallThrough(); state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'play').andCallThrough();
videoPlayer.onReady(); spyOn(state.videoPlayer, 'log').andCallThrough();
spyOn(state.videoPlayer, 'play').andCallThrough();
state.videoPlayer.onReady();
}); });
it('log the load_video event', function () { 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 () { it('autoplay the first video', function () {
expect(videoPlayer.play).not.toHaveBeenCalled(); expect(state.videoPlayer.play).not.toHaveBeenCalled();
}); });
}); });
describe('onStateChange', function () { describe('onStateChange', function () {
describe('when the video is unstarted', function () { describe('when the video is unstarted', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
spyOn(videoControl, 'pause').andCallThrough(); spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(videoCaption, 'pause').andCallThrough(); spyOn(state.videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({ state.videoPlayer.onStateChange({
data: YT.PlayerState.PAUSED data: YT.PlayerState.PAUSED
}); });
}); });
it('pause the video control', function () { it('pause the video control', function () {
expect(videoControl.pause).toHaveBeenCalled(); expect(state.videoControl.pause).toHaveBeenCalled();
}); });
it('pause the video caption', function () { it('pause the video caption', function () {
expect(videoCaption.pause).toHaveBeenCalled(); expect(state.videoCaption.pause).toHaveBeenCalled();
}); });
}); });
...@@ -227,26 +176,28 @@ ...@@ -227,26 +176,28 @@
beforeEach(function () { beforeEach(function () {
// Create the first instance of the player. // Create the first instance of the player.
initialize(); state = jasmine.initializePlayer();
oldState = state; oldState = state;
spyOn(oldState.videoPlayer, 'onPause').andCallThrough(); spyOn(oldState.videoPlayer, 'onPause').andCallThrough();
// Now initialize a second instance. // 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(window, 'setInterval').andReturn(100);
spyOn(videoControl, 'play'); spyOn(state.videoControl, 'play');
spyOn(videoCaption, 'play'); spyOn(state.videoCaption, 'play');
videoPlayer.onStateChange({ state.videoPlayer.onStateChange({
data: YT.PlayerState.PLAYING data: YT.PlayerState.PLAYING
}); });
}); });
it('log the play_video event', function () { it('log the play_video event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'play_video', { currentTime: 0 } 'play_video', { currentTime: 0 }
); );
}); });
...@@ -257,17 +208,17 @@ ...@@ -257,17 +208,17 @@
it('set update interval', function () { it('set update interval', function () {
expect(window.setInterval).toHaveBeenCalledWith( 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 () { it('play the video control', function () {
expect(videoControl.play).toHaveBeenCalled(); expect(state.videoControl.play).toHaveBeenCalled();
}); });
it('play the video caption', function () { it('play the video caption', function () {
expect(videoCaption.play).toHaveBeenCalled(); expect(state.videoCaption.play).toHaveBeenCalled();
}); });
}); });
...@@ -275,90 +226,96 @@ ...@@ -275,90 +226,96 @@
var currentUpdateIntrval; var currentUpdateIntrval;
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'log').andCallThrough(); spyOn(state.videoPlayer, 'log').andCallThrough();
spyOn(videoControl, 'pause').andCallThrough(); spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(videoCaption, 'pause').andCallThrough(); spyOn(state.videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({ state.videoPlayer.onStateChange({
data: YT.PlayerState.PLAYING data: YT.PlayerState.PLAYING
}); });
currentUpdateIntrval = videoPlayer.updateInterval; currentUpdateIntrval = state.videoPlayer.updateInterval;
videoPlayer.onStateChange({ state.videoPlayer.onStateChange({
data: YT.PlayerState.PAUSED data: YT.PlayerState.PAUSED
}); });
}); });
it('log the pause_video event', function () { it('log the pause_video event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'pause_video', { currentTime: 0 } 'pause_video', { currentTime: 0 }
); );
}); });
it('clear update interval', function () { it('clear update interval', function () {
expect(videoPlayer.updateInterval).toBeUndefined(); expect(state.videoPlayer.updateInterval).toBeUndefined();
}); });
it('pause the video control', function () { it('pause the video control', function () {
expect(videoControl.pause).toHaveBeenCalled(); expect(state.videoControl.pause).toHaveBeenCalled();
}); });
it('pause the video caption', function () { it('pause the video caption', function () {
expect(videoCaption.pause).toHaveBeenCalled(); expect(state.videoCaption.pause).toHaveBeenCalled();
}); });
}); });
describe('when the video is ended', function () { describe('when the video is ended', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoControl, 'pause').andCallThrough(); state.videoEl = $('video, iframe');
spyOn(videoCaption, 'pause').andCallThrough();
videoPlayer.onStateChange({ spyOn(state.videoControl, 'pause').andCallThrough();
spyOn(state.videoCaption, 'pause').andCallThrough();
state.videoPlayer.onStateChange({
data: YT.PlayerState.ENDED data: YT.PlayerState.ENDED
}); });
}); });
it('pause the video control', function () { it('pause the video control', function () {
expect(videoControl.pause).toHaveBeenCalled(); expect(state.videoControl.pause).toHaveBeenCalled();
}); });
it('pause the video caption', function () { it('pause the video caption', function () {
expect(videoCaption.pause).toHaveBeenCalled(); expect(state.videoCaption.pause).toHaveBeenCalled();
}); });
}); });
}); });
describe('onSeek', function () { describe('onSeek', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
runs(function () { runs(function () {
state.videoPlayer.play(); state.videoPlayer.play();
}); });
waitsFor(function () { 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); }, 'video begins playing', WAIT_TIMEOUT);
}); });
it('Slider event causes log update', function () { it('Slider event causes log update', function () {
runs(function () { runs(function () {
var currentTime = videoPlayer.currentTime; var currentTime = state.videoPlayer.currentTime;
spyOn(videoPlayer, 'log'); spyOn(state.videoPlayer, 'log');
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 2 } jQuery.Event('slide'), { value: 2 }
); );
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'seek_video', 'seek_video',
{ {
old_time: currentTime, old_time: currentTime,
...@@ -371,24 +328,24 @@ ...@@ -371,24 +328,24 @@
it('seek the player', function () { it('seek the player', function () {
runs(function () { runs(function () {
spyOn(videoPlayer.player, 'seekTo'); spyOn(state.videoPlayer.player, 'seekTo');
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 60 } jQuery.Event('slide'), { value: 60 }
); );
expect(videoPlayer.player.seekTo) expect(state.videoPlayer.player.seekTo)
.toHaveBeenCalledWith(60, true); .toHaveBeenCalledWith(60, true);
}); });
}); });
it('call updatePlayTime on player', function () { it('call updatePlayTime on player', function () {
runs(function () { runs(function () {
spyOn(videoPlayer, 'updatePlayTime'); spyOn(state.videoPlayer, 'updatePlayTime');
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 60 } jQuery.Event('slide'), { value: 60 }
); );
expect(videoPlayer.updatePlayTime) expect(state.videoPlayer.updatePlayTime)
.toHaveBeenCalledWith(60); .toHaveBeenCalledWith(60);
}); });
}); });
...@@ -399,16 +356,16 @@ ...@@ -399,16 +356,16 @@
function () function ()
{ {
runs(function () { runs(function () {
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 20 } jQuery.Event('slide'), { value: 20 }
); );
videoPlayer.pause(); state.videoPlayer.pause();
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 10 } jQuery.Event('slide'), { value: 10 }
); );
waitsFor(function () { waitsFor(function () {
return Math.round(videoPlayer.currentTime) === 10; return Math.round(state.videoPlayer.currentTime) === 10;
}, 'currentTime got updated', 10000); }, 'currentTime got updated', 10000);
}); });
}); });
...@@ -416,26 +373,28 @@ ...@@ -416,26 +373,28 @@
describe('onSpeedChange', function () { describe('onSpeedChange', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough();
spyOn(state, 'setSpeed').andCallThrough(); spyOn(state, 'setSpeed').andCallThrough();
spyOn(videoPlayer, 'log').andCallThrough(); spyOn(state.videoPlayer, 'log').andCallThrough();
spyOn(videoPlayer.player, 'setPlaybackRate').andCallThrough(); spyOn(state.videoPlayer.player, 'setPlaybackRate').andCallThrough();
}); });
describe('always', function () { describe('always', function () {
beforeEach(function () { beforeEach(function () {
videoPlayer.currentTime = 60; state.videoPlayer.currentTime = 60;
videoPlayer.onSpeedChange('0.75', false); state.videoPlayer.onSpeedChange('0.75', false);
}); });
it('check if speed_change_video is logged', function () { it('check if speed_change_video is logged', function () {
expect(videoPlayer.log).toHaveBeenCalledWith( expect(state.videoPlayer.log).toHaveBeenCalledWith(
'speed_change_video', 'speed_change_video',
{ {
current_time: videoPlayer.currentTime, current_time: state.videoPlayer.currentTime,
old_speed: '1.0', old_speed: '1.0',
new_speed: '0.75' new_speed: '0.75'
} }
...@@ -443,7 +402,7 @@ ...@@ -443,7 +402,7 @@
}); });
it('convert the current time to the new speed', function () { 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 () { it('set video speed to the new speed', function () {
...@@ -453,75 +412,82 @@ ...@@ -453,75 +412,82 @@
describe('when the video is playing', function () { describe('when the video is playing', function () {
beforeEach(function () { beforeEach(function () {
videoPlayer.currentTime = 60; state.videoPlayer.currentTime = 60;
videoPlayer.play(); state.videoPlayer.play();
videoPlayer.onSpeedChange('0.75', false); state.videoPlayer.onSpeedChange('0.75', false);
}); });
it('trigger updatePlayTime event', function () { it('trigger updatePlayTime event', function () {
expect(videoPlayer.player.setPlaybackRate) expect(state.videoPlayer.player.setPlaybackRate)
.toHaveBeenCalledWith('0.75'); .toHaveBeenCalledWith('0.75');
}); });
}); });
describe('when the video is not playing', function () { describe('when the video is not playing', function () {
beforeEach(function () { beforeEach(function () {
videoPlayer.onSpeedChange('0.75', false); state.videoPlayer.onSpeedChange('0.75', false);
}); });
it('trigger updatePlayTime event', function () { it('trigger updatePlayTime event', function () {
expect(videoPlayer.player.setPlaybackRate) expect(state.videoPlayer.player.setPlaybackRate)
.toHaveBeenCalledWith('0.75'); .toHaveBeenCalledWith('0.75');
}); });
it('video has a correct speed', function () { it('video has a correct speed', function () {
spyOn(videoPlayer, 'onSpeedChange'); spyOn(state.videoPlayer, 'onSpeedChange');
state.speed = '2.0'; state.speed = '2.0';
videoPlayer.onPlay(); state.videoPlayer.onPlay();
expect(videoPlayer.onSpeedChange).toHaveBeenCalledWith('2.0'); expect(state.videoPlayer.onSpeedChange)
videoPlayer.onPlay(); .toHaveBeenCalledWith('2.0');
expect(videoPlayer.onSpeedChange.calls.length).toEqual(1); state.videoPlayer.onPlay();
expect(state.videoPlayer.onSpeedChange.calls.length).toEqual(1);
}); });
it('video has a correct volume', function () { it('video has a correct volume', function () {
spyOn(videoPlayer.player, 'setVolume'); spyOn(state.videoPlayer.player, 'setVolume');
state.currentVolume = '0.26'; state.currentVolume = '0.26';
videoPlayer.onPlay(); state.videoPlayer.onPlay();
expect(videoPlayer.player.setVolume).toHaveBeenCalledWith('0.26'); expect(state.videoPlayer.player.setVolume)
.toHaveBeenCalledWith('0.26');
}); });
}); });
}); });
describe('onVolumeChange', function () { describe('onVolumeChange', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
}); });
it('set the volume on player', function () { it('set the volume on player', function () {
spyOn(videoPlayer.player, 'setVolume'); spyOn(state.videoPlayer.player, 'setVolume');
videoPlayer.onVolumeChange(60); state.videoPlayer.onVolumeChange(60);
expect(videoPlayer.player.setVolume).toHaveBeenCalledWith(60); expect(state.videoPlayer.player.setVolume).toHaveBeenCalledWith(60);
}); });
describe('when the video is not playing', function () { describe('when the video is not playing', function () {
beforeEach(function () { beforeEach(function () {
videoPlayer.player.setVolume('1'); state.videoPlayer.player.setVolume('1');
}); });
it('video has a correct volume', function () { it('video has a correct volume', function () {
spyOn(videoPlayer.player, 'setVolume'); spyOn(state.videoPlayer.player, 'setVolume');
state.currentVolume = '0.26'; state.currentVolume = '0.26';
videoPlayer.onPlay(); state.videoPlayer.onPlay();
expect(videoPlayer.player.setVolume).toHaveBeenCalledWith('0.26'); expect(state.videoPlayer.player.setVolume)
.toHaveBeenCalledWith('0.26');
}); });
}); });
}); });
describe('update', function () { describe('update', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoPlayer, 'updatePlayTime').andCallThrough(); state.videoEl = $('video, iframe');
spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough();
}); });
describe( describe(
...@@ -529,14 +495,14 @@ ...@@ -529,14 +495,14 @@
function () function ()
{ {
beforeEach(function () { beforeEach(function () {
videoPlayer.player.getCurrentTime = function () { state.videoPlayer.player.getCurrentTime = function () {
return NaN; return NaN;
}; };
videoPlayer.update(); state.videoPlayer.update();
}); });
it('does not trigger updatePlayTime event', function () { it('does not trigger updatePlayTime event', function () {
expect(videoPlayer.updatePlayTime).not.toHaveBeenCalled(); expect(state.videoPlayer.updatePlayTime).not.toHaveBeenCalled();
}); });
}); });
...@@ -545,14 +511,14 @@ ...@@ -545,14 +511,14 @@
function () function ()
{ {
beforeEach(function () { beforeEach(function () {
videoPlayer.player.getCurrentTime = function () { state.videoPlayer.player.getCurrentTime = function () {
return 60; return 60;
}; };
videoPlayer.update(); state.videoPlayer.update();
}); });
it('trigger updatePlayTime event', function () { it('trigger updatePlayTime event', function () {
expect(videoPlayer.updatePlayTime) expect(state.videoPlayer.updatePlayTime)
.toHaveBeenCalledWith(60); .toHaveBeenCalledWith(60);
}); });
}); });
...@@ -563,34 +529,44 @@ ...@@ -563,34 +529,44 @@
var START_TIME = 1, END_TIME = 2; var START_TIME = 1, END_TIME = 2;
beforeEach(function () { 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(state.videoPlayer, 'update').andCallThrough();
spyOn(videoPlayer, 'pause').andCallThrough(); spyOn(state.videoPlayer, 'pause').andCallThrough();
spyOn(videoProgressSlider, 'notifyThroughHandleEnd') spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd')
.andCallThrough(); .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; var duration;
videoProgressSlider.notifyThroughHandleEnd.reset(); state.videoProgressSlider.notifyThroughHandleEnd.reset();
videoPlayer.pause.reset(); state.videoPlayer.pause.reset();
videoPlayer.play(); state.videoPlayer.play();
waitsFor(function () { 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); }, 'pause() has been called', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(videoPlayer.startTime).toBe(0); expect(state.videoPlayer.startTime).toBe(0);
expect(videoPlayer.endTime).toBe(null); expect(state.videoPlayer.endTime).toBe(null);
expect(duration).toBe(END_TIME); expect(duration).toBe(END_TIME);
expect(videoProgressSlider.notifyThroughHandleEnd) expect(state.videoProgressSlider.notifyThroughHandleEnd)
.toHaveBeenCalledWith({end: true}); .toHaveBeenCalledWith({end: true});
}); });
}); });
...@@ -598,17 +574,19 @@ ...@@ -598,17 +574,19 @@
describe('updatePlayTime', function () { describe('updatePlayTime', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoCaption, 'updatePlayTime').andCallThrough(); state.videoEl = $('video, iframe');
spyOn(videoProgressSlider, 'updatePlayTime').andCallThrough();
spyOn(state.videoCaption, 'updatePlayTime').andCallThrough();
spyOn(state.videoProgressSlider, 'updatePlayTime').andCallThrough();
}); });
it('update the video playback time', function () { it('update the video playback time', function () {
var duration = 0; var duration = 0;
waitsFor(function () { waitsFor(function () {
duration = videoPlayer.duration(); duration = state.videoPlayer.duration();
if (duration > 0) { if (duration > 0) {
return true; return true;
...@@ -620,7 +598,7 @@ ...@@ -620,7 +598,7 @@
runs(function () { runs(function () {
var htmlStr; var htmlStr;
videoPlayer.updatePlayTime(60); state.videoPlayer.updatePlayTime(60);
htmlStr = $('.vidtime').html(); htmlStr = $('.vidtime').html();
...@@ -643,13 +621,13 @@ ...@@ -643,13 +621,13 @@
it('update the playback time on caption', function () { it('update the playback time on caption', function () {
waitsFor(function () { waitsFor(function () {
return videoPlayer.duration() > 0; return state.videoPlayer.duration() > 0;
}, 'Video is fully loaded.', WAIT_TIMEOUT); }, 'Video is fully loaded.', WAIT_TIMEOUT);
runs(function () { runs(function () {
videoPlayer.updatePlayTime(60); state.videoPlayer.updatePlayTime(60);
expect(videoCaption.updatePlayTime) expect(state.videoCaption.updatePlayTime)
.toHaveBeenCalledWith(60); .toHaveBeenCalledWith(60);
}); });
}); });
...@@ -658,15 +636,15 @@ ...@@ -658,15 +636,15 @@
var duration = 0; var duration = 0;
waitsFor(function () { waitsFor(function () {
duration = videoPlayer.duration(); duration = state.videoPlayer.duration();
return duration > 0; return duration > 0;
}, 'Video is fully loaded.', WAIT_TIMEOUT); }, 'Video is fully loaded.', WAIT_TIMEOUT);
runs(function () { runs(function () {
videoPlayer.updatePlayTime(60); state.videoPlayer.updatePlayTime(60);
expect(videoProgressSlider.updatePlayTime) expect(state.videoProgressSlider.updatePlayTime)
.toHaveBeenCalledWith({ .toHaveBeenCalledWith({
time: 60, time: 60,
duration: duration duration: duration
...@@ -676,68 +654,93 @@ ...@@ -676,68 +654,93 @@
}); });
// Disabled 1/13/14 due to flakiness observed in master // 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, var START_TIME = 1,
END_TIME = 2; END_TIME = 2;
beforeEach(function () { 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(state.videoPlayer, 'updatePlayTime').andCallThrough();
spyOn(videoPlayer.player, 'seekTo').andCallThrough(); spyOn(state.videoPlayer.player, 'seekTo').andCallThrough();
spyOn(videoProgressSlider, 'updateStartEndTimeRegion') spyOn(state.videoProgressSlider, 'updateStartEndTimeRegion')
.andCallThrough(); .andCallThrough();
}); });
it('when duration becomes available, updatePlayTime() is called', function () { it(
'when duration becomes available, updatePlayTime() is called',
function ()
{
var duration; var duration;
expect(videoPlayer.initialSeekToStartTime).toBeTruthy(); expect(state.videoPlayer.initialSeekToStartTime).toBeTruthy();
expect(videoPlayer.seekToStartTimeOldSpeed).toBe('void'); expect(state.videoPlayer.seekToStartTimeOldSpeed).toBe('void');
videoPlayer.play(); state.videoPlayer.play();
waitsFor(function () { waitsFor(function () {
duration = videoPlayer.duration(); duration = state.videoPlayer.duration();
return videoPlayer.isPlaying() && return state.videoPlayer.isPlaying() &&
videoPlayer.initialSeekToStartTime === false; state.videoPlayer.initialSeekToStartTime === false;
}, 'duration becomes available', WAIT_TIMEOUT); }, 'duration becomes available', WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(videoPlayer.startTime).toBe(START_TIME); expect(state.videoPlayer.startTime).toBe(START_TIME);
expect(videoPlayer.endTime).toBe(END_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}); .toHaveBeenCalledWith({duration: duration});
expect(videoPlayer.seekToStartTimeOldSpeed).toBe(state.speed); expect(state.videoPlayer.seekToStartTimeOldSpeed)
.toBe(state.speed);
}); });
}); });
}); });
describe('updatePlayTime with invalid endTime', function () { describe('updatePlayTime with invalid endTime', function () {
beforeEach(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 () { it('invalid endTime is reset to null', function () {
var duration; var duration;
videoPlayer.updatePlayTime.reset(); state.videoPlayer.updatePlayTime.reset();
videoPlayer.play(); state.videoPlayer.play();
waitsFor(function () { waitsFor(
return videoPlayer.isPlaying() && function () {
videoPlayer.initialSeekToStartTime === false; return state.videoPlayer.isPlaying() &&
}, 'updatePlayTime was invoked and duration is set', WAIT_TIMEOUT); state.videoPlayer.initialSeekToStartTime === false;
},
'updatePlayTime was invoked and duration is set',
WAIT_TIMEOUT
);
runs(function () { runs(function () {
expect(videoPlayer.endTime).toBe(null); expect(state.videoPlayer.endTime).toBe(null);
}); });
}); });
}); });
...@@ -745,9 +748,12 @@ ...@@ -745,9 +748,12 @@
describe('toggleFullScreen', function () { describe('toggleFullScreen', function () {
describe('when the video player is not full screen', function () { describe('when the video player is not full screen', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoCaption, 'resize').andCallThrough();
videoControl.toggleFullScreen(jQuery.Event('click')); state.videoEl = $('video, iframe');
spyOn(state.videoCaption, 'resize').andCallThrough();
state.videoControl.toggleFullScreen(jQuery.Event('click'));
}); });
it('replace the full screen button tooltip', function () { it('replace the full screen button tooltip', function () {
...@@ -760,22 +766,25 @@ ...@@ -760,22 +766,25 @@
}); });
it('tell VideoCaption to resize', function () { it('tell VideoCaption to resize', function () {
expect(videoCaption.resize).toHaveBeenCalled(); expect(state.videoCaption.resize).toHaveBeenCalled();
expect(state.resizer.setMode).toHaveBeenCalled(); expect(state.resizer.setMode).toHaveBeenCalled();
}); });
}); });
describe('when the video player already full screen', function () { describe('when the video player already full screen', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(videoCaption, 'resize').andCallThrough();
state.videoEl = $('video, iframe');
spyOn(state.videoCaption, 'resize').andCallThrough();
state.el.addClass('video-fullscreen'); state.el.addClass('video-fullscreen');
videoControl.fullScreenState = true; state.videoControl.fullScreenState = true;
isFullScreen = 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 () { it('replace the full screen button tooltip', function () {
...@@ -788,7 +797,7 @@ ...@@ -788,7 +797,7 @@
}); });
it('tell VideoCaption to resize', function () { it('tell VideoCaption to resize', function () {
expect(videoCaption.resize).toHaveBeenCalled(); expect(state.videoCaption.resize).toHaveBeenCalled();
expect(state.resizer.setMode) expect(state.resizer.setMode)
.toHaveBeenCalledWith('width'); .toHaveBeenCalledWith('width');
}); });
...@@ -797,112 +806,114 @@ ...@@ -797,112 +806,114 @@
describe('play', function () { describe('play', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(player, 'playVideo').andCallThrough();
state.videoEl = $('video, iframe');
spyOn(state.videoPlayer.player, 'playVideo').andCallThrough();
}); });
describe('when the player is not ready', function () { describe('when the player is not ready', function () {
beforeEach(function () { beforeEach(function () {
player.playVideo = void 0; state.videoPlayer.player.playVideo = void 0;
videoPlayer.play(); state.videoPlayer.play();
}); });
it('does nothing', function () { it('does nothing', function () {
expect(player.playVideo).toBeUndefined(); expect(state.videoPlayer.player.playVideo).toBeUndefined();
}); });
}); });
describe('when the player is ready', function () { describe('when the player is ready', function () {
beforeEach(function () { beforeEach(function () {
player.playVideo.andReturn(true); state.videoPlayer.player.playVideo.andReturn(true);
videoPlayer.play(); state.videoPlayer.play();
}); });
it('delegate to the player', function () { it('delegate to the player', function () {
expect(player.playVideo).toHaveBeenCalled(); expect(state.videoPlayer.player.playVideo).toHaveBeenCalled();
}); });
}); });
}); });
describe('isPlaying', function () { describe('isPlaying', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(player, 'getPlayerState').andCallThrough();
state.videoEl = $('video, iframe');
spyOn(state.videoPlayer.player, 'getPlayerState').andCallThrough();
}); });
describe('when the video is playing', function () { describe('when the video is playing', function () {
beforeEach(function () { beforeEach(function () {
player.getPlayerState.andReturn(YT.PlayerState.PLAYING); state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PLAYING);
}); });
it('return true', function () { it('return true', function () {
expect(videoPlayer.isPlaying()).toBeTruthy(); expect(state.videoPlayer.isPlaying()).toBeTruthy();
}); });
}); });
describe('when the video is not playing', function () { describe('when the video is not playing', function () {
beforeEach(function () { beforeEach(function () {
player.getPlayerState.andReturn(YT.PlayerState.PAUSED); state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PAUSED);
}); });
it('return false', function () { it('return false', function () {
expect(videoPlayer.isPlaying()).toBeFalsy(); expect(state.videoPlayer.isPlaying()).toBeFalsy();
}); });
}); });
}); });
describe('pause', function () { describe('pause', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(player, 'pauseVideo').andCallThrough();
videoPlayer.pause(); state.videoEl = $('video, iframe');
spyOn(state.videoPlayer.player, 'pauseVideo').andCallThrough();
state.videoPlayer.pause();
}); });
it('delegate to the player', function () { it('delegate to the player', function () {
expect(player.pauseVideo).toHaveBeenCalled(); expect(state.videoPlayer.player.pauseVideo).toHaveBeenCalled();
}); });
}); });
describe('duration', function () { describe('duration', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(player, 'getDuration').andCallThrough();
videoPlayer.duration(); state.videoEl = $('video, iframe');
spyOn(state.videoPlayer.player, 'getDuration').andCallThrough();
state.videoPlayer.duration();
}); });
it('delegate to the player', function () { it('delegate to the player', function () {
expect(player.getDuration).toHaveBeenCalled(); expect(state.videoPlayer.player.getDuration).toHaveBeenCalled();
}); });
}); });
describe('getDuration', function () { describe('getDuration', function () {
var oldYT;
beforeEach(function () { 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(); jasmine.stubRequests();
window.YT = { state = jasmine.initializePlayerYouTube();
Player: function () {
return { getDuration: function () { return 60; } };
},
PlayerState: oldYT.PlayerState,
ready: function (callback) {
callback();
}
};
spyOn(window.YT, 'Player').andCallThrough();
initializeYouTube(); state.videoEl = $('video, iframe');
spyOn(state, 'getDuration').andCallThrough(); spyOn(state, 'getDuration').andCallThrough();
spyOn(state.videoPlayer.player, 'getDuration').andReturn(0);
});
afterEach(function () { // When `state.videoPlayer.player.getDuration()` returns a `0`,
window.YT = oldYT; // the fall-back function `state.getDuration()` will be called.
state.videoPlayer.player.getDuration.andReturn(0);
}); });
it('getDuration is called as a fall-back', function () { it('getDuration is called as a fall-back', function () {
...@@ -914,27 +925,33 @@ ...@@ -914,27 +925,33 @@
describe('playback rate', function () { describe('playback rate', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
player.setPlaybackRate(1.5);
state.videoEl = $('video, iframe');
state.videoPlayer.player.setPlaybackRate(1.5);
}); });
it('set the player playback rate', function () { 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 () { describe('volume', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn(player, 'getVolume').andCallThrough();
state.videoEl = $('video, iframe');
spyOn(state.videoPlayer.player, 'getVolume').andCallThrough();
}); });
it('set the player volume', function () { it('set the player volume', function () {
var expectedValue = 60, var expectedValue = 60,
realValue; realValue;
player.setVolume(60); state.videoPlayer.player.setVolume(60);
realValue = Math.round(player.getVolume()*100); realValue = Math.round(state.videoPlayer.player.getVolume()*100);
expect(realValue).toEqual(expectedValue); expect(realValue).toEqual(expectedValue);
}); });
...@@ -942,9 +959,14 @@ ...@@ -942,9 +959,14 @@
describe('on Touch devices', function () { describe('on Touch devices', function () {
it('`is-touch` class name is added to container', 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]); window.onTouchBasedDevice.andReturn([device]);
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
expect(state.el).toHaveClass('is-touch'); expect(state.el).toHaveClass('is-touch');
}); });
...@@ -952,11 +974,13 @@ ...@@ -952,11 +974,13 @@
it('modules are not initialized on iPhone', function () { it('modules are not initialized on iPhone', function () {
window.onTouchBasedDevice.andReturn(['iPhone']); window.onTouchBasedDevice.andReturn(['iPhone']);
initialize(); state = jasmine.initializePlayer();
state.videoEl = $('video, iframe');
var modules = [ var modules = [
videoControl, videoCaption, videoProgressSlider, state.videoControl, state.videoCaption, state.videoProgressSlider,
videoSpeedControl, videoVolumeControl state.videoSpeedControl, state.videoVolumeControl
]; ];
$.each(modules, function (index, module) { $.each(modules, function (index, module) {
...@@ -964,37 +988,42 @@ ...@@ -964,37 +988,42 @@
}); });
}); });
$.each(['iPad', 'Android'], function(index, device) { $.each(['iPad', 'Android'], function (index, device) {
var message = 'controls become visible after playing starts on ' + var message = 'controls become visible after playing starts ' +
device; 'on ' + device;
it(message, function() {
var controls;
window.onTouchBasedDevice.andReturn([device]);
runs(function () { it(message, function () {
initialize(); var controls;
controls = state.el.find('.video-controls');
});
waitsFor(function () { window.onTouchBasedDevice.andReturn([device]);
return state.el.hasClass('is-initialized');
},'Video is not initialized.' , WAIT_TIMEOUT);
runs(function () { runs(function () {
expect(controls).toHaveClass('is-hidden'); state = jasmine.initializePlayer();
videoPlayer.play();
});
waitsFor(function () { state.videoEl = $('video, iframe');
duration = videoPlayer.duration();
return duration > 0 && videoPlayer.isPlaying(); controls = state.el.find('.video-controls');
},'Video does not play.' , WAIT_TIMEOUT); });
runs(function () { waitsFor(function () {
expect(controls).not.toHaveClass('is-hidden'); return state.el.hasClass('is-initialized');
},'Video is not initialized.' , WAIT_TIMEOUT);
runs(function () {
expect(controls).toHaveClass('is-hidden');
state.videoPlayer.play();
});
waitsFor(function () {
duration = state.videoPlayer.duration();
return duration > 0 && state.videoPlayer.isPlaying();
},'Video does not play.' , WAIT_TIMEOUT);
runs(function () {
expect(controls).not.toHaveClass('is-hidden');
});
}); });
});
}); });
}); });
}); });
......
(function() { (function (undefined) {
describe('VideoProgressSlider', function() { describe('VideoProgressSlider', function () {
var state, videoPlayer, videoProgressSlider, oldOTBD; var state, oldOTBD;
function initialize() { beforeEach(function () {
loadFixtures('video_all.html');
state = new Video('#example');
videoPlayer = state.videoPlayer;
videoProgressSlider = state.videoProgressSlider;
}
beforeEach(function() {
oldOTBD = window.onTouchBasedDevice; oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null); .andReturn(null);
}); });
afterEach(function() { afterEach(function () {
$('source').remove(); $('source').remove();
window.onTouchBasedDevice = oldOTBD; window.onTouchBasedDevice = oldOTBD;
}); });
describe('constructor', function() { describe('constructor', function () {
describe('on a non-touch based device', function() { describe('on a non-touch based device', function () {
beforeEach(function() { beforeEach(function () {
spyOn($.fn, 'slider').andCallThrough(); spyOn($.fn, 'slider').andCallThrough();
initialize();
state = jasmine.initializePlayer();
}); });
it('build the slider', function() { it('build the slider', function () {
expect(videoProgressSlider.slider).toBe('.slider'); expect(state.videoProgressSlider.slider).toBe('.slider');
expect($.fn.slider).toHaveBeenCalledWith({ expect($.fn.slider).toHaveBeenCalledWith({
range: 'min', range: 'min',
change: videoProgressSlider.onChange, change: state.videoProgressSlider.onChange,
slide: videoProgressSlider.onSlide, slide: state.videoProgressSlider.onSlide,
stop: videoProgressSlider.onStop stop: state.videoProgressSlider.onStop
}); });
}); });
it('build the seek handle', function() { it('build the seek handle', function () {
expect(videoProgressSlider.handle) expect(state.videoProgressSlider.handle)
.toBe('.slider .ui-slider-handle'); .toBe('.slider .ui-slider-handle');
}); });
}); });
describe('on a touch-based device', function() { describe('on a touch-based device', function () {
it('does not build the slider on iPhone', function() { it('does not build the slider on iPhone', function () {
window.onTouchBasedDevice.andReturn(['iPhone']); 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, // We can't expect $.fn.slider not to have been called,
// because sliders are used in other parts of Video. // because sliders are used in other parts of Video.
}); });
$.each(['iPad', 'Android'], function(index, device) { $.each(['iPad', 'Android'], function (index, device) {
it('build the slider on ' + device, function() { it('build the slider on ' + device, function () {
window.onTouchBasedDevice.andReturn([device]); window.onTouchBasedDevice.andReturn([device]);
initialize();
expect(videoProgressSlider.slider).toBeDefined(); state = jasmine.initializePlayer();
expect(state.videoProgressSlider.slider).toBeDefined();
}); });
}); });
}); });
}); });
describe('play', function() { describe('play', function () {
beforeEach(function() { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
}); });
describe('when the slider was already built', function() { describe('when the slider was already built', function () {
var spy; var spy;
beforeEach(function() { beforeEach(function () {
spy = spyOn(videoProgressSlider, 'buildSlider'); spy = spyOn(state.videoProgressSlider, 'buildSlider');
spy.andCallThrough(); 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); expect(spy.callCount).toEqual(0);
}); });
}); });
...@@ -86,40 +83,40 @@ ...@@ -86,40 +83,40 @@
// Currently, the slider is not rebuilt if it does not exist. // Currently, the slider is not rebuilt if it does not exist.
}); });
describe('updatePlayTime', function() { describe('updatePlayTime', function () {
beforeEach(function() { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
}); });
describe('when frozen', function() { describe('when frozen', function () {
beforeEach(function() { beforeEach(function () {
spyOn($.fn, 'slider').andCallThrough(); spyOn($.fn, 'slider').andCallThrough();
videoProgressSlider.frozen = true; state.videoProgressSlider.frozen = true;
videoProgressSlider.updatePlayTime(20, 120); state.videoProgressSlider.updatePlayTime(20, 120);
}); });
it('does not update the slider', function() { it('does not update the slider', function () {
expect($.fn.slider).not.toHaveBeenCalled(); expect($.fn.slider).not.toHaveBeenCalled();
}); });
}); });
describe('when not frozen', function() { describe('when not frozen', function () {
beforeEach(function() { beforeEach(function () {
spyOn($.fn, 'slider').andCallThrough(); spyOn($.fn, 'slider').andCallThrough();
videoProgressSlider.frozen = false; state.videoProgressSlider.frozen = false;
videoProgressSlider.updatePlayTime({ state.videoProgressSlider.updatePlayTime({
time: 20, time: 20,
duration: 120 duration: 120
}); });
}); });
it('update the max value of the slider', function() { it('update the max value of the slider', function () {
expect($.fn.slider).toHaveBeenCalledWith( expect($.fn.slider).toHaveBeenCalledWith(
'option', 'max', 120 'option', 'max', 120
); );
}); });
it('update current value of the slider', function() { it('update current value of the slider', function () {
expect($.fn.slider).toHaveBeenCalledWith( expect($.fn.slider).toHaveBeenCalledWith(
'option', 'value', 20 'option', 'value', 20
); );
...@@ -127,72 +124,74 @@ ...@@ -127,72 +124,74 @@
}); });
}); });
describe('onSlide', function() { describe('onSlide', function () {
beforeEach(function() { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOn($.fn, 'slider').andCallThrough(); spyOn($.fn, 'slider').andCallThrough();
spyOn(videoPlayer, 'onSlideSeek').andCallThrough(); spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough();
}); });
// Disabled 12/30/13 due to flakiness in master // Disabled 12/30/13 due to flakiness in master
xit('freeze the slider', function() { xit('freeze the slider', function () {
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 20 } jQuery.Event('slide'), { value: 20 }
); );
expect(videoProgressSlider.frozen).toBeTruthy(); expect(state.videoProgressSlider.frozen).toBeTruthy();
}); });
// Disabled 12/30/13 due to flakiness in master // Disabled 12/30/13 due to flakiness in master
xit('trigger seek event', function() { xit('trigger seek event', function () {
videoProgressSlider.onSlide( state.videoProgressSlider.onSlide(
jQuery.Event('slide'), { value: 20 } 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(); jasmine.Clock.useMock();
initialize(); state = jasmine.initializePlayer();
spyOn(videoPlayer, 'onSlideSeek').andCallThrough();
spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough();
}); });
// Disabled 12/30/13 due to flakiness in master // Disabled 12/30/13 due to flakiness in master
xit('freeze the slider', function() { xit('freeze the slider', function () {
videoProgressSlider.onStop( state.videoProgressSlider.onStop(
jQuery.Event('stop'), { value: 20 } jQuery.Event('stop'), { value: 20 }
); );
expect(videoProgressSlider.frozen).toBeTruthy(); expect(state.videoProgressSlider.frozen).toBeTruthy();
}); });
// Disabled 12/30/13 due to flakiness in master // Disabled 12/30/13 due to flakiness in master
xit('trigger seek event', function() { xit('trigger seek event', function () {
videoProgressSlider.onStop( state.videoProgressSlider.onStop(
jQuery.Event('stop'), { value: 20 } jQuery.Event('stop'), { value: 20 }
); );
expect(videoPlayer.onSlideSeek).toHaveBeenCalled(); expect(state.videoPlayer.onSlideSeek).toHaveBeenCalled();
}); });
// Disabled 12/30/13 due to flakiness in master // Disabled 12/30/13 due to flakiness in master
xit('set timeout to unfreeze the slider', function() { xit('set timeout to unfreeze the slider', function () {
videoProgressSlider.onStop( state.videoProgressSlider.onStop(
jQuery.Event('stop'), { value: 20 } jQuery.Event('stop'), { value: 20 }
); );
jasmine.Clock.tick(200); jasmine.Clock.tick(200);
expect(videoProgressSlider.frozen).toBeFalsy(); expect(state.videoProgressSlider.frozen).toBeFalsy();
}); });
}); });
it('getRangeParams' , function() { it('getRangeParams' , function () {
var testCases = [ var testCases = [
{ {
startTime: 10, startTime: 10,
...@@ -211,9 +210,9 @@ ...@@ -211,9 +210,9 @@
} }
]; ];
initialize(); state = jasmine.initializePlayer();
$.each(testCases, function(index, testCase) { $.each(testCases, function (index, testCase) {
var step = 100/testCase.duration, var step = 100/testCase.duration,
left = testCase.startTime*step, left = testCase.startTime*step,
width = testCase.endTime*step - left, width = testCase.endTime*step - left,
...@@ -221,7 +220,7 @@ ...@@ -221,7 +220,7 @@
left: left + '%', left: left + '%',
width: width + '%' width: width + '%'
}, },
params = videoProgressSlider.getRangeParams( params = state.videoProgressSlider.getRangeParams(
testCase.startTime, testCase.endTime, testCase.duration testCase.startTime, testCase.endTime, testCase.duration
); );
...@@ -231,40 +230,44 @@ ...@@ -231,40 +230,44 @@
describe('notifyThroughHandleEnd', function () { describe('notifyThroughHandleEnd', function () {
beforeEach(function () { beforeEach(function () {
initialize(); state = jasmine.initializePlayer();
spyOnEvent(videoProgressSlider.handle, 'focus'); spyOnEvent(state.videoProgressSlider.handle, 'focus');
spyOn(videoProgressSlider, 'notifyThroughHandleEnd') spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd')
.andCallThrough(); .andCallThrough();
}); });
it('params.end = true', function () { 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'); .toBe('video ended');
expect('focus').toHaveBeenTriggeredOn(videoProgressSlider.handle); expect('focus').toHaveBeenTriggeredOn(
state.videoProgressSlider.handle
);
}); });
it('params.end = false', function () { 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'); .toBe('video position');
expect('focus').not.toHaveBeenTriggeredOn(videoProgressSlider.handle); expect('focus').not.toHaveBeenTriggeredOn(
state.videoProgressSlider.handle
);
}); });
it('is called when video plays', function () { it('is called when video plays', function () {
videoPlayer.play(); state.videoPlayer.play();
waitsFor(function () { waitsFor(function () {
return videoPlayer.isPlaying(); return state.videoPlayer.isPlaying();
}, 'duration is set, video is playing', 5000); }, 'duration is set, video is playing', 5000);
runs(function () { runs(function () {
expect(videoProgressSlider.notifyThroughHandleEnd) expect(state.videoProgressSlider.notifyThroughHandleEnd)
.toHaveBeenCalledWith({end: false}); .toHaveBeenCalledWith({end: false});
}); });
}); });
......
(function() { (function (undefined) {
describe('VideoQualityControl', function() { describe('VideoQualityControl', function () {
var state, videoControl, videoQualityControl, oldOTBD; var state, oldOTBD;
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine
.createSpy('onTouchBasedDevice')
.andReturn(null);
});
function initialize() { afterEach(function () {
loadFixtures('video.html'); $('source').remove();
state = new Video('#example'); window.onTouchBasedDevice = oldOTBD;
videoControl = state.videoControl; });
videoQualityControl = state.videoQualityControl;
}
beforeEach(function() { describe('constructor', function () {
oldOTBD = window.onTouchBasedDevice; beforeEach(function () {
window.onTouchBasedDevice = jasmine state = jasmine.initializePlayer('video.html');
.createSpy('onTouchBasedDevice') });
.andReturn(null);
});
afterEach(function() { it('render the quality control', function () {
$('source').remove(); var container = state.videoControl.secondaryControlsEl;
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() { expect(container).toContain('a.quality_control');
var oldYT = window.YT; });
beforeEach(function() { it('add ARIA attributes to quality control', function () {
window.YT = { var qualityControl = $('a.quality_control');
Player: function () {
return { getDuration: function () { return 60; } };
},
PlayerState: oldYT.PlayerState,
ready: function(f){f();}
};
initialize(); expect(qualityControl).toHaveAttrs({
}); 'role': 'button',
'title': 'HD off',
'aria-disabled': 'false'
});
});
afterEach(function () { it('bind the quality control', function () {
window.YT = oldYT; var handler = state.videoQualityControl.toggleQuality;
});
it('render the quality control', function() { expect($('a.quality_control')).toHandleWith('click', handler);
var container = videoControl.secondaryControlsEl; });
expect(container).toContain('a.quality_control');
});
it('add ARIA attributes to quality control', function () {
var qualityControl = $('a.quality_control');
expect(qualityControl).toHaveAttrs({
'role': 'button',
'title': 'HD off',
'aria-disabled': 'false'
}); });
});
it('bind the quality control', function() {
var handler = videoQualityControl.toggleQuality;
expect($('a.quality_control')).toHandleWith('click', handler);
});
}); });
});
}).call(this); }).call(this);
(function() { (function (undefined) {
describe('VideoSpeedControl', function() { describe('VideoSpeedControl', function () {
var state, videoPlayer, videoControl, videoSpeedControl; var state, oldOTBD;
function initialize() { beforeEach(function () {
loadFixtures('video_all.html'); oldOTBD = window.onTouchBasedDevice;
state = new Video('#example'); window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
videoPlayer = state.videoPlayer; .andReturn(null);
videoControl = state.videoControl;
videoSpeedControl = state.videoSpeedControl;
}
beforeEach(function() {
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
});
afterEach(function() {
$('source').remove();
window.onTouchBasedDevice = oldOTBD;
});
describe('constructor', function() {
describe('always', function() {
beforeEach(function() {
initialize();
});
it('add the video speed control to player', function() {
var li, secondaryControls;
secondaryControls = $('.secondary-controls');
li = secondaryControls.find('.video_speeds li');
expect(secondaryControls).toContain('.speeds');
expect(secondaryControls).toContain('.video_speeds');
expect(secondaryControls.find('p.active').text()).toBe('1.0x');
expect(li.filter('.active')).toHaveData('speed', videoSpeedControl.currentSpeed);
expect(li.length).toBe(videoSpeedControl.speeds.length);
$.each(li.toArray().reverse(), function(index, link) {
expect($(link)).toHaveData('speed', videoSpeedControl.speeds[index]);
expect($(link).find('a').text()).toBe(videoSpeedControl.speeds[index] + 'x');
});
});
it('add ARIA attributes to speed control', function () {
var speedControl = $('div.speeds>a');
expect(speedControl).toHaveAttrs({
'role': 'button',
'title': 'Speeds',
'aria-disabled': 'false'
});
});
it('bind to change video speed link', function() {
expect($('.video_speeds a')).toHandleWith('click', videoSpeedControl.changeVideoSpeed);
});
});
describe('when running on touch based device', function() {
$.each(['iPad', 'Android'], function(index, device) {
it('is not rendered on' + device, function() {
window.onTouchBasedDevice.andReturn([device]);
initialize();
expect(state.el.find('div.speeds')).not.toExist();
});
});
});
describe('when running on non-touch based device', function() {
beforeEach(function() {
initialize();
}); });
it('open the speed toggle on hover', function() { afterEach(function () {
$('.speeds').mouseenter(); $('source').remove();
expect($('.speeds')).toHaveClass('open'); window.onTouchBasedDevice = oldOTBD;
$('.speeds').mouseleave();
expect($('.speeds')).not.toHaveClass('open');
}); });
it('close the speed toggle on mouse out', function() { describe('constructor', function () {
$('.speeds').mouseenter().mouseleave(); describe('always', function () {
expect($('.speeds')).not.toHaveClass('open'); beforeEach(function () {
state = jasmine.initializePlayer();
});
it('add the video speed control to player', function () {
var li, secondaryControls;
secondaryControls = $('.secondary-controls');
li = secondaryControls.find('.video_speeds li');
expect(secondaryControls).toContain('.speeds');
expect(secondaryControls).toContain('.video_speeds');
expect(secondaryControls.find('p.active').text())
.toBe('1.0x');
expect(li.filter('.active')).toHaveData(
'speed', state.videoSpeedControl.currentSpeed
);
expect(li.length).toBe(state.videoSpeedControl.speeds.length);
$.each(li.toArray().reverse(), function (index, link) {
expect($(link)).toHaveData(
'speed', state.videoSpeedControl.speeds[index]
);
expect($(link).find('a').text()).toBe(
state.videoSpeedControl.speeds[index] + 'x'
);
});
});
it('add ARIA attributes to speed control', function () {
var speedControl = $('div.speeds>a');
expect(speedControl).toHaveAttrs({
'role': 'button',
'title': 'Speeds',
'aria-disabled': 'false'
});
});
it('bind to change video speed link', function () {
expect($('.video_speeds a')).toHandleWith(
'click', state.videoSpeedControl.changeVideoSpeed
);
});
});
describe('when running on touch based device', function () {
$.each(['iPad', 'Android'], function (index, device) {
it('is not rendered on' + device, function () {
window.onTouchBasedDevice.andReturn([device]);
state = jasmine.initializePlayer();
expect(state.el.find('div.speeds')).not.toExist();
});
});
});
describe('when running on non-touch based device', function () {
beforeEach(function () {
state = jasmine.initializePlayer();
});
it('open the speed toggle on hover', function () {
$('.speeds').mouseenter();
expect($('.speeds')).toHaveClass('open');
$('.speeds').mouseleave();
expect($('.speeds')).not.toHaveClass('open');
});
it('close the speed toggle on mouse out', function () {
$('.speeds').mouseenter().mouseleave();
expect($('.speeds')).not.toHaveClass('open');
});
it('close the speed toggle on click', function () {
$('.speeds').mouseenter().click();
expect($('.speeds')).not.toHaveClass('open');
});
// Tabbing depends on the following order:
// 1. Play anchor
// 2. Speed anchor
// 3. A number of speed entry anchors
// 4. Volume anchor
// If another focusable element is inserted or if the order is
// changed, things will malfunction as a flag,
// state.previousFocus, is set in the 1,3,4 elements and is
// used to determine the behavior of foucus() and blur() for
// the speed anchor.
it(
'checks for a certain order in focusable elements in ' +
'video controls',
function ()
{
var foundFirst = false,
playIndex, speedIndex, firstSpeedEntry, lastSpeedEntry,
volumeIndex;
$('.video-controls').find('a, :focusable').each(
function (index)
{
if ($(this).hasClass('video_control')) {
playIndex = index;
} else if ($(this).parent().hasClass('speeds')) {
speedIndex = index;
} else if ($(this).hasClass('speed_link')) {
if (!foundFirst) {
firstSpeedEntry = index;
foundFirst = true;
}
lastSpeedEntry = index;
} else if ($(this).parent().hasClass('volume')) {
volumeIndex = index;
}
});
expect(playIndex+1).toEqual(speedIndex);
expect(speedIndex+1).toEqual(firstSpeedEntry);
expect(lastSpeedEntry+1).toEqual(volumeIndex);
});
});
}); });
it('close the speed toggle on click', function() { describe('changeVideoSpeed', function () {
$('.speeds').mouseenter().click(); // This is an unnecessary test. The internal browser API, and
expect($('.speeds')).not.toHaveClass('open'); // YouTube API detect (and do not do anything) if there is a
}); // request for a speed that is already set.
// Tabbing depends on the following order: //
// 1. Play anchor // describe("when new speed is the same") ...
// 2. Speed anchor
// 3. A number of speed entry anchors describe('when new speed is not the same', function () {
// 4. Volume anchor beforeEach(function () {
// If another focusable element is inserted or if the order is changed, things will state = jasmine.initializePlayer();
// malfunction as a flag, state.previousFocus, is set in the 1,3,4 elements and is state.videoSpeedControl.setSpeed(1.0);
// used to determine the behavior of foucus() and blur() for the speed anchor. spyOn(state.videoPlayer, 'onSpeedChange').andCallThrough();
it('checks for a certain order in focusable elements in video controls', function() {
var playIndex, speedIndex, firstSpeedEntry, lastSpeedEntry, volumeIndex, foundFirst = false; $('li[data-speed="0.75"] a').click();
$('.video-controls').find('a, :focusable').each(function(index) { });
if ($(this).hasClass('video_control')) {
playIndex = index; it('trigger speedChange event', function () {
} expect(state.videoPlayer.onSpeedChange).toHaveBeenCalled();
else if ($(this).parent().hasClass('speeds')) { expect(state.videoSpeedControl.currentSpeed).toEqual(0.75);
speedIndex = index; });
} });
else if ($(this).hasClass('speed_link')) {
if (!foundFirst) { describe(
firstSpeedEntry = index; 'make sure the speed control gets the focus afterwards',
foundFirst = true; function ()
} {
lastSpeedEntry = index; var anchor;
}
else if ($(this).parent().hasClass('volume')) { beforeEach(function () {
volumeIndex = index; state = jasmine.initializePlayer();
} anchor= $('.speeds > a').first();
}); state.videoSpeedControl.setSpeed(1.0);
expect(playIndex+1).toEqual(speedIndex); spyOnEvent(anchor, 'focus');
expect(speedIndex+1).toEqual(firstSpeedEntry); });
expect(lastSpeedEntry+1).toEqual(volumeIndex);
}); it('when the speed is the same', function () {
}); $('li[data-speed="1.0"] a').click();
}); expect('focus').toHaveBeenTriggeredOn(anchor);
});
describe('changeVideoSpeed', function() {
// This is an unnecessary test. The internal browser API, and YouTube API it('when the speed is not the same', function () {
// detect (and do not do anything) if there is a request for a speed that $('li[data-speed="0.75"] a').click();
// is already set. expect('focus').toHaveBeenTriggeredOn(anchor);
// });
// describe("when new speed is the same") ... });
describe('when new speed is not the same', function() {
beforeEach(function() {
initialize();
videoSpeedControl.setSpeed(1.0);
spyOn(videoPlayer, 'onSpeedChange').andCallThrough();
$('li[data-speed="0.75"] a').click();
});
it('trigger speedChange event', function() {
expect(videoPlayer.onSpeedChange).toHaveBeenCalled();
expect(videoSpeedControl.currentSpeed).toEqual(0.75);
});
});
describe('make sure the speed control gets the focus afterwards', function() {
var anchor;
beforeEach(function() {
initialize();
anchor= $('.speeds > a').first();
videoSpeedControl.setSpeed(1.0);
spyOnEvent(anchor, 'focus');
});
it('when the speed is the same', function() {
$('li[data-speed="1.0"] a').click();
expect('focus').toHaveBeenTriggeredOn(anchor);
}); });
it('when the speed is not the same', function() { describe('onSpeedChange', function () {
$('li[data-speed="0.75"] a').click(); beforeEach(function () {
expect('focus').toHaveBeenTriggeredOn(anchor); state = jasmine.initializePlayer();
$('li[data-speed="1.0"] a').addClass('active');
state.videoSpeedControl.setSpeed(0.75);
});
it('set the new speed as active', function () {
expect($('.video_speeds li[data-speed="1.0"]'))
.not.toHaveClass('active');
expect($('.video_speeds li[data-speed="0.75"]'))
.toHaveClass('active');
expect($('.speeds p.active')).toHaveHtml('0.75x');
});
}); });
});
}); });
describe('onSpeedChange', function() {
beforeEach(function() {
initialize();
$('li[data-speed="1.0"] a').addClass('active');
videoSpeedControl.setSpeed(0.75);
});
it('set the new speed as active', function() {
expect($('.video_speeds li[data-speed="1.0"]')).not.toHaveClass('active');
expect($('.video_speeds li[data-speed="0.75"]')).toHaveClass('active');
expect($('.speeds p.active')).toHaveHtml('0.75x');
});
});
});
}).call(this); }).call(this);
(function() { (function (undefined) {
describe('VideoVolumeControl', function() { describe('VideoVolumeControl', function () {
var state, videoControl, videoVolumeControl, oldOTBD; var state, oldOTBD;
function initialize() { beforeEach(function () {
loadFixtures('video_all.html'); oldOTBD = window.onTouchBasedDevice;
state = new Video('#example'); window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
videoControl = state.videoControl; .andReturn(null);
videoVolumeControl = state.videoVolumeControl;
} afterEach(function () {
$('source').remove();
beforeEach(function() { window.onTouchBasedDevice = oldOTBD;
oldOTBD = window.onTouchBasedDevice; });
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(null);
});
afterEach(function() { describe('constructor', function () {
$('source').remove(); beforeEach(function () {
window.onTouchBasedDevice = oldOTBD; spyOn($.fn, 'slider').andCallThrough();
}); state = jasmine.initializePlayer();
});
describe('constructor', function() { it('initialize currentVolume to 100%', function () {
beforeEach(function() { // Please note that:
spyOn($.fn, 'slider').andCallThrough(); // 0% -> 0
$.cookie.andReturn('75'); // 100% -> 1.0
initialize(); expect(state.videoVolumeControl.currentVolume).toEqual(1);
}); });
it('initialize currentVolume to 75', function() {
expect(state.videoVolumeControl.currentVolume).toEqual(75);
});
it('render the volume control', function() {
expect(videoControl.secondaryControlsEl.html()).toContain("<div class=\"volume\">\n");
});
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
});
});
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'];
expect(sliderHandle).toHaveAttrs({
'role': 'slider',
'title': 'volume',
'aria-disabled': 'false',
'aria-valuemin': '0',
'aria-valuemax': '100'
});
expect(sliderHandle.attr('aria-valuenow')).toBeInRange(0, 100);
expect(sliderHandle.attr('aria-valuetext')).toBeInArray(arr);
}); it('render the volume control', function () {
expect(state.videoControl.secondaryControlsEl.html())
.toContain("<div class=\"volume\">\n");
});
it('add ARIA attributes to volume control', function () { it('create the slider', function () {
var volumeControl = $('div.volume>a'); expect($.fn.slider).toHaveBeenCalledWith({
expect(volumeControl).toHaveAttrs({ orientation: "vertical",
'role': 'button', range: "min",
'title': 'Volume', min: 0,
'aria-disabled': 'false' max: 100,
}); value: state.videoVolumeControl.currentVolume,
}); change: state.videoVolumeControl.onChange,
slide: state.videoVolumeControl.onChange
it('bind the volume control', function() { });
expect($('.volume>a')).toHandleWith('click', videoVolumeControl.toggleMute); });
expect($('.volume')).not.toHaveClass('open');
$('.volume').mouseenter();
expect($('.volume')).toHaveClass('open');
$('.volume').mouseleave();
expect($('.volume')).not.toHaveClass('open');
});
});
describe('onChange', function() { it('add ARIA attributes to slider handle', function () {
beforeEach(function() { var sliderHandle = $('div.volume-slider>a.ui-slider-handle'),
initialize(); arr = [
}); 'muted', 'very low', 'low', 'average', 'loud',
'very loud', 'maximum'
];
expect(sliderHandle).toHaveAttrs({
'role': 'slider',
'title': 'volume',
'aria-disabled': 'false',
'aria-valuemin': '0',
'aria-valuemax': '100'
});
expect(sliderHandle.attr('aria-valuenow')).toBeInRange(0, 100);
expect(sliderHandle.attr('aria-valuetext')).toBeInArray(arr);
});
describe('when the new volume is more than 0', function() { it('add ARIA attributes to volume control', function () {
beforeEach(function() { var volumeControl = $('div.volume>a');
videoVolumeControl.onChange(void 0, {
value: 60
});
});
it('set the player volume', function() { expect(volumeControl).toHaveAttrs({
expect(videoVolumeControl.currentVolume).toEqual(60); 'role': 'button',
}); 'title': 'Volume',
'aria-disabled': 'false'
});
});
it('remote muted class', function() { it('bind the volume control', function () {
expect($('.volume')).not.toHaveClass('muted'); expect($('.volume>a')).toHandleWith(
}); 'click', state.videoVolumeControl.toggleMute
}); );
expect($('.volume')).not.toHaveClass('open');
describe('when the new volume is 0', function() { $('.volume').mouseenter();
beforeEach(function() { expect($('.volume')).toHaveClass('open');
videoVolumeControl.onChange(void 0, {
value: 0
});
});
it('set the player volume', function() { $('.volume').mouseleave();
expect(videoVolumeControl.currentVolume).toEqual(0); expect($('.volume')).not.toHaveClass('open');
});
}); });
it('add muted class', function() { describe('onChange', function () {
expect($('.volume')).toHaveClass('muted'); var initialData = [{
}); range: 'muted',
}); value: 0,
expectation: 'muted'
var initialData = [ }, {
{ range: 'in ]0,20]',
range: 'muted', value: 10,
value: 0, expectation: 'very low'
expectation: 'muted' }, {
}, range: 'in ]20,40]',
{ value: 30,
range: 'in ]0,20]', expectation: 'low'
value: 10, }, {
expectation: 'very low' range: 'in ]40,60]',
}, value: 50,
{ expectation: 'average'
range: 'in ]20,40]', }, {
value: 30, range: 'in ]60,80]',
expectation: 'low' value: 70,
}, expectation: 'loud'
{ }, {
range: 'in ]40,60]', range: 'in ]80,100[',
value: 50, value: 90,
expectation: 'average' expectation: 'very loud'
}, }, {
{ range: 'maximum',
range: 'in ]60,80]', value: 100,
value: 70, expectation: 'maximum'
expectation: 'loud' }];
},
{ beforeEach(function () {
range: 'in ]80,100[', state = jasmine.initializePlayer();
value: 90,
expectation: 'very loud'
},
{
range: 'maximum',
value: 100,
expectation: 'maximum'
}
];
$.each(initialData, function(index, data) {
describe('when the new volume is ' + data.range, function() {
beforeEach(function() {
videoVolumeControl.onChange(void 0, {
value: data.value
}); });
});
it('changes ARIA attributes', function () { describe('when the new volume is more than 0', function () {
var sliderHandle = $('div.volume-slider>a.ui-slider-handle'); beforeEach(function () {
expect(sliderHandle).toHaveAttrs({ state.videoVolumeControl.onChange(void 0, {
'aria-valuenow': data.value.toString(10), value: 60
'aria-valuetext': data.expectation });
});
it('set the player volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(60);
});
it('remote muted class', function () {
expect($('.volume')).not.toHaveClass('muted');
});
}); });
});
});
});
});
describe('toggleMute', function() { describe('when the new volume is 0', function () {
beforeEach(function() { beforeEach(function () {
initialize(); state.videoVolumeControl.onChange(void 0, {
}); value: 0
});
});
describe('when the current volume is more than 0', function() { it('set the player volume', function () {
beforeEach(function() { expect(state.videoVolumeControl.currentVolume).toEqual(0);
videoVolumeControl.currentVolume = 60; });
videoVolumeControl.buttonEl.trigger('click');
});
it('save the previous volume', function() { it('add muted class', function () {
expect(videoVolumeControl.previousVolume).toEqual(60); expect($('.volume')).toHaveClass('muted');
}); });
});
it('set the player volume', function() { $.each(initialData, function (index, data) {
expect(videoVolumeControl.currentVolume).toEqual(0); 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'
);
expect(sliderHandle).toHaveAttrs({
'aria-valuenow': data.value.toString(10),
'aria-valuetext': data.expectation
});
});
});
});
}); });
});
describe('when the current volume is 0', function() { describe('toggleMute', function () {
beforeEach(function() { beforeEach(function () {
videoVolumeControl.currentVolume = 0; state = jasmine.initializePlayer();
videoVolumeControl.previousVolume = 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('set the player volume to previous volume', function() { it('save the previous volume', function () {
expect(videoVolumeControl.currentVolume).toEqual(60); expect(state.videoVolumeControl.previousVolume).toEqual(60);
});
it('set the player volume', function () {
expect(state.videoVolumeControl.currentVolume).toEqual(0);
});
});
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(state.videoVolumeControl.currentVolume).toEqual(60);
});
});
}); });
});
}); });
});
}).call(this); }).call(this);
...@@ -559,16 +559,32 @@ function (VideoPlayer) { ...@@ -559,16 +559,32 @@ function (VideoPlayer) {
// example the length of the video can be determined from the meta // example the length of the video can be determined from the meta
// data. // data.
function fetchMetadata() { function fetchMetadata() {
var _this = this; var _this = this,
metadataXHRs = [];
this.metadata = {}; this.metadata = {};
$.each(this.videos, function (speed, url) { $.each(this.videos, function (speed, url) {
_this.getVideoMetadata(url, function (data) { var xhr = _this.getVideoMetadata(url, function (data) {
if (data.data) { if (data.data) {
_this.metadata[data.data.id] = 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,52 +176,21 @@ function (HTML5Video, Resizer) { ...@@ -176,52 +176,21 @@ function (HTML5Video, Resizer) {
_resize(state, videoWidth, videoHeight); _resize(state, videoWidth, videoHeight);
// We wait for metadata to arrive, before we request the update // After initialization, update the VCR with total time.
// of the VCR video time, and of the start-end time region. // At this point only the metadata duration is available (not
// Metadata contains duration of the video. We wait for 2 // very precise), but it is better than having 00:00:00 for
// seconds, and then abandon our attempts to update the VCR // total time.
// video time (and the start-end time region) using metadata. if (state.youtubeMetadataReceived) {
(function () { // Metadata was already received, and is available.
var checkInterval = window.setInterval( _updateVcrAndRegion(state);
checkForMetadata, 50 } else {
), // We wait for metadata to arrive, before we request the update
numberOfChecks = 0; // of the VCR video time, and of the start-end time region.
// Metadata contains duration of the video.
return; state.el.on('metadata_received', function () {
_updateVcrAndRegion(state);
function checkForMetadata() { });
if (state.metadata && state.metadata[state.youtubeId()]) { }
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',
{
time: 0,
duration: duration
}
);
state.trigger(
'videoProgressSlider.updateStartEndTimeRegion',
{
duration: duration
}
);
window.clearInterval(checkInterval);
} else {
numberOfChecks += 1;
if (numberOfChecks === 40) {
window.clearInterval(checkInterval);
}
}
}
}());
}); });
} }
...@@ -230,7 +199,26 @@ function (HTML5Video, Resizer) { ...@@ -230,7 +199,26 @@ function (HTML5Video, Resizer) {
} }
} }
function _resize (state, videoWidth, videoHeight) { function _updateVcrAndRegion(state) {
var duration = state.videoPlayer.duration();
state.trigger(
'videoControl.updateVcrVidTime',
{
time: 0,
duration: duration
}
);
state.trigger(
'videoProgressSlider.updateStartEndTimeRegion',
{
duration: duration
}
);
}
function _resize(state, videoWidth, videoHeight) {
state.resizer = new Resizer({ state.resizer = new Resizer({
element: state.videoEl, element: state.videoEl,
elementRatio: videoWidth/videoHeight, elementRatio: videoWidth/videoHeight,
...@@ -783,7 +771,17 @@ function (HTML5Video, Resizer) { ...@@ -783,7 +771,17 @@ function (HTML5Video, Resizer) {
* This instability is internal to the player API (or browser internals). * This instability is internal to the player API (or browser internals).
*/ */
function duration() { 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 // For YouTube videos, before the video starts playing, the API
// function player.getDuration() will return 0. This means that the VCR // 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