I have written a backbone view which takes a file object or blob as an option in instantiation and then checks that file for EXIF data, corrects orientation and resizes the image if necessary depending on the options passed in.
Within the view there is a function mainFn which takes the file object and calls all other subsequent functions.
My issue is how to I test mainFn that uses ReadFile and an image constructor?
For my test set-up I am using mocah, chai, sinon and phantomjs.
In my sample code I have removed all other functions as to not add unnecessary clutter. If you wish to see the whole view visit its github repository.
var imageUpLoad = Backbone.View.extend({
template: _.template(document.getElementById("file-uploader-template").innerHTML),
// global variables passed in through options - required
_file: null, // our target file
cb: null,
maxFileSize: null, // megabytes
maxHeight: null, // pixels - resize target
maxWidth: null, // pixels - resize target
minWidth: null, // pixels
maxAllowedHeight: null, //pixels
maxAllowedWidth: null, // pixels
// globals determined through function
sourceWidth: null,
sourceHeight: null,
initialize: function (options) {
this._file = options.file;
this.cb = options.cb;
this.maxHeight = options.maxHeight;
this.maxWidth = options.maxWidth;
this.maxFileSize = options.maxFileSize;
this.minWidth = options.minWidth;
this.maxAllowedHeight = options.maxAllowedHeight;
this.maxAllowedWidth = options.maxAllowedWidth;
},
render: function () {
this.setElement(this.template());
this.mainFn(this._file);
return this;
},
// returns the width and height of the source file and calls the transform function
mainFn: function (file) {
var fr = new FileReader();
var that = this;
fr.onloadend = function () {
var _img = new Image();
// image width and height can only be determined once the image has loaded
_img.onload = function () {
that.sourceWidth = _img.width;
that.sourceHeight = _img.height;
that.transformImg(file);
};
_img.src = fr.result;
};
fr.readAsDataURL(file);
}
});
My test set-up
describe("image-upload view", function () {
before(function () {
// create test fixture
this.$fixture = $('<div id="image-view-fixture"></div><div>');
});
beforeEach(function () {
// fake image
this.b64DataJPG = ''/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAA' +
'ABABIBAwABAAAABgASAAAAAAD/2wBDAAEBAQEBAQEBAQEBAQEB' +
'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ' +
'EBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEB' +
'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ' +
'EBAQEBAQH/wAARCAABAAIDASIAAhEBAxEB/8QAHwAAAQUBAQEB' +
'AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBA' +
'QAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk' +
'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1' +
'hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKj' +
'pKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+' +
'Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAA' +
'AAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAx' +
'EEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl' +
'8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2' +
'hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmq' +
'srO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8v' +
'P09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigD/2Q==';
var b64toBlob = function (b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var input = b64Data.replace(/\s/g, '');
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
try{
var blob = new Blob( byteArrays, {type : contentType});
}
catch(e){
// TypeError old chrome and FF
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if(e.name == 'TypeError' && window.BlobBuilder){
var bb = new BlobBuilder();
bb.append(byteArrays);
blob = bb.getBlob(contentType);
}
else if(e.name == "InvalidStateError"){
// InvalidStateError (tested on FF13 WinXP)
blob = new Blob(byteArrays, {type : contentType});
}
else{
// We're screwed, blob constructor unsupported entirely
}
}
return blob;
};
this.blobJPG = b64toBlob(this.b64DataJPG, "image/jpg");
/* **************** */
this.$fixture.empty().appendTo($("#fixtures"));
this.view = new imageUpLoad({
file: this.blobJPG,
cb: function (url) {console.log(url);},
maxFileSize: 500000,
minWidth: 200,
maxHeight: 900,
maxWidth: 1000,
maxAllowedHeight: 4300,
maxAllowedWidth: 1000
});
this.renderSpy = sinon.spy(this.view, "render");
this.readFileDataStub = sinon.stub(this.view, 'readFileData');
this.resizeImageStub = sinon.stub(this.view, 'resizeImage');
this.returnDataUrlStub = sinon.stub(this.view, 'returnDataUrl');
this.mainFnSpy = sinon.spy(this.view, 'mainFn');
this.transformImgStub = sinon.stub(this.view, 'transformImg');
this.sizeConfigStub = sinon.stub(this.view, 'sizeConfig');
this.resizeConfStub = sinon.stub(this.view, 'resizeConf');
this.callbackSpy = sinon.spy();
});
afterEach(function () {
this.renderSpy.restore();
this.readFileDataStub.restore();
this.resizeImageStub.restore();
this.returnDataUrlStub.restore();
this.mainFnSpy.restore();
this.sizeConfigStub.restore();
this.resizeConfStub.restore();
this.transformImgStub.restore();
});
after(function () {
$("#fixtures").empty();
});
it("can render", function () {
var _view = this.view.render();
expect(this.renderSpy).to.have.been.called;
expect(this.view).to.equal(_view);
});
});
Aucun commentaire:
Enregistrer un commentaire