Node.js unittest Stubbing Own function - javascript

Apologies if this was asked before. Here is the module that I'd like to unittest inside file getStuff.js. I'm having difficulty stubbing theresolveThing module used here.
getStuff.js
const resolveThing = require('./resolveThing.js');
module.exports = async function getStuff(target, stuff) {
const { element, test, other } = resolveThing(target);
try {
return element;
} catch (error) {
throw new Error('Did not work.');
}
};
And here is my attempt at the unittest with stubbing using sinon. However when I try to run this it errors out with TypeError: Cannot stub non-existent own property resolveType. Anyone know how I can get this test to work?
const getStuff = require('../com/getStuff');
const resolveThing = require('../com/resolveThing');
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');
describe('com.resolveThing', function() {
beforeEach(function () {
sinon.stub(resolveThing, 'resolveThing').returns({element:'a',test:'b',other:'c'});
});
afterEach(function () {
resolveThing.restore();
});
it('Standard message', function() {
const answer = getAttribute('a','b');
expect(answer).toEqual('a');
});
});

sinon.stub(resolveThing, 'resolveThing').returns({element:'a',test:'b',other:'c'});
resolveThing must be an object and 'resolveThing' must be a function in the object, an exception is thrown if the property is not already a function.
I think this is what's hapning in your case.

Related

using sinon to mock a line in a function

I have a function as follows
import config from "../config";
export const encrypt = (recordJSONy, logger) => {
const key = config.encryption.key
if(!key || key == ""){
throw encryptionError.ENCYPTION_KEY_MISSING
}
try{
const decryptedDataStr = TisEncryption.Cipher.encrypt(recordJSON);
return decryptedDataStr;
} catch(e){
console.log(e)
throw encryptionError.ENCRYPTION_FAILED
}
}
I need to write a test for it
describe("help function test", () => {
it("test", () => {
console.log(helperFunctions.encrypt("xxx", loggingService))
});
});
However the above is always returning error because config.encryption.key returns undefined.
I am trying to find a way to kind of mock config.encryption.key to return "xxxxxxx" instead of undefined. The more I look at sinon the more I get confused. Can anyone shed light on how to do so?

Stubing a class call from another function

I have 2 files controller.js and entity.js which interact with each other. I am testing controller.js, and it creates an instance of entity.js (class) and use one of its functions. How can I stub/mock/spy the call and the return of that method?
controller.js
const controller= async (req, res) => {
try {
...
const entity = new Entity({
...
});
const validation = await entity.validate();
...
return res.send()
}
} catch (error) {
return res.send(error)
}
};
Entity.js
class Entity{
constructor() {
...
}
...
async validate() {
...
return response;
}
}
Any idea how to test controller.js using supertest, sinon and chai?
Sinon will happily stub the function. Since it's a class method you just need to be sure to stub the function on the prototype:
const controller = async (req, res) => {
const entity = new Entity();
const validation = await entity.validate();
console.log(validation)
};
class Entity{
constructor() {}
async validate() {
return "real function";
}
}
// stub it
let stub = sinon.stub(Entity.prototype, 'validate')
stub.returns('stubbed function')
controller()
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/7.1.1/sinon.min.js"></script>
This solution uses Ava (but you should be able to adapt to Mocha easily). However I'm more familiar with testdouble. If you have no success with sinon (I'm sure you will), here's an alternative that you may want to consider.
So if we have burrito.js:
module.exports = class {
eat() {
return '🌯';
}
};
And lunch.js:
var Burrito = require('./burrito');
module.exports = () => (new Burrito()).eat();
Then in your test:
const td = require('testdouble');
const test = require('ava');
test('swap burrito', t => {
td.replace('./burrito', class FakeBurrito {
eat() {
return '🌮';
}
});
const lunch = require('./lunch');
t.is(lunch(), '🌮'); // PASS
t.is(lunch(), '🌯'); // FAIL
});
The key is to require your dependency (a burrito) before your subject under test (your lunch) requires it, so that you have time to fake it.

jest mock a property that is an object and a function at the same time

I am trying to mock a property of an object that acts as an object and as a function at the same time. Here's the code:
index.js
const nock = require('nock');
async function myFunc() {
nock.back.setMode('param1');
const { nockDone } = await nock.back('param1', 'param2');
nock.enableNetConnect('param1');
return nockDone;
}
module.exports = { myFunc }
My goal is to mock the nock object in a way I can assert that when myFunc is called, nock.back is called with param1 and param2.
To do so I have the following test:
index.test.js
const nock = require('nock');
const subjectUnderTest = require('./index');
const nockBackImplementation = jest.fn();
nockBackImplementation.setMode = jest.fn();
const nockBackMock = jest.spyOn(nock, 'back');
nockBackMock.mockImplementation(() => nockBackImplementation);
describe('test', () => {
it('calls nock.back with the proper parameters', () => {
subjectUnderTest.myFunc();
expect(nockBackMock).toHaveBeenCalledWith('param1', 'param2');
});
});
For some reason, the test fails saying that the mock function has not been called and also gives this error:
UnhandledPromiseRejectionWarning: TypeError: nock.back.setMode is not a function
I'm not sure how to properly mock nock.
You're assigning the setMode mock to the function used as implementation, which I think is different from the actual nock.back mock. You can set it correctly this way
const nockBackMock = jest
.spyOn(nock, "back")
.mockResolvedValue({ nockDone: "test" });
nockBackMock.setMode = jest.fn();
// you also need to mock the enableNetConnect to avoid errors
const enableNetConnectMock = jest
.spyOn(nock, "enableNetConnect")
.mockReturnValue({});
describe("test", () => {
it("calls nock.back with the proper parameters", () => {
subjectUnderTest.myFunc();
expect(nockBackMock).toHaveBeenCalledWith("param1", "param2");
});
});

How do I test custom Koa middleware for error handling?

As part of a migration of an older app from ExpressJs to Koa JS (v1). I've written a piece of middleware to handle any errors that occur. It looks something like this:
module.errors = function * (next) {
try {
yield next;
} catch (err) {
switch(err && err.message) {
case: 'Bad Request':
this.status = 400;
this.body = {message: 'Bad Request'};
brea;
default:
this.status = 500;
this.body = {message: 'An error has occurred'};
}
this.app.emit('error', err, this);
}
}
It gets included in my application like this:
const app = require('koa')();
const router = require('koa-router');
const { errors } = require('./middleware/errors');
app.use(errors)
.use(router.routes());
app.get('/some-request', function *(next){
// request that could error
});
app.listen();
This all works fine, but I'd like to test the middleware with my unit tests, and perhaps because I'm still fairly new to both Koa and Generator functions, I'm struggling to figure out how to do this.
I know that if I import the error handling middleware, I need to pass it a function that will throw an error, but how do I execute the function passed? Does it need to be closure of some description? How do I assert/expect on the values set for the status code and the like?
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
describe('errors middleware', () => {
it('returns a 500 on a generic error', () => {
let thrower = function(){ throw new Error() }
let errorHandler = errors(thrower());
// mass of confusion
expect(errorHandler.next()).to.throw(Error);
});
});
Koa middlewares are generators (return/yield multiple times) and don't behave like functions, so it feels weird to write unit tests for them. Personally, I suffice with end-to-end test cases.
However, the following might work in your case.
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
describe('errors middleware', () => {
it('returns a 500 on a generic error', () => {
let ctx = { body: {}, status: 404 };
let errorMidIterator = errors().call(ctx, 'NEXT_MID');
// test that it correctly yields to next middleware
expect(errorMidIterator.next().value).should.equal('NEXT_MID');
// simualte an error and test if it correctly sets the body
expect(errorMidIterator.throw(new Error()).done).to.equal(true);
expect(ctx.status).should.equal(500);
});
});
As a side note, I think it is better to export middleware factories from your files rather than plain middleware generator functions. The former gives you more control (i.e. you can possibly inject some of the dependencies, in this case the thrower() function, through the Factory function arguments). My middleware files look like these.
module.exports = function MyMiddleware(options) {
return function *MyMiddleware(next) {
// options.config.foo
// options.httpclient.get(..)
};
}
Lastly koa wraps the generator functions with co, which changes the semantics so unit tests are not that useful (subjective)
you can use this library https://www.npmjs.com/package/co which used by koa.js 1.x to wrap your generator functions and mock the context object.
const co = require('co');
const Emitter = require('events');
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
const wrapped = co.wrap(errors);
const mockApp = new Emitter();
describe('errors middleware', () => {
it('returns a 500 on a generic error', (done) => {
const ERROR_MSG = 'middleware error';
const ctx = {app: mockApp};
const next = function* () {
throw new Error(ERROR_MSG);
}
wrapped.call(ctx, next)
.then(() => {
try {
expect(ctx.status).to.equal(500);
expect(ctx.body.message).to.equal(ERROR_MSG);
done();
} catch (err) {
done(err);
}
})
.catch(err => done(err))
});
});
This is how I solved this problem with Jest, I just created a custom res object and passed it to error handler:
const error = require('../../../middleware/error');
describe('error middleware', () => {
it(' return 500 if there is unhandled error', async () => {
const res = {
status: (c) => {this.c = c; return {send: (s) => {this.s = s; return this}}} ,
c: 200,
s: 'OK',
};
const req = {};
const next = jest.fn();
const err = () => {
throw new Error()
};
const errorHandler = error(err, req, res, next);
expect(errorHandler).toMatchObject({c: 500, s: 'Something failed'});
});
});

sinon stub not replacing function

I'm trying to use sinon stub to replace a function that might take along time. But when I run the tests, the test code doesn't seem to be using the sinon stubs.
Here is the code I'm trying to test.
function takeTooLong() {
return returnSomething();
}
function returnSomething() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('ok')
}, 1500)
})
}
module.exports = {
takeTooLong,
returnSomething
}
and this is the test code.
const chai = require('chai')
chai.use(require('chai-string'))
chai.use(require('chai-as-promised'))
const expect = chai.expect
chai.should()
const db = require('./database')
const sinon = require('sinon')
require('sinon-as-promised')
describe('Mock the DB connection', function () {
it('should use stubs for db connection for takeTooLong', function (done) {
const stubbed = sinon.stub(db, 'returnSomething').returns(new Promise((res) => res('kk')));
const result = db.takeTooLong()
result.then((res) => {
expect(res).to.equal('kk')
sinon.assert.calledOnce(stubbed);
stubbed.restore()
done()
}).catch((err) => done(err))
})
I get an assertion error
AssertionError: expected 'ok' to equal 'kk'
+ expected - actual
-ok
+kk
What am I doing wrong? Why isn't the stub being used ? The test framework in Mocha.
Sinon stubs the property of the object, not the function itself.
In your case you are exporting that function within an object.
module.exports = {
takeTooLong,
returnSomething
}
So in order to properly call the function from the object, you need to replace your function call with the reference to the export object like :
function takeTooLong() {
return module.exports.returnSomething();
}
Of course based on your code, you can always refactor it :
var exports = module.exports = {
takeTooLong: function() { return exports.returnSomething() }
returnSomething: function() { /* .. */ }
}
You might want to have a look at Proxyquire to stub/spy directly exported functions.
https://www.npmjs.com/package/proxyquire/

Categories