Node.js sinon stubbing a function in parallel executions causes failed tests - node.js

I have 2 test cases which test the same function just taking 2 different executions paths, so to illustrate:
MyClass.prototype.functionBeingTested = function() {
if (this.check1()) {
this.isCheck1Called = true;
} else if (this.check2()) {
this.isCheck1Called = false;
} else {
...
}
};
My 2 test cases are as follow:
it('should take check1() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check1Stub sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check2Stub sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
Now by default, check1() returns false so I don't stub it in the second test case, but by the time the second case is running, the check1() function stub is still active and causes the second case to enter the execution path of the first case as-well, making the second case test fail.
I understand it's a problem of test running in parallel and the first sinon stub still being used by the first test case, is there anyway I can solve this problem?

At the end of the first test, you should restore the original method (which is always a good thing, to prevent tests from being influenced by previous tests):
check1Stub.restore()
Or, alternatively, you can use a Sinon sandbox to run each test in:
describe('MyClass', function() {
beforeEach(function() {
this.sinon = sinon.sandbox.create();
});
afterEach(function() {
this.sinon.restore();
});
it('should take check1() execution path', function() {
var myClass = new MyClass({}, {}, {});
// `this.sinon` is the sandbox
var check1Stub = this.sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass = new MyClass({}, {}, {});
var check2Stub = this.sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
});
(See mocha-sinon, which does exactly the same)

Related

does mocha intelligently execute async code?

I have this code:
const mocha = require("mocha");
const assert = require("assert");
describe("saving records", function (done) {
it("Saves a record to the database", function (done) {
let mx = false;
setTimeout(() => {
mx = false; //#### note this line
}, 6000);
done();
assert(mx === true);
});
});
I am not sure why, but mocha gives a test pass in the terminal that says:
saving records
✓ Saves a record to the database
1 passing (30ms)
Question no.1 : Why is the test passing at this point
The next weird thing is: It doesn't even wait for 6 seconds seconds before the test passes. Since, I've used done parameter, Question no. 2: shouldn't it wait until the execution is done?
Have I misinterpreted some information?
const mocha = require("mocha");
const assert = require("assert");
describe("saving records", function (done) {
it("Saves a record to the database", function (done) {
let mx = false;
setTimeout(() => {
mx = false; //#### note this line
assert(mx === true);
done();
}, 6000);
});
});
In your variant test passes because assert is after done();
Working with async tests described here

How to reuse an element inside of a function in protractor page object model?

I am using protractor with Jasmine in windows 10 OS. This is my page for stack over flow login .May I know how to access txt_username inside of clearme: function().
pgstackover.js
//pgstackover.js
'use strict';
module.exports = {
txt_username: element(by.id('email')),
txt_password: element(by.id('password')),
btn_submit: element(by.id('submit-button')),
clearme: function() {
txt_username.isDisplayed();
txt_username.clear();
txt_password.clear()
} ,
go: function() {
browser.driver.ignoreSynchronization = true;
browser.waitForAngularEnabled(false);
browser.driver.manage().window().maximize();
browser.driver.get('https://stackoverflow.com/users/login'); //overrides baseURL
}
This is my spec.js file and it works until clear me function and fails with error Failed: txt_username is not defined
var toDoPage = require('../../../../pages/pgstackover.js');
describe('My first non angular class', function() {
it('should navigate to stack overflow login page', function() {
toDoPage.go();
});
it ('My function', function() {
// browser.driver.get('https://stackoverflow.com/users/login');
toDoPage.txt_username.sendKeys('6');
toDoPage.txt_password.sendKeys('winchester');
var value=toDoPage.btn_submit.getText();
expect(value).toEqual("Log in");
});
it('clear me', function() {
toDoPage.clearme();
});
})
Too make long story short your code does not know what is txt_username so you need to point it out. You are missing .this in your clearme function.
I haven't used a promise manager for ages (since it is obsolete) so here is a working example using async/await:
async clearme() {
await this.txt_username.isDisplayed();
await this.txt_username.clear();
await this.txt_password.clear();
}

Testing method signatures in Node.js

I'm relatively new to Unit-testing and TDD specificly and am about to start my first project with TDD using mocha and chai.
Am I supposed to test the existence and parameter length of the methods?
And if so, is there any better way of doing it than I currently am? It feels extremly verbose, especially when repeating this for most of my classes.
For understand I've set up some dummy test.
test/index.js
'use strict';
const assert = require('chai').assert;
const Test = require('../lib/index.js');
describe('Test', function() {
it('should be a function without parameters', function() {
assert.isFunction(Test);
assert.lengthOf(Test, 0);
});
let test;
beforeEach(function() {
test = new Test();
});
describe('static#method1', function() {
it('should have static method method1 with 1 parameter', function() {
assert.property(Test, 'method1');
assert.isFunction(Test.method1);
assert.lengthOf(Test.method1, 1);
});
it('should assert on non-string parameters', function() {
const params = [
123,
{},
[],
function() {}
];
params.forEach(function(param) {
assert.throws(function() {
Test.method1(param)
});
});
});
it('should return "some value"', function() {
assert.equal(Test.method1('param'), 'some value')
});
});
describe('method2', function() {
it('should have method method2 with 2 parameters', function() {
assert.property(test, 'method2');
assert.isFunction(test.method2);
assert.lengthOf(test.method2, 2);
});
it('should assert on non-number parameters', function() {
const params = [
'some string',
{},
[],
function() {}
];
params.forEach(function(param) {
assert.throws(function() {
test.method2(param)
});
});
});
it('should add the parameters', function() {
assert.equal(test.method2(1, 2), 3);
assert.equal(test.method2(9, -2), 7);
assert.equal(test.method2(3, -12), -9);
assert.equal(test.method2(-7, -5), -12);
})
});
});
And the tested implementation.
lib/index.js
'use strict';
const assert = require('chai').assert;
exports = module.exports = (function() {
class Test {
static method1(param0) {
assert.typeOf(param0, 'string');
return 'some value';
}
method2(param0, param1) {
assert.typeOf(param0, 'number');
assert.typeOf(param1, 'number');
return param0 + param1;
}
}
return Test;
}());
No, such detailed tests are not necessary. What is the value of them? What do they help you to achieve?
Usually when testing functions we test behavior of a function, not its implementation. Implementation can completely change without changing the observable behavior: for example, you can find more readable way to rewrite your code or a more performant algorithm.
You test the call signature of your function by the whole set of tests for it, indirectly. Every test provides an example of how to use your function, thus ensuring its call signature and return parameters.

How can I stub a Promise such that my test can be run synchronously?

I am trying to unit test a module by stubbing one of its dependencies, in this case the UserManager
A simplified version of the module is as follows:
// CodeHandler
module.exports = function(UserManager) {
return {
oAuthCallback: function(req, res) {
var incomingCode = req.query.code;
var clientKey = req.query.key;
UserManager.saveCode(clientKey, incomingCode)
.then(function(){
res.redirect('https://test.tes');
}).catch(function(err){
res.redirect('back');
}
);
}
};
};
I'm stubbing the UserManager's saveCode function which returns a Promise such that it returns a resolved Promise, but when I assert that res.redirect has been called, alas at the time of the assertion res.redirect has not yet been called.
A simplified version of the unit test is:
// test
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var res = {
redirect: function() {}
};
var expectedUrl = 'https://test.tes';
var ch;
beforeEach(function() {
sinon.stub(UserManager, 'saveCode').returns(
new RSVP.Promise(function(resolve, reject){
resolve();
})
);
sinon.stub(res, 'redirect');
ch = CodeHandler(UserManager);
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
});
How can I properly stub the promise such that the method under test behaves synchronously?
I've worked out a solution using sinon-stub-promise.
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var ch;
var promise;
var res = {
redirect: function() {}
};
beforeEach(function() {
promise = sinon.stub(UserManager, 'saveCode').returnsPromise();
ch = CodeHandler(UserManager);
sinon.stub(res, 'redirect');
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
describe('can save code', function() {
var expectedUrl = 'https://test.tes';
beforeEach(function() {
promise.resolves();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
});
});
describe('can not save code', function() {
var expectedUrl = 'back';
beforeEach(function() {
promise.rejects();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
})
});
This works perfectly.
Well, the easiest thing would be not to stub it to run synchronously at all since that might change execution order and use Mocha's built in promises support (or jasmine-as-promised if using jasmine).
The reason is there can be cases like:
somePromise.then(function(){
doB();
});
doA();
If you cause promises to resolve synchronously the execution order - and thus output of the program changes, making the test worthless.
On the contrary, you can use the test syntax:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () => {
return methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
});
});
You can use the even lighter arrow syntax for single lines which makes the test even less verbose:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () =>
methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
);
});
In RSVP, you can't set the scheduler as far as I know so it's quite impossible to test things synchronously anyway, other libraries like bluebird let you do it at your own risk, but even in libraries that let you do it it's probably not the best idea.

How to unit test console output with mocha on nodejs?

Take into account the following example Javascript code below:
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
};
How should I unit test that on nodejs using mocha (and possibly sinonjs), noticing that this is a private function called inside a module? I need to pass in the argument and check if the function is logging the right thing to the console.
Can I do the same with console.warn and console.error?
I prefer mocha-sinon over "plain" sinon because it integrates nicely with Mocha.
Example:
var expect = require('chai').expect;
require('mocha-sinon');
// Function to test, can also be in another file and as long as it's
// being called through some public interface it should be testable.
// If it's not in any way exposed/exported, testing will be problematic.
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
}
describe('privateFunction()', function() {
beforeEach(function() {
this.sinon.stub(console, 'log');
});
it('should log "Good morning" for hours < 12', function() {
privateFunction(5);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good morning') ).to.be.true;
});
it('should log "Good afternoon" for hours >= 12 and < 19', function() {
privateFunction(15);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good afternoon') ).to.be.true;
});
it('should log "Good night!" for hours >= 19', function() {
privateFunction(20);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good night!') ).to.be.true;
});
});
One potential issue: some Mocha reporters use console.log as well, so the tests that stub it may not yield any output.
There's a workaround, but it's not ideal either because it will intersperse Mocha output with the output from privateFunction(). If that's not a problem, replace beforeEach() with this:
beforeEach(function() {
var log = console.log;
this.sinon.stub(console, 'log', function() {
return log.apply(log, arguments);
});
});
ignoring the fact that it's a private function, i would take a couple of steps; refactor my code for better separation of concerns, and utilise this separation with test doubles.
take all the side effects outside to their own modules (the side effect here is writing to the console):
out.js
function log (message) {
console.log(message);
};
module.exports = {log};
app.js
const {log} = require('out');
function greeter (time) {
if (time < 12) {
log('Good morning');
}
if (time >= 12 && time < 19) {
log('Good afternoon');
} else {
log('Good night!');
}
};
module.exports = {greeter};
use some module proxy/spy, like proxyquire to replace the whole out writer when testing:
app.spec.js
describe('output writers', function(){
const fakeOut = {
log: sinon.spy(),
};
const app = proxyquire('./app', {
'out': fakeOut
});
it('should log to the fake out', function(){
app.greeter(15);
assert(fakeOut.log.calledOnce);
});
});
If your purpose is solely to test console output, I would suggest instead of stubs / spies etc on method calls, to use something like:
test-console
monitor stdout/stderr instead, you can use ideas from this gist

Resources