Add frontend video image validations - EDUCATOR-447

This commit is contained in:
Mushtaq Ali
2017-05-19 16:29:50 +05:00
parent e8fee2e09a
commit cf6200cbb3
14 changed files with 510 additions and 106 deletions

View File

@@ -25,7 +25,8 @@ define(
);
var view = new PreviousVideoUploadListView({
collection: collection,
videoHandlerUrl: videoHandlerUrl
videoHandlerUrl: videoHandlerUrl,
videoImageSettings: {}
});
return view.render().$el;
},

View File

@@ -14,7 +14,8 @@ define(
},
view = new PreviousVideoUploadView({
model: new Backbone.Model($.extend({}, defaultData, modelData)),
videoHandlerUrl: '/videos/course-v1:org.0+course_0+Run_0'
videoHandlerUrl: '/videos/course-v1:org.0+course_0+Run_0',
videoImageSettings: {}
});
return view.render().$el;
};

View File

@@ -1,36 +1,77 @@
define(
['jquery', 'underscore', 'backbone', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'js/views/video_thumbnail', 'common/js/spec_helpers/template_helpers'],
function($, _, Backbone, AjaxHelpers, VideoThumbnailView, TemplateHelpers) {
'js/views/video_thumbnail', 'js/views/previous_video_upload_list', 'common/js/spec_helpers/template_helpers'],
function($, _, Backbone, AjaxHelpers, VideoThumbnailView, PreviousVideoUploadListView, TemplateHelpers) {
'use strict';
describe('VideoThumbnailView', function() {
var IMAGE_UPLOAD_URL = '/videos/upload/image',
UPLOADED_IMAGE_URL = 'images/upload_success.jpg',
VIDEO_IMAGE_MAX_BYTES = 2 * 1024 * 1024,
VIDEO_IMAGE_MIN_BYTES = 2 * 1024,
VIDEO_IMAGE_MAX_WIDTH = 1280,
VIDEO_IMAGE_MAX_HEIGHT = 720,
VIDEO_IMAGE_SUPPORTED_FILE_FORMATS = {
'.bmp': 'image/bmp',
'.bmp2': 'image/x-ms-bmp', // PIL gives x-ms-bmp format
'.gif': 'image/gif',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png'
},
videoListView,
videoThumbnailView,
$videoListEl,
$videoThumbnailEl,
createVideoListView,
createFakeImageFile,
verifyStateInfo,
render = function(modelData) {
var defaultData = {
verifyStateInfo;
/**
* Creates a list of video records.
*
* @param {Object} modelData Model data for video records.
* @param {Integer} numVideos Number of video elements to create.
* @param {Integer} videoViewIndex Index of video on which videoThumbnailView would be based.
*/
createVideoListView = function(modelData, numVideos, videoViewIndex) {
var modelData = modelData || {}, // eslint-disable-line no-redeclare
numVideos = numVideos || 1, // eslint-disable-line no-redeclare
videoViewIndex = videoViewIndex || 0, // eslint-disable-line no-redeclare,
defaultData = {
client_video_id: 'foo.mp4',
duration: 42,
created: '2014-11-25T23:13:05',
edx_video_id: 'dummy_id',
status: 'uploading',
thumbnail_url: null
};
videoThumbnailView = new VideoThumbnailView({
model: new Backbone.Model($.extend({}, defaultData, modelData)),
imageUploadURL: IMAGE_UPLOAD_URL
});
return videoThumbnailView.render().$el;
};
status: 'uploading'
},
collection = new Backbone.Collection(_.map(_.range(numVideos), function(num, index) {
return new Backbone.Model(
_.extend({}, defaultData, {edx_video_id: 'dummy_id_' + index}, modelData)
);
}));
videoListView = new PreviousVideoUploadListView({
collection: collection,
videoHandlerUrl: '/videos/course-v1:org.0+course_0+Run_0',
videoImageUploadURL: IMAGE_UPLOAD_URL,
videoImageSettings: {
max_size: VIDEO_IMAGE_MAX_BYTES,
min_size: VIDEO_IMAGE_MIN_BYTES,
max_width: VIDEO_IMAGE_MAX_WIDTH,
max_height: VIDEO_IMAGE_MAX_HEIGHT,
supported_file_formats: VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
}
});
$videoListEl = videoListView.render().$el;
videoThumbnailView = videoListView.itemViews[videoViewIndex].videoThumbnailView;
$videoThumbnailEl = videoThumbnailView.render().$el;
return videoListView;
};
createFakeImageFile = function(size) {
var fileFakeData = 'i63ljc6giwoskyb9x5sw0169bdcmcxr3cdz8boqv0lik971972cmd6yknvcxr5sw0nvc169bdcmcxsdf';
return new Blob(
[fileFakeData.substr(0, size)],
{type: 'image/jpg'}
);
createFakeImageFile = function(size, type) {
var size = size || VIDEO_IMAGE_MIN_BYTES, // eslint-disable-line no-redeclare
type = type || 'image/jpeg'; // eslint-disable-line no-redeclare
return new Blob([Array(size + 1).join('i')], {type: type});
};
verifyStateInfo = function($thumbnail, state, onHover, additionalSRText) {
@@ -50,9 +91,12 @@ define(
).toEqual(additionalSRText);
}
expect($thumbnail.find('.action-icon').html().trim()).toEqual(
videoThumbnailView.actionsInfo[state].icon
);
if (state !== 'error') {
expect($thumbnail.find('.action-icon').html().trim()).toEqual(
videoThumbnailView.actionsInfo[state].icon
);
}
expect($thumbnail.find('.action-text').html().trim()).toEqual(
videoThumbnailView.actionsInfo[state].text
);
@@ -68,22 +112,22 @@ define(
beforeEach(function() {
setFixtures('<div id="page-prompt"></div><div id="page-notification"></div>');
TemplateHelpers.installTemplate('video-thumbnail');
TemplateHelpers.installTemplate('previous-video-upload-list');
createVideoListView();
});
it('renders as expected', function() {
var $el = render({});
expect($el.find('.thumbnail-wrapper')).toExist();
expect($el.find('.upload-image-input')).toExist();
expect($videoThumbnailEl.find('.thumbnail-wrapper')).toExist();
expect($videoThumbnailEl.find('.upload-image-input')).toExist();
});
it('does not show duration if not available', function() {
var $el = render({duration: 0});
expect($el.find('.thumbnail-wrapper .video-duration')).not.toExist();
createVideoListView({duration: 0});
expect($videoThumbnailEl.find('.thumbnail-wrapper .video-duration')).not.toExist();
});
it('shows the duration if available', function() {
var $el = render({}),
$duration = $el.find('.thumbnail-wrapper .video-duration');
var $duration = $videoThumbnailEl.find('.thumbnail-wrapper .video-duration');
expect($duration).toExist();
expect($duration.find('.duration-text-machine').text().trim()).toEqual('0:42');
expect($duration.find('.duration-text-human').text().trim()).toEqual('Video duration is 42 seconds');
@@ -114,8 +158,8 @@ define(
});
it('can upload image', function() {
var $el = render({}),
$thumbnail = $el.find('.thumbnail-wrapper'),
var videoViewIndex = 0,
$thumbnail = $videoThumbnailEl.find('.thumbnail-wrapper'),
requests = AjaxHelpers.requests(this),
additionalSRText = videoThumbnailView.getSRText();
@@ -125,12 +169,17 @@ define(
verifyStateInfo($thumbnail, 'requirements', true, additionalSRText);
// Add image to upload queue and send POST request to upload image
$el.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile(60)]});
$videoThumbnailEl.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile()]});
verifyStateInfo($thumbnail, 'progress');
// Verify if POST request received for image upload
AjaxHelpers.expectRequest(requests, 'POST', IMAGE_UPLOAD_URL + '/dummy_id', new FormData());
AjaxHelpers.expectRequest(
requests,
'POST',
IMAGE_UPLOAD_URL + '/dummy_id_' + videoViewIndex,
new FormData()
);
// Send successful upload response
AjaxHelpers.respondWithJson(requests, {image_url: UPLOADED_IMAGE_URL});
@@ -142,45 +191,136 @@ define(
});
it('shows error state correctly', function() {
var $el = render({}),
$thumbnail = $el.find('.thumbnail-wrapper'),
var $thumbnail = $videoThumbnailEl.find('.thumbnail-wrapper'),
requests = AjaxHelpers.requests(this);
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$el.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile(60)]});
$videoThumbnailEl.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile()]});
AjaxHelpers.respondWithError(requests, 400);
verifyStateInfo($thumbnail, 'error');
});
it('should show error notification in case of server error', function() {
var $el = render({}),
requests = AjaxHelpers.requests(this);
it('calls readMessage with correct message', function() {
var errorMessage = 'This image file type is not supported. Supported file types are ' +
videoThumbnailView.getVideoImageSupportedFileFormats().humanize + '.',
successData = {
files: [createFakeImageFile()],
submit: function() {}
},
failureData = {
jqXHR: {
responseText: JSON.stringify({
error: errorMessage
})
}
};
spyOn(videoThumbnailView, 'readMessages');
videoThumbnailView.imageSelected({}, successData);
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(['Video image upload started']);
videoThumbnailView.imageUploadSucceeded({}, {result: {image_url: UPLOADED_IMAGE_URL}});
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(['Video image upload completed']);
videoThumbnailView.imageUploadFailed({}, failureData);
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(
['Could not upload the video image file', errorMessage]
);
});
it('should show error message in case of server error', function() {
var requests = AjaxHelpers.requests(this);
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$el.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile(60)]});
$videoThumbnailEl.find('.upload-image-input').fileupload('add', {files: [createFakeImageFile()]});
AjaxHelpers.respondWithError(requests);
expect($('#notification-error-title').text().trim()).toEqual(
"Studio's having trouble saving your work"
// Verify error message is present
expect($videoListEl.find('.thumbnail-error-wrapper')).toExist();
});
it('should show error message when file is smaller than minimum size', function() {
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MIN_BYTES - 10)]});
// Verify error message
expect($videoListEl.find('.thumbnail-error-wrapper').find('.action-text').html()
.trim()).toEqual(
'The selected image must be larger than ' +
videoThumbnailView.getVideoImageMinSize().humanize + '.'
);
});
it('calls readMessage with correct message', function() {
spyOn(videoThumbnailView, 'readMessages');
it('should show error message when file is larger than maximum size', function() {
videoThumbnailView.chooseFile();
videoThumbnailView.imageSelected({}, {submit: function() {}});
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(['Video image upload started']);
videoThumbnailView.imageUploadSucceeded({}, {result: {image_url: UPLOADED_IMAGE_URL}});
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(['Video image upload completed']);
videoThumbnailView.imageUploadFailed();
expect(videoThumbnailView.readMessages).toHaveBeenCalledWith(['Video image upload failed']);
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MAX_BYTES + 10)]});
// Verify error message
expect($videoListEl.find('.thumbnail-error-wrapper').find('.action-text').html()
.trim()).toEqual(
'The selected image must be smaller than ' +
videoThumbnailView.getVideoImageMaxSize().humanize + '.'
);
});
it('should not show error message when file size is equals to minimum file size', function() {
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MIN_BYTES)]});
// Verify error not present.
expect($videoListEl.find('.thumbnail-error-wrapper')).not.toExist();
});
it('should not show error message when file size is equals to maximum file size', function() {
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MAX_BYTES)]});
// Verify error not present.
expect($videoListEl.find('.thumbnail-error-wrapper')).not.toExist();
});
it('should show error message when file has unsupported content type', function() {
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MIN_BYTES, 'mov/mp4')]});
// Verify error message
expect($videoListEl.find('.thumbnail-error-wrapper').find('.action-text').html()
.trim()).toEqual(
'This image file type is not supported. Supported file types are ' +
videoThumbnailView.getVideoImageSupportedFileFormats().humanize + '.'
);
});
it('should not show error message when file has supported content type', function() {
videoThumbnailView.chooseFile();
// Add image to upload queue and send POST request to upload image
$videoThumbnailEl.find('.upload-image-input')
.fileupload('add', {files: [createFakeImageFile(VIDEO_IMAGE_MIN_BYTES)]});
// Verify error message is not present
expect($videoListEl.find('.thumbnail-error-wrapper')).not.toExist();
});
});
}