Add Timed Transcripts Editor.

This commit is contained in:
Anton Stupak
2013-08-13 18:10:44 +03:00
committed by polesye
parent 1f7bb112bf
commit aecc20af6b
75 changed files with 8762 additions and 279 deletions

View File

@@ -0,0 +1,300 @@
define(
[
"jquery", "backbone", "underscore",
"js/views/transcripts/utils", "js/views/transcripts/editor",
"js/views/metadata", "js/models/metadata", "js/collections/metadata",
"underscore.string", "xmodule", "js/views/transcripts/metadata_videolist",
"jasmine-jquery"
],
function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCollection, _str) {
describe('Transcripts.Editor', function () {
var VideoListEntry = {
default_value: ['a thing', 'another thing'],
display_name: 'Video URL',
explicitly_set: true,
field_name: 'video_url',
help: 'A list of things.',
options: [],
type: MetadataModel.VIDEO_LIST_TYPE,
value: [
'http://youtu.be/12345678901',
'video.mp4',
'video.webm'
]
},
DisplayNameEntry = {
default_value: 'default value',
display_name: 'Dispaly Name',
explicitly_set: true,
field_name: 'display_name',
help: 'Specifies the name for this component.',
options: [],
type: MetadataModel.GENERIC_TYPE,
value: 'display value'
},
models = [DisplayNameEntry, VideoListEntry],
testData = {
'display_name': DisplayNameEntry,
'video_url': VideoListEntry
},
metadataDict = {
object: testData,
string: JSON.stringify(testData)
},
transcripts, container;
beforeEach(function () {
var tpl = sandbox({
'class': 'wrapper-comp-settings basic_metadata_edit',
'data-metadata': JSON.stringify(metadataDict['object'])
});
appendSetFixtures(tpl);
container = $('.basic_metadata_edit');
spyOn(Utils, 'command');
});
afterEach(function () {
Utils.Storage.remove('sub');
});
describe('Test initialization', function () {
beforeEach(function () {
spyOn(MetadataView, 'Editor');
transcripts = new Editor({
el: container
});
});
$.each(metadataDict, function(index, val) {
it('toModels with argument as ' + index, function () {
expect(transcripts.toModels(val)).toEqual(models);
});
});
it('MetadataView.Editor is initialized', function () {
expect(MetadataView.Editor).toHaveBeenCalledWith({
el: container,
collection: transcripts.collection
});
});
});
describe('Test synchronization', function () {
var nameEntry = {
default_value: 'default value',
display_name: 'Display Name',
explicitly_set: true,
field_name: 'display_name',
help: 'Specifies the name for this component.',
options: [],
type: MetadataModel.GENERIC_TYPE,
value: 'default'
},
subEntry = {
default_value: 'default value',
display_name: 'Timed Transcript',
explicitly_set: true,
field_name: 'sub',
help: 'Specifies the name for this component.',
options: [],
type: 'Generic',
value: 'default'
},
html5SourcesEntry = {
default_value: ['a thing', 'another thing'],
display_name: 'Video Sources',
explicitly_set: true,
field_name: 'html5_sources',
help: 'A list of html5 sources.',
options: [],
type: MetadataModel.LIST_TYPE,
value: ['default.mp4', 'default.webm']
},
youtubeEntry = {
default_value: 'OEoXaMPEzfM',
display_name: 'Youtube ID',
explicitly_set: true,
field_name: 'youtube_id_1_0',
help: 'Specifies the name for this component.',
options: [],
type: MetadataModel.GENERIC_TYPE,
value: 'OEoXaMPEzfM'
},
metadataCollection,
metadataView;
beforeEach(function () {
spyOn(MetadataView, 'Editor');
transcripts = new Editor({
el: container
});
metadataCollection = new MetadataCollection(
[
nameEntry,
subEntry,
html5SourcesEntry,
youtubeEntry
]
);
metadataView = jasmine.createSpyObj(
'MetadataView.Editor',
[
'getModifiedMetadataValues'
]
);
});
describe('Test Advanced to Basic synchronization', function () {
it('Correct data', function () {
transcripts.syncBasicTab(metadataCollection, metadataView);
var collection = transcripts.collection.models,
displayNameValue = collection[0].getValue(),
videoUrlValue = collection[1].getValue();
expect(displayNameValue).toBe('default');
expect(videoUrlValue).toEqual([
'http://youtu.be/OEoXaMPEzfM',
'default.mp4',
'default.webm'
]);
});
it('If metadataCollection is not defined', function () {
transcripts.syncBasicTab(null);
var collection = transcripts.collection.models,
videoUrlValue = collection[1].getValue();
expect(videoUrlValue).toEqual([
'http://youtu.be/12345678901',
'video.mp4',
'video.webm'
]);
});
it('Youtube Id has length not eqaul 11', function () {
var model = metadataCollection.findWhere({
field_name: 'youtube_id_1_0'
});
model.setValue([
'12345678',
'default.mp4',
'default.webm'
]);
transcripts.syncBasicTab(metadataCollection, metadataView);
var collection = transcripts.collection.models,
videoUrlValue = collection[1].getValue();
expect(videoUrlValue).toEqual([
'',
'default.mp4',
'default.webm'
]);
});
});
describe('Test Basic to Advanced synchronization', function () {
it('Correct data', function () {
transcripts.syncAdvancedTab(metadataCollection);
var collection = metadataCollection.models,
displayNameValue = collection[0].getValue(),
subValue = collection[1].getValue(),
html5SourcesValue = collection[2].getValue(),
youtubeValue = collection[3].getValue();
expect(displayNameValue).toBe('display value');
expect(subValue).toBe('default');
expect(html5SourcesValue).toEqual([
'video.mp4',
'video.webm'
]);
expect(youtubeValue).toBe('12345678901');
});
it('metadataCollection is not defined', function () {
transcripts.syncAdvancedTab(null);
var collection = metadataCollection.models,
displayNameValue = collection[0].getValue(),
subValue = collection[1].getValue(),
html5SourcesValue = collection[2].getValue(),
youtubeValue = collection[3].getValue();
expect(displayNameValue).toBe('default');
expect(subValue).toBe('default');
expect(html5SourcesValue).toEqual([
'default.mp4',
'default.webm'
]);
expect(youtubeValue).toBe('OEoXaMPEzfM');
});
it('Youtube Id is not adjusted', function () {
var model = transcripts.collection.models[1];
model.setValue([
'video.mp4',
'video.webm'
]);
transcripts.syncAdvancedTab(metadataCollection);
var collection = metadataCollection.models,
html5SourcesValue = collection[2].getValue(),
youtubeValue = collection[3].getValue();
expect(html5SourcesValue).toEqual([
'video.mp4',
'video.webm'
]);
expect(youtubeValue).toBe('');
});
it('Timed Transcript field is updated', function () {
Utils.Storage.set('sub', 'test_value');
transcripts.syncAdvancedTab(metadataCollection);
var collection = metadataCollection.models,
subValue = collection[1].getValue();
expect(subValue).toBe('test_value');
});
it('Timed Transcript field is updated just once', function () {
Utils.Storage.set('sub', 'test_value');
var collection = metadataCollection.models,
subModel = collection[1];
spyOn(subModel, 'setValue');
transcripts.syncAdvancedTab(metadataCollection);
transcripts.syncAdvancedTab(metadataCollection);
transcripts.syncAdvancedTab(metadataCollection);
expect(subModel.setValue.calls.length).toBe(1);
});
});
});
});
});

View File

@@ -0,0 +1,241 @@
define(
[
"jquery", "underscore",
"js/views/transcripts/utils", "js/views/transcripts/file_uploader",
"xmodule", "jquery.form", "jasmine-jquery"
],
function ($, _, Utils, FileUploader) {
describe('Transcripts.FileUploader', function () {
var videoListEntryTemplate = readFixtures(
'transcripts/metadata-videolist-entry.underscore'
),
fileUploadTemplate = readFixtures(
'transcripts/file-upload.underscore'
),
view;
beforeEach(function () {
setFixtures(
$("<div>", {id: "metadata-videolist-entry"})
.html(videoListEntryTemplate)
);
appendSetFixtures(
$("<script>",
{
id: "file-upload",
type: "text/template"
}
).text(fileUploadTemplate)
);
var messenger = jasmine.createSpyObj(
'MessageManager',
['render', 'showError', 'hideError']
),
videoListObject = jasmine.createSpyObj(
'MetadataView.VideoList',
['render', 'getVideoObjectsList']
),
$container = $('.transcripts-status');
$container
.append('<div class="transcripts-file-uploader" />')
.append('<a class="setting-upload" href="#">Upload</a>');
spyOn(FileUploader.prototype, 'render').andCallThrough();
view = new FileUploader({
el: $container,
messenger: messenger,
videoListObject: videoListObject,
component_id: 'component_id'
});
});
it('Initialize', function () {
expect(view.file).toBe(false);
expect(FileUploader.prototype.render).toHaveBeenCalled();
});
describe('Render', function () {
beforeEach(function () {
spyOn(_, 'template').andCallThrough();
});
it('Template doesn\'t exist', function () {
spyOn(console, 'error');
view.uploadTpl = '';
view.render();
expect(console.error).toHaveBeenCalled();
expect(view.render).not.toThrow();
expect(_.template).not.toHaveBeenCalled();
});
it('Container where template will be inserted doesn\'t exist',
function () {
$('.transcripts-file-uploader').remove();
view.render();
expect(view.render).not.toThrow();
expect(_.template).not.toHaveBeenCalled();
}
);
it('All works okay if all data is okay', function () {
var elList = ['$form', '$input', '$progress'],
validFileExtensions = ['srt', 'sjson'],
result = $.map(validFileExtensions, function(item, index) {
return '.' + item;
}).join(', ');
view.validFileExtensions = validFileExtensions;
view.render();
expect(view.render).not.toThrow();
expect(_.template).toHaveBeenCalled();
$.each(elList, function(index, el) {
expect(view[el].length).not.toBe(0);
});
expect(view.$input.attr('accept')).toBe(result);
});
});
describe('Upload', function () {
it('File is not chosen', function () {
spyOn($.fn, 'ajaxSubmit');
view.upload();
expect(view.$form.ajaxSubmit).not.toHaveBeenCalled();
});
it('File is chosen', function () {
spyOn($.fn, 'ajaxSubmit');
view.file = {};
view.upload();
expect(view.$form.ajaxSubmit).toHaveBeenCalled();
});
});
it('clickHandler', function () {
spyOn($.fn, 'trigger');
$('.setting-upload').click();
expect($('.setting-upload').trigger).toHaveBeenCalledWith('click');
expect(view.$input).toHaveValue('');
});
describe('changeHadler', function () {
beforeEach(function () {
spyOn(view, 'upload');
});
it('Valid File Type - error should be hided', function () {
spyOn(view, 'checkExtValidity').andReturn(true);
view.$input.change();
expect(view.checkExtValidity).toHaveBeenCalled();
expect(view.upload).toHaveBeenCalled();
expect(view.options.messenger.hideError).toHaveBeenCalled();
});
it('Invalid File Type - error should be shown', function () {
spyOn(view, 'checkExtValidity').andReturn(false);
view.$input.change();
expect(view.checkExtValidity).toHaveBeenCalled();
expect(view.upload).not.toHaveBeenCalled();
expect(view.options.messenger.showError).toHaveBeenCalled();
});
});
describe('checkExtValidity', function () {
var data = {
Correct: {
name: 'file_name.srt',
isValid: true
},
Incorrect: {
name: 'file_name.mp4',
isValid: false
}
};
$.each(data, function(fileType, fileInfo) {
it(fileType + ' file type', function () {
var result = view.checkExtValidity(fileInfo);
expect(result).toBe(fileInfo.isValid);
});
});
});
it('xhrResetProgressBar', function () {
view.xhrResetProgressBar();
expect(view.$progress.width()).toBe(0);
expect(view.$progress.html()).toBe('0%');
expect(view.$progress).not.toHaveClass('is-invisible');
});
it('xhrProgressHandler', function () {
var percent = 26;
spyOn($.fn, 'width').andCallThrough();
view.xhrProgressHandler(null, null, null, percent);
expect(view.$progress.width).toHaveBeenCalledWith(percent + '%');
expect(view.$progress.html()).toBe(percent + '%');
});
describe('xhrCompleteHandler', function () {
it('Ajax Success', function () {
var xhr = {
status: 200,
responseText: JSON.stringify({
status: 'Success',
subs: 'test'
})
};
spyOn(Utils.Storage, 'set');
view.xhrCompleteHandler(xhr);
expect(view.$progress).toHaveClass('is-invisible');
expect(view.options.messenger.render.mostRecentCall.args[0])
.toEqual('uploaded');
expect(Utils.Storage.set)
.toHaveBeenCalledWith('sub', 'test');
});
var assertAjaxError = function (xhr) {
spyOn(Utils.Storage, 'set');
view.xhrCompleteHandler(xhr);
expect(view.options.messenger.showError).toHaveBeenCalled();
expect(view.$progress).toHaveClass('is-invisible');
expect(view.options.messenger.render)
.not
.toHaveBeenCalled();
expect(Utils.Storage.set)
.not
.toHaveBeenCalledWith('sub', 'test');
};
it('Ajax transport Error', function () {
var xhr = {
status: 400,
responseText: JSON.stringify({})
};
assertAjaxError(xhr);
});
});
});
});

View File

@@ -0,0 +1,284 @@
define(
[
"jquery", "underscore",
"js/views/transcripts/utils", "js/views/transcripts/message_manager",
"js/views/transcripts/file_uploader", "sinon", "jasmine-jquery",
"xmodule"
],
function ($, _, Utils, MessageManager, FileUploader, sinon) {
describe('Transcripts.MessageManager', function () {
var videoListEntryTemplate = readFixtures(
'transcripts/metadata-videolist-entry.underscore'
),
foundTemplate = readFixtures(
'transcripts/messages/transcripts-found.underscore'
),
handlers = {
importHandler: ['replace', 'Error: Import failed.'],
replaceHandler: ['replace', 'Error: Replacing failed.'],
chooseHandler: ['choose', 'Error: Choosing failed.', 'video_id']
},
view, fileUploader, sinonXhr;
beforeEach(function () {
var videoList, $container;
fileUploader = FileUploader.prototype;
setFixtures(
$("<div>", {id: "metadata-videolist-entry"})
.html(videoListEntryTemplate)
);
appendSetFixtures(
$("<script>",
{
id: "transcripts-found",
type: "text/template"
}
).text(foundTemplate)
);
videoList = jasmine.createSpyObj(
'MetadataView.VideoList',
['getVideoObjectsList']
);
$container = $('#metadata-videolist-entry');
spyOn(fileUploader, 'initialize');
spyOn(console, 'error');
spyOn(Utils.Storage, 'set');
view = new MessageManager({
el: $container,
parent: videoList,
component_id: 'component_id'
});
});
it('Initialize', function () {
expect(fileUploader.initialize).toHaveBeenCalledWith({
el: view.$el,
messenger: view,
component_id: view.component_id,
videoListObject: view.options.parent
});
});
describe('Render', function () {
beforeEach(function () {
spyOn(_,'template').andCallThrough();
spyOn(fileUploader, 'render');
});
it('Template doesn\'t exist', function () {
view.render('incorrect_template_name');
expect(console.error).toHaveBeenCalled();
expect(_.template).not.toHaveBeenCalled();
expect(view.$el.find('.transcripts-status'))
.toHaveClass('is-invisible');
expect(fileUploader.render).not.toHaveBeenCalled();
});
it('All works okay if correct data is passed', function () {
view.render('found');
expect(console.error).not.toHaveBeenCalled();
expect(_.template).toHaveBeenCalled();
expect(view.$el).not.toHaveClass('is-invisible');
expect(fileUploader.render).toHaveBeenCalled();
});
});
describe('showError', function () {
var errorMessage ='error',
$error, $buttons;
beforeEach(function () {
view.render('found');
spyOn(view, 'hideError');
spyOn($.fn, 'html').andCallThrough();
$error = view.$el.find('.transcripts-error-message');
$buttons = view.$el.find('.wrapper-transcripts-buttons');
});
it('Error message is not passed', function () {
view.showError(null);
expect(view.hideError).not.toHaveBeenCalled();
expect($error.html).not.toHaveBeenCalled();
expect($error).toHaveClass('is-invisible');
expect($buttons).not.toHaveClass('is-invisible');
});
it('Show message and buttons', function () {
view.showError(errorMessage);
expect(view.hideError).toHaveBeenCalled();
expect($error.html).toHaveBeenCalled();
expect($error).not.toHaveClass('is-invisible');
expect($buttons).not.toHaveClass('is-invisible');
});
it('Show message and hide buttons', function () {
view.showError(errorMessage, true);
expect(view.hideError).toHaveBeenCalled();
expect($error.html).toHaveBeenCalled();
expect($error).not.toHaveClass('is-invisible');
expect($buttons).toHaveClass('is-invisible');
});
});
it('hideError', function () {
view.render('found');
var $error = view.$el.find('.transcripts-error-message'),
$buttons = view.$el.find('.wrapper-transcripts-buttons');
expect($error).toHaveClass('is-invisible');
expect($buttons).not.toHaveClass('is-invisible');
});
$.each(handlers, function(key, value) {
it(key, function () {
var eventObj = jasmine.createSpyObj('event', ['preventDefault']);
spyOn($.fn, 'data').andReturn('video_id');
spyOn(view, 'processCommand');
view[key](eventObj);
expect(view.processCommand.mostRecentCall.args).toEqual(value);
});
});
describe('processCommand', function () {
var action = 'replace',
errorMessage = 'errorMessage',
videoList = void(0),
extraParamas = 'video_id';
beforeEach(function () {
view.render('found');
spyOn(Utils, 'command').andCallThrough();
spyOn(view, 'render');
spyOn(view, 'showError');
sinonXhr = sinon.fakeServer.create();
sinonXhr.autoRespond = true;
});
afterEach(function () {
sinonXhr.restore();
});
var assertCommand = function (config, expectFunc) {
var flag = false,
defaults = {
action: 'replace',
errorMessage: 'errorMessage',
extraParamas: void(0)
};
args = $.extend({}, defaults, config);
runs(function() {
view
.processCommand(
args.action,
args.errorMessage,
args.extraParamas
)
.always(function () { flag = true; });
});
waitsFor(function() {
return flag;
}, "Ajax Timeout", 750);
runs(expectFunc);
};
it('Invoke without extraParamas', function () {
sinonXhr.respondWith([
200,
{ "Content-Type": "application/json"},
JSON.stringify({
status: 'Success',
subs: 'video_id'
})
]);
assertCommand(
{ },
function() {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_id,
videoList,
void(0)
);
expect(view.showError).not.toHaveBeenCalled();
expect(view.render.mostRecentCall.args[0])
.toEqual('found');
expect(Utils.Storage.set).toHaveBeenCalled();
}
);
});
it('Invoke with extraParamas', function () {
sinonXhr.respondWith([
200,
{ "Content-Type": "application/json"},
JSON.stringify({
status: 'Success',
subs: 'video_id'
})
]);
view.processCommand(action, errorMessage, extraParamas);
assertCommand(
{ extraParamas : extraParamas },
function () {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_id,
videoList,
{
html5_id: extraParamas
}
);
expect(view.showError).not.toHaveBeenCalled();
expect(view.render.mostRecentCall.args[0])
.toEqual('found');
expect(Utils.Storage.set).toHaveBeenCalled();
}
);
});
it('Fail', function () {
sinonXhr.respondWith([400, {}, '']);
assertCommand(
{ },
function () {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_id,
videoList,
void(0)
);
expect(view.showError).toHaveBeenCalled();
expect(view.render).not.toHaveBeenCalled();
expect(Utils.Storage.set).not.toHaveBeenCalled();
}
);
});
});
});
});

View File

@@ -0,0 +1,264 @@
define(
[
"jquery", "underscore",
"js/views/transcripts/utils",
"underscore.string", "xmodule", "jasmine-jquery"
],
function ($, _, Utils, _str) {
describe('Transcripts.Utils', function () {
var videoId = 'OEoXaMPEzfM',
ytLinksList = (function (id) {
var links = [
'http://www.youtube.com/watch?v=%s&feature=feedrec_grec_index',
'http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/%s',
'http://www.youtube.com/v/%s?fs=1&amp;hl=en_US&amp;rel=0',
'http://www.youtube.com/watch?v=%s#t=0m10s',
'http://www.youtube.com/embed/%s?rel=0',
'http://www.youtube.com/watch?v=%s',
'http://youtu.be/%s'
];
return $.map(links, function (link) {
return _str.sprintf(link, id);
});
} (videoId)),
html5FileName = 'file_name',
html5LinksList = (function (videoName) {
var videoTypes = ['mp4', 'webm'],
links = [
'http://somelink.com/%s.%s?param=1&param=2#hash',
'http://somelink.com/%s.%s#hash',
'http://somelink.com/%s.%s?param=1&param=2',
'http://somelink.com/%s.%s',
'ftp://somelink.com/%s.%s',
'https://somelink.com/%s.%s',
'somelink.com/%s.%s',
'%s.%s'
],
data = {};
$.each(videoTypes, function (index, type) {
data[type] = $.map(links, function (link) {
return _str.sprintf(link, videoName, type);
});
});
return data;
} (html5FileName));
describe('Method: getField', function (){
var collection,
testFieldName = 'test_field';
beforeEach(function() {
collection = jasmine.createSpyObj(
'Collection',
[
'findWhere'
]
);
});
it('All works okay if all arguments are passed', function () {
Utils.getField(collection, testFieldName);
expect(collection.findWhere).toHaveBeenCalledWith({
field_name: testFieldName
});
});
var wrongArgumentLists = [
{
argName: 'collection',
list: [undefined, testFieldName]
},
{
argName: 'field name',
list: [collection, undefined]
},
{
argName: 'both',
list: [undefined, undefined]
}
];
$.each(wrongArgumentLists, function (index, element) {
it(element.argName + ' argument(s) is/are absent', function () {
var result = Utils.getField.apply(this, element.list);
expect(result).toBeUndefined();
});
});
});
describe('Method: parseYoutubeLink', function () {
describe('Supported urls', function () {
$.each(ytLinksList, function (index, link) {
it(link, function () {
var result = Utils.parseYoutubeLink(link);
expect(result).toBe(videoId);
});
});
});
describe('Wrong arguments ', function () {
beforeEach(function(){
spyOn(console, 'log');
});
it('no arguments', function () {
var result = Utils.parseYoutubeLink();
expect(result).toBeUndefined();
});
it('wrong data type', function () {
var result = Utils.parseYoutubeLink(1);
expect(result).toBeUndefined();
});
it('videoId is wrong', function () {
var videoId = 'wrong_id',
link = 'http://youtu.be/' + videoId,
result = Utils.parseYoutubeLink(link);
expect(result).toBeUndefined();
});
var wrongUrls = [
'http://youtu.bee/' + videoId,
'http://youtu.be/',
'example.com',
'http://google.com/somevideo.mp4'
];
$.each(wrongUrls, function (index, link) {
it(link, function () {
var result = Utils.parseYoutubeLink(link);
expect(result).toBeUndefined();
});
});
});
});
describe('Method: parseHTML5Link', function () {
describe('Supported urls', function () {
$.each(html5LinksList, function (format, linksList) {
$.each(linksList, function (index, link) {
it(link, function () {
var result = Utils.parseHTML5Link(link);
expect(result).toEqual({
video: html5FileName,
type: format
});
});
});
});
});
describe('Wrong arguments ', function () {
beforeEach(function(){
spyOn(console, 'log');
});
it('no arguments', function () {
var result = Utils.parseHTML5Link();
expect(result).toBeUndefined();
});
it('wrong data type', function () {
var result = Utils.parseHTML5Link(1);
expect(result).toBeUndefined();
});
var html5WrongUrls = [
'http://youtu.bee/' + videoId,
'http://youtu.be/',
'example.com',
'http://google.com/somevideo.mp1',
'http://google.com/somevideomp4',
'http://google.com/somevideo_mp4',
'http://google.com/somevideo:mp4',
'http://google.com/somevideo',
'http://google.com/somevideo.webm_'
];
$.each(html5WrongUrls, function (index, link) {
it(link, function () {
var result = Utils.parseHTML5Link(link);
expect(result).toBeUndefined();
});
});
});
});
it('Method: getYoutubeLink', function () {
var videoId = 'video_id',
result = Utils.getYoutubeLink(videoId),
expectedResult = 'http://youtu.be/' + videoId;
expect(result).toBe(expectedResult);
});
describe('Method: parseLink', function () {
var resultDataDict = {
'html5': {
link: html5LinksList['mp4'][0],
resp: {
mode: 'html5',
video: html5FileName,
type: 'mp4'
}
},
'youtube': {
link: ytLinksList[0],
resp: {
mode: 'youtube',
video: videoId,
type: 'youtube'
}
},
'incorrect': {
link: 'http://example.com',
resp: {
mode: 'incorrect'
}
}
};
$.each(resultDataDict, function (mode, data) {
it(mode, function () {
var result = Utils.parseLink(data.link);
expect(result).toEqual(data.resp);
});
});
describe('Wrong arguments ', function () {
it('no arguments', function () {
var result = Utils.parseLink();
expect(result).toBeUndefined();
});
it('wrong data type', function () {
var result = Utils.parseLink(1);
expect(result).toBeUndefined();
});
});
});
});
});

View File

@@ -0,0 +1,554 @@
define(
[
"jquery", "underscore",
"js/views/transcripts/utils", "js/views/transcripts/metadata_videolist",
"js/views/transcripts/message_manager",
"js/views/metadata", "js/models/metadata", "js/views/abstract_editor",
"sinon", "xmodule", "jasmine-jquery"
],
function ($, _, Utils, VideoList, MessageManager, MetadataView, MetadataModel, AbstractEditor, sinon) {
describe('CMS.Views.Metadata.VideoList', function () {
var videoListEntryTemplate = readFixtures(
'transcripts/metadata-videolist-entry.underscore'
),
correctMessanger = MessageManager,
messenger = correctMessanger.prototype,
abstractEditor = AbstractEditor.prototype,
component_id = 'component_id',
videoList = [
{
mode: "youtube",
type: "youtube",
video: "12345678901"
},
{
mode: "html5",
type: "mp4",
video: "video"
},
{
mode: "html5",
type: "webm",
video: "video"
}
],
modelStub = {
default_value: ['a thing', 'another thing'],
display_name: 'Video URL',
explicitly_set: true,
field_name: 'video_url',
help: 'A list of things.',
options: [],
type: MetadataModel.VIDEO_LIST_TYPE,
value: [
'http://youtu.be/12345678901',
'video.mp4',
'video.webm'
]
},
response = JSON.stringify({
command: 'found',
status: 'Success',
subs: 'video_id'
}),
view, sinonXhr;
beforeEach(function () {
sinonXhr = sinon.fakeServer.create();
sinonXhr.respondWith([
200,
{ "Content-Type": "application/json"},
response
]);
sinonXhr.autoRespond = true;
var tpl = sandbox({
'class': 'component',
'data-id': component_id
}),
model = new MetadataModel(modelStub),
videoList, $el;
setFixtures(tpl);
appendSetFixtures(
$("<script>",
{
id: "metadata-videolist-entry",
type: "text/template"
}
).text(videoListEntryTemplate)
);
spyOn(messenger, 'initialize');
spyOn(messenger, 'render').andReturn(messenger);
spyOn(messenger, 'showError');
spyOn(messenger, 'hideError');
spyOn(Utils, 'command').andCallThrough();
spyOn(abstractEditor, 'initialize').andCallThrough();
spyOn(abstractEditor, 'render').andCallThrough();
MessageManager = function () {
messenger.initialize();
return messenger;
};
$el = $('.component');
spyOn(console, 'error');
view = new VideoList({
el: $el,
model: model
});
this.addMatchers({
assertValueInView: function(expected) {
var actualValue = this.actual.getValueFromEditor();
return this.env.equals_(actualValue, expected);
},
assertCanUpdateView: function (expected) {
var actual = this.actual,
actualValue;
actual.setValueInEditor(expected);
actualValue = actual.getValueFromEditor();
return this.env.equals_(actualValue, expected);
},
assertIsCorrectVideoList: function (expected) {
var actualValue = this.actual.getVideoObjectsList();
return this.env.equals_(actualValue, expected);
}
});
});
afterEach(function () {
MessageManager = correctMessanger;
sinonXhr.restore();
});
var waitsForResponse = function (expectFunc, prep) {
var flag = false;
if (prep) {
runs(prep);
}
waitsFor(function() {
var req = sinonXhr.requests,
len = req.length;
if (len && req[0].readyState === 4) {
flag = true;
}
return flag;
}, "Ajax Timeout", 750);
runs(expectFunc);
};
it('Initialize', function () {
expect(abstractEditor.initialize).toHaveBeenCalled();
expect(messenger.initialize).toHaveBeenCalled();
expect(view.component_id).toBe(component_id);
expect(view.$el).toHandle('input');
});
describe('Render', function () {
var assertToHaveBeenRendered = function (videoList) {
expect(abstractEditor.render).toHaveBeenCalled();
expect(Utils.command).toHaveBeenCalledWith(
'check',
component_id,
videoList
);
expect(messenger.render).toHaveBeenCalled();
},
resetSpies = function() {
abstractEditor.render.reset();
Utils.command.reset();
messenger.render.reset();
sinonXhr.requests.length = 0;
};
it('is rendered in correct way', function () {
waitsForResponse(function () {
assertToHaveBeenRendered(videoList);
});
});
it('is rendered with opened extra videos bar', function () {
var videoListLength = [
{
mode: "youtube",
type: "youtube",
video: "12345678901"
},
{
mode: "html5",
type: "mp4",
video: "video"
}
],
videoListHtml5mode = [
{
mode: "html5",
type: "mp4",
video: "video"
}
];
spyOn(view, 'getVideoObjectsList').andReturn(videoListLength);
spyOn(view, 'openExtraVideosBar');
waitsForResponse(
function () {
assertToHaveBeenRendered(videoListLength);
view.getVideoObjectsList.andReturn(videoListLength);
expect(view.openExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies();
view.render();
}
);
waitsForResponse(
function () {
assertToHaveBeenRendered(videoListHtml5mode);
expect(view.openExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies();
view.openExtraVideosBar.reset();
view.getVideoObjectsList.andReturn(videoListHtml5mode);
view.render();
}
);
});
it('is rendered without opened extra videos bar', function () {
var videoList = [
{
mode: "youtube",
type: "youtube",
video: "12345678901"
}
];
spyOn(view, 'getVideoObjectsList').andReturn(videoList);
spyOn(view, 'closeExtraVideosBar');
waitsForResponse(
function () {
assertToHaveBeenRendered(videoList);
expect(view.closeExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies();
view.render();
}
);
});
});
describe('isUniqVideoTypes', function () {
it('Unique data - return true', function () {
var data = videoList,
result = view.isUniqVideoTypes(data);
expect(result).toBe(true);
});
it('Not Unique data - return false', function () {
var data = [
{
mode: "html5",
type: "mp4",
video: "video"
},
{
mode: "html5",
type: "mp4",
video: "video"
},
{
mode: "youtube",
type: "youtube",
video: "12345678901"
}
],
result = view.isUniqVideoTypes(data);
expect(result).toBe(false);
});
});
describe('checkIsUniqVideoTypes', function () {
it('Error is shown', function () {
var data = [
{
mode: "html5",
type: "mp4",
video: "video"
},
{
mode: "html5",
type: "mp4",
video: "video"
},
{
mode: "youtube",
type: "youtube",
video: "12345678901"
}
],
result = view.checkIsUniqVideoTypes(data);
expect(messenger.showError).toHaveBeenCalled();
expect(result).toBe(false);
});
it('All works okay if arguments are not passed', function () {
spyOn(view, 'getVideoObjectsList').andReturn(videoList);
var result = view.checkIsUniqVideoTypes();
expect(view.getVideoObjectsList).toHaveBeenCalled();
expect(messenger.showError).not.toHaveBeenCalled();
expect(result).toBe(true);
});
});
describe('checkValidity', function () {
beforeEach(function () {
spyOn(view, 'checkIsUniqVideoTypes').andReturn(true);
});
it('Error message are shown', function () {
var data = { mode: 'incorrect' },
result = view.checkValidity(data, true);
expect(messenger.showError).toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(false);
});
it('Error message are shown when flag is not passed', function () {
var data = { mode: 'incorrect' },
result = view.checkValidity(data);
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
});
it('All works okay if correct data is passed', function () {
var data = videoList,
result = view.checkValidity(data);
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
});
});
it('openExtraVideosBar', function () {
view.$extraVideosBar.removeClass('is-visible');
view.openExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
});
it('closeExtraVideosBar', function () {
view.$extraVideosBar.addClass('is-visible');
view.closeExtraVideosBar();
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
});
it('toggleExtraVideosBar', function () {
view.$extraVideosBar.addClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
});
it('getValueFromEditor', function () {
expect(view).assertValueInView(modelStub.value);
});
it('setValueInEditor', function () {
expect(view).assertCanUpdateView(['abc.mp4']);
});
it('getVideoObjectsList', function () {
var value = [
{
mode: 'youtube',
type: 'youtube',
video: '12345678901'
},
{
mode: 'html5',
type: 'mp4',
video: 'video'
}
];
view.setValueInEditor([
'http://youtu.be/12345678901',
'video.mp4',
'video'
]);
expect(view).assertIsCorrectVideoList(value);
});
describe('getPlaceholders', function () {
var defaultPlaceholders;
beforeEach(function () {
defaultPlaceholders = view.placeholders;
});
it('All works okay if empty values are passed', function () {
var result = view.getPlaceholders([]),
expectedResult = _.values(defaultPlaceholders).reverse();
expect(result).toEqual(expectedResult);
});
it('On filling less than 3 fields, remaining fields should have ' +
'placeholders for video types that were not filled yet',
function () {
var dataDict = {
youtube: {
value: [modelStub.value[0]],
expectedResult: [
defaultPlaceholders.youtube,
defaultPlaceholders.mp4,
defaultPlaceholders.webm
]
},
mp4: {
value: [modelStub.value[1]],
expectedResult: [
defaultPlaceholders.mp4,
defaultPlaceholders.youtube,
defaultPlaceholders.webm
]
},
webm: {
value: [modelStub.value[2]],
expectedResult: [
defaultPlaceholders.webm,
defaultPlaceholders.youtube,
defaultPlaceholders.mp4
]
}
};
$.each(dataDict, function(index, val) {
var result = view.getPlaceholders(val.value);
expect(result).toEqual(val.expectedResult);
});
}
);
});
describe('inputHandler', function () {
var eventObject;
var resetSpies = function () {
messenger.hideError.reset();
view.updateModel.reset();
view.closeExtraVideosBar.reset();
};
beforeEach(function () {
eventObject = jQuery.Event('input');
spyOn(view, 'updateModel');
spyOn(view, 'closeExtraVideosBar');
spyOn(view, 'checkValidity');
spyOn($.fn, 'hasClass');
spyOn($.fn, 'addClass');
spyOn($.fn, 'removeClass');
spyOn($.fn, 'prop').andCallThrough();
spyOn(_, 'isEqual');
resetSpies();
});
it('Field has invalid value - nothing should happen',
function () {
$.fn.hasClass.andReturn(false);
view.checkValidity.andReturn(false);
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith('disabled', true);
expect($.fn.addClass).toHaveBeenCalledWith('is-disabled');
}
);
it('Main field has invalid value - extra Videos Bar should be closed',
function () {
$.fn.hasClass.andReturn(true);
view.checkValidity.andReturn(false);
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith('disabled', true);
expect($.fn.addClass).toHaveBeenCalledWith('is-disabled');
}
);
it('Model is updated if value is valid',
function () {
view.checkValidity.andReturn(true);
_.isEqual.andReturn(false);
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith('disabled', false);
expect($.fn.removeClass).toHaveBeenCalledWith('is-disabled');
}
);
it('Corner case: Error is hided',
function () {
view.checkValidity.andReturn(true);
_.isEqual.andReturn(true);
view.inputHandler(eventObject);
expect(messenger.hideError).toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith('disabled', false);
expect($.fn.removeClass).toHaveBeenCalledWith('is-disabled');
}
);
});
});
});