Why doesn't sinon recognize my stub? - javascript

Let's say I have a module that exports like this:
module.exports = mymodule;
Then in my test file, I require the module and stub it.
var mymodule = require('./mymodule');
describe('Job gets sports data from API', function(){
context('When there is a GET request', function(){
it('will call callback after getting response', sinon.test(function(done){
var getRequest = sinon.stub(mymodule, 'getSports');
getRequest.yields();
var callback = sinon.spy();
mymodule.getSports(callback);
sinon.assert.calledOnce(callback);
done();
}));
});
});
That works and the test passes! But everything breaks down if I need to export more than one object. See below:
module.exports = {
api: getSports,
other: other
};
Then I try to adjust my test code:
var mymodule = require('./mymodule');
describe('Job gets sports data from API', function(){
context('When there is a GET request', function(){
it('will call callback after getting response', sinon.test(function(done){
var getRequest = sinon.stub(mymodule.api, 'getSports');
getRequest.yields();
var callback = sinon.spy();
mymodule.api.getSports(callback);
sinon.assert.calledOnce(callback);
done();
}));
});
});
In this case, my test craps out. How can I change my stub code to work? Thanks!

Based on this
module.exports = {
api: getSports,
other: other
};
it looks like mymodule.api doesn't itself have a getSports method. Rather, mymodyle.api is a reference to a getSports function insider your module.
Instead of stubbing getSports you would need to stub api:
var getRequest = sinon.stub(mymodule, 'api');
However, given how you're trying to stub getSports, you might instead want to update how you are exporting the function instead of how you are stubbing it.

Related

node.js mock sendmailer transporter inside function

Im working with an node handler in AWS lambda and i need to make another files with integration tests from that function, but i cant mock the transporter with sinon or mockery.
the index.js function:
var nodemailer = require('nodemailer');
exports.handler = (event, context, callback) =>
{
var transporter=createTransporter();
transporter.sendMail(data, function (error, success) {
console.log(error);
response = getResponse(404, error);
}
callback(null, response);
});
}
function createTransporter() {
return nodemailer.createTransport({
service: "SMTP",
auth: {
user: "XXXX#XXX",
pass: "XXXX"
}
});
}
the purpose is to mock the function createTransporter() so that it doesnt send any email when it is called in javascript file test with mocha and expect:
var mockery = require('mockery');
var nodemailerMock = require('nodemailer-mock');
var index = require("../index.js");
describe("The handler function tests", function () {
before(function () {
mockery.enable({
warnOnUnregistered: false
});
mockery.registerMock('nodemailer', nodemailerMock);
});
it('JSON error html ', function () {
var callback = function (name, response) {
expect(JSON.stringify(response.statusCode)).to.be('404');
};
var context = {};
index.handler(event, context, callback);
});
});
I wrote nodemailer-mock :)
The problem you're having is that you are calling var index = require("../index.js"); before you are mocking nodemailer via mockery, so it is already in the module cache. I included // Make sure anything that uses nodemailer is loaded here, after it is mocked... in the examples in the README, but should probably make it more clear.
Move the require("../index.js") after nodemailer is mocked and it will be work as expected.
var mockery = require('mockery');
var nodemailerMock = require('nodemailer-mock');
// don't require here since you will get the real nodemailer and cache it
var index;
describe("The handler function tests", function () {
before(function () {
mockery.enable({
warnOnUnregistered: false
});
mockery.registerMock('nodemailer', nodemailerMock);
// do the require() here after nodemailer is mocked
index = require("../index.js");
});
// your tests here should now use nodemailer-mock
it('JSON error html ', function () {
var callback = function (name, response) {
expect(JSON.stringify(response.statusCode)).to.be('404');
};
var context = {};
index.handler(event, context, callback);
});
});
Another option is to use the { useCleanCache: true } option with calls to mockery.resetCache();, though I have had mixed results. See Controlling the Module Cache in the mockery documentation.
I'm not 100% sure why this would fail, but I suggest one of two things:
Try doing var createTransporter = function()... there's a slight difference here that might be your issue
exporting createTransporter so you can assign a new value to it, either a mock or not. This isn't very "keep implementation details private", it does work
Have your module return a class, or object anyway, where you can set some "use this transporter method" value. (ie dependency injection)
You can use the following option from Jest:
jest.mock('nodemailer').setMock(/* function mock for module */)
Remember to use this at the top of the file, before import or require statements.
Here is the official Jest documentation: https://jestjs.io/docs/manual-mocks#mocking-node-modules.

Node.js calling function from other function not working

Profile.js code goes as below
'use strict';
var service = require('../services/Profile');
class Profile {
updateProfile(req, resp) {
this.updateUserDetails(req, resp);
}
updateUserDetails(req, resp){
var admin = req.body;
resp.json({"success":true,"message":"User Updated"});
}
}
module.exports = new Profile();
server.js code goes as below
...... Some code -------
var profile = require("./controllers/Profile")
app.put("/api/profile", auth, profile.updateProfile);
...... Some code -------
When I make the call <>/api/profile I am getting error
TypeError: Cannot read property 'updateUserDetails' of undefined ,
(at line number of code this.updateUserDetails(req, resp);)
Since there is some common logic so I need to move to some function and want to call in different place, but I am getting this error. I am new to node js looking for help.
This is a classic misunderstanding of how this works in javascript. I'd suggest you search stackoverflow for the phrase "how this works in javascript".
As for your code, you either need to do this:
app.put("/api/profile", auth, function (req,res) {
profile.updateProfile(req,res)
});
or this:
app.put("/api/profile", auth, profile.updateProfile.bind(profile));
I moved the function out of class and using it, it worked
'use strict';
var service = require('../services/Profile');
class Profile {
updateProfile(req, resp) {
updateUserDetails(req, resp);
}
}
function updateUserDetails(req, resp){
var admin = req.body;
resp.json({"success":true,"message":"User Updated"});
}
module.exports = new Profile();
change your code to:
var prof = new Profile();
module.exports = prof;
and then use it in the other method like this:
class Profile {
updateProfile(req, resp) {
prof.updateUserDetails(req, resp);
}
this should work just fine.

What is the best way to write unit test in node.js?

I have a module where I load a mustache template file. I would like to write a unit test for this. I am trying to use mocha, chai and rewire.
Here is my module.js:
var winston = require('winston');
var fs = require('fs');
var config = require('./config.js');
exports.logger = new winston.Logger({
transports: [
new winston.transports.File(config.logger_config.file_transport),
new winston.transports.Console(config.logger_config.console_transport)
],
exitOnError: false
});
exports.readTemplateFile = function(templateFile, callback) {
fs.readFile(config.base_directory + templateFile + '.tpl.xml', 'utf8', function (err, data) {
if (err) {
logger.error('Could not read template ' + templateFile + ': ' + err);
}
callback(data);
});
};
In the callback function I use mustache to do something with the template.
What is the best way to test this?
Maybe I will have to rewire the fs.readFile? As the file won't be there when the test will be executed. The Winston logger is also an interesting part I guess, not sure if it will be initialized if I import this within a mocha test. My first test shows the logger is undefined.
One of the most important unit testing principle is testing very small piece of code. To achieve that you should definitely mock or stub calls to functions that not belong to testing code (readFile and logger.error in this case). For provided code you can make three test cases:
calling readFile with proper arguments
calling error if err is present
calling callback function with proper argument
Your callback function should be tested outside this code, for e.g. by providing fake data as parameter:
define('Some test', () => {
it('should return true', () => {
expect(callbackFunction('fakeData').to.be.ok);
});
});

Mocking console.log()/Any Other Function in MOCHA testing framework

I am writing test cases for NODE JS API. But wherever console.log() is there in routes or services of NODE JS File, it gets printed to CLI. Is there a way to mock these so that these won't get printed in CLI.
I have explored couple of libraries like Sinon, Stub for mocking. But couldn't grasp the working of those libraries.
You can override function entirely: console.log = function () {}.
You should not try to mock console.log itself, a better approach is for your node modules to take a logging object. This allows you to provide an alternative (ie. a mock) during testing. For example:
<my_logger.js>
module.exports = {
err: function(message) {
console.log(message);
}
}
<my_module.js>
var DefaultLogger = require('my_logger.js');
module.exports = function(logger) {
this.log = logger || DefaultLogger;
// Other setup goes here
};
module.exports.prototype.myMethod = function() {
this.log.err('Error message.');
};
<my_module_test.js>
var MyModule = require('my_module.js');
describe('Test Example', function() {
var log_mock = { err: function(msg) {} };
it('Should not output anything.', function() {
var obj = new MyModule(log_mock);
obj.myMethod();
});
});
The code here I've simplified, as the actual test isn't the reason for the example. Merely the insertion of alternative logging.
If you have a large codebase with lots of console.log calls, it is better to simply update the code as you add tests for each method. Making your logging pluggable in this way makes your code easier and more receptive to testing. Also, there are many logging frameworks available for node. console.log is fine during development when you just want to dump out something to see what's going on. But, if possible, try to avoid using it as your logging solution.
I could not find a solution which only hides the console.log calls in the module to be tested, and mocks none of the calls of the testing framework (mocha/chai in my case).
I came up with using a copy of console in the app code:
/* console.js */
module.exports = console;
/* app.js */
const console = require('./console');
console.log("I'm hidden in the tests");
/* app.spec.js */
const mockery = require('mockery');
var app;
before(() => {
// Mock console
var consoleMock = {
log: () => {}
}
mockery.registerMock('./console', consoleMock);
// Require test module after mocking
app = require('./app');
});
after(() => {
mockery.deregisterAll();
mockery.disable();
});
it('works', () => {});
You could do something along the lines of adding these before/after blocks to your tests, but the issue is that mocha actually uses console.log to print the pretty messages about the results of the test, so you would lose those
describe('Test Name', function() {
var originalLog;
beforeEach(function() {
originalLog = console.log;
console.log = function () {};
});
// test code here
afterEach(function() {
console.log = originalLog;
})
})
The problem is that your output would just look like
Test Name
X passing (Yms)
Without any intermediate text

Dispatcher not registering callbacks in jest unit tests

I'm writing unit tests for a store in a react+flux app. I followed the example of setting up the mock dispatcher here, and my unit test looks like this:
jest.dontMock "../../app/scripts/stores/item_store.coffee"
jest.dontMock "object-assign"
describe 'ItemStore', ->
ShopConstants = require "../../app/scripts/constants/shop_constants.coffee"
ShopDispatcher = undefined
ItemStore = undefined
callback = undefined
actionBuildQueryString =
source: "VIEW_ACTION"
action:
type: ShopConstants.ActionTypes.BUILD_QUERY_STRING
size: "4"
actionReceiveFilterRespData =
source: "SERVER_ACTION"
action:
type: ShopConstants.ActionTypes.RECEIVE_FILTER_RESP_DATA
data: {item: {} }
beforeEach ->
ShopConstants = require "../../app/scripts/constants/shop_constants.coffee"
ShopDispatcher = require "../../app/scripts/dispatchers/shop_dispatcher.coffee"
ItemStore = require "../../app/scripts/stores/item_store.coffee"
callback = ShopDispatcher.register.mock.calls[0][0]
it "registers a callback with the dispatcher", ->
expect(ShopDispatcher.register.mock.calls.length).toBe(1)
In my item_store.coffee file, I register with the dispatcher as so:
ShopDispatcher.register (payload) ->
action = payload.action
switch action.type
when ActionTypes.BUILD_QUERY_STRING
WebApiUtils.fetchItems(payload)
when ActionTypes.RECEIVE_FILTER_RESP_DATA
_setItems(action.data)
ItemStore.emitChange()
I expected the mocked Dispatcher to register the callbacks since that happens in the actual item_store file, which I have told jest to not mock. However, since ShopDispatcher.register is undefined, it's not being registered, but I am not quite sure why. Any help is appreciated.
I was also facing the same problem. Instead of using the ShopDispatcher.register.mock.calls[0][0] try the ShopDispatcher.dispatch. the below code working perfectly for me (using type script).
beforeEach(function () {
dispatcher = require("../../../src/App/Dispatcher");
localeStore = require("../../../src/stores/localestore");
localeAction = require("../../../src/actions/Locale/LocaleAction");
}
it("should translate the element with the value in current locale JSON", function () {
localeChangeAction = new localeAction(true, locale, localeJson);
dispatcher.dispatch(localeChangeAction);
var translatedText = localeStore.instance.TranslateText("login.login-header");
expect(translatedText).toEqual("Login header");
});

Categories