i have written backbone view takes file object or blob option in instantiation , checks file exif data, corrects orientation , resizes image if necessary depending on options passed in.
within view there function mainfn takes file object , calls other subsequent functions.
my issue how test mainfn uses readfile , image constructor?
for test set-up using mocah, chai, sinon , phantomjs.
in sample code have removed other functions not add unnecessary clutter. if wish see whole view visit 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 width , height of source file , calls transform function mainfn: function (file) { var fr = new filereader(); var = this; fr.onloadend = function () { var _img = new image(); // image width , height can determined once 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 = []; (var offset = 0; offset < bytecharacters.length; offset += slicesize) { var slice = bytecharacters.slice(offset, offset + slicesize); var bytenumbers = new array(slice.length); (var = 0; < 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 , 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); }); });
you either mock filereader / image on window, e.g.
// beforeeach var _filereader = window.filereader; window.filereader = sinon.stub().return('whatever'); // aftereach window.filereader = _filereader; or reference constructor on instance, e.g.
// view.js var view = backbone.view.extend({ filereader: window.filereader, mainfn: function() { var filereader = new this.filereader(); } }); // view.spec.js sinon.stub(this.view, 'filereader').return('whatever'); personally i'd prefer latter there's no risk of breaking global reference if, example, forget reassign original value.
Comments
Post a Comment