javascript - Why are these tests passing? -


i have function:

let removepresentation = function(presentationname, callback) {   let rimraf = require('rimraf');    callback();   callback();   callback();    if(!presentationname || !presentationname.trim()) {     callback();     return;   }    presentationname = presentationname.replace('.zip', '');    rimraf('./presentations/' + presentationname, function(err) {     if(err) {       console.log(err);     }     callback();   }); };  exports.removepresentation = removepresentation; 

and trying test following:

var chai = require('chai'), expect = require('chai').expect, sinonchai = require('sinon-chai'), sinon = require('sinon'), mock = require('mock-require');  chai.use(sinonchai);  describe('removepresentation', function() {    var sandbox;   var callback;   var rimrafspy;    beforeeach(function() {     sandbox = sinon.sandbox.create();     mock('../business/communications_business', {});      rimrafspy = sinon.spy();     callback = sinon.spy();      mock('rimraf', rimrafspy);   });    aftereach(function() {     sandbox.restore();   });    it('should call rimraf if presentation name valid', function(done) {     let roomstatebusiness = require('../business/roomstate_business');      roomstatebusiness.removepresentation('name.zip', callback);      expect(rimrafspy).to.have.been.calledwith('./presentations/name');     expect(callback).to.have.been.called.once;     done();   });    it('should not call rimraf if presentation name null', function(done) {     let roomstatebusiness = require('../business/roomstate_business');      roomstatebusiness.removepresentation(null, callback);      expect(rimrafspy).not.to.have.been.called;     expect(callback).to.have.been.called.once;     done();   });    it('should not call rimraf if presentation name whitespace', function(done) {     let roomstatebusiness = require('../business/roomstate_business');      roomstatebusiness.removepresentation('      ', callback);      expect(rimrafspy).not.to.have.been.called;     expect(callback).to.have.been.called.once;     done();   });    it('should not call rimraf if presentation name empty string', function(done) {     let roomstatebusiness = require('../business/roomstate_business');      roomstatebusiness.removepresentation('', callback);      expect(rimrafspy).not.to.have.been.called;     expect(callback).to.have.been.called.once;     done();   });  }); 

even though calling callback() multiple times (whilst testing only), expect(callback).to.have.been.called.once; asserting true. have checked on chai api that expects call once, although passing no matter how many times call callback(). doing wrong?

there no such assertion expect(fn).to.have.been.called.once.

as per sinon-chai docs, there only:

  • expect(fn).to.have.been.called
  • expect(fn).to.have.been.calledonce

the problem

this known problem chai , why getter-only-assertions bad thing. chai allows write piece of code looks property access (ie. assertion not end function call) assert...whatever want assert. uses property getters execute necessary code.

the problem if make typo or other mistake, expression evaluate undefined (you accessing property not exist) , no assertion code ever executed, resulting in test passing (because tests fail if exception thrown).

in case, there assertion called, , returns object. unfortunately, object not have assertion once, there no code executed , test passes.

the solution

there 2 options available you:

  • upgrade chai 4 , node.js version proxy support (not sure proxy support added, node.js 5 or 6) - chai introduced safeguard against these issues proxying property access through proxy object checks if using valid assertion
  • never use getters assertions , end assertions function call - make sure if ever make mistake test fail infamous undefined not function error

the second option highly preferred, in opinion, there can no doubt on correctness of test case. chai proxy support can still turned off on supported platforms.


Comments

Popular posts from this blog

python Tkinter Capturing keyboard events save as one single string -

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

javascript - Z-index in d3.js -