testing - Backbone - Test method in view that uses ReadFile -


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