I'm trying to set up unit tests in my project. For that, I use mocha chai and sinon librairies. I'm using a NodeJs server version 8.
Versions :
Sinon : "7.1.0"
Mocha: "5.1.0"
Chai: "4.2.0"
I'd like to stub a method which is declared in another file.
Here's an example :
- a.js
exports.FnA(return FnB())
- b.js
exports.FnB()
I want to stub method FnB() from b.js file so I can test FnA() regardless FnB() return.
Here's what I've tried :
beforeEach(() => {
this.FnBStub = sinon.stub(b, 'FnB').returns('mocked');
});
afterEach(() => this.FnBStub.restore());
it('should mocked FnB function', () => {
try {
console.log(b.FnB()); //returns 'mocked'
console.log(a.FnA()); //return error from FnB() execution ...
} catch (e) {
console.log(e);
}
});
It does stub the method FnB() but only when I called it from an instance of b file. So when I called FnA() the stub seems to go away ...
What am I missing ?
Some help would be really appreciated, thanks :)
EDIT :
a.js example :
const FnB = require('./FnB)
exports.FnA = data => {
const limit = data.releases.update ? 60 : 20;
return FnB(data.ref, limit)
};
b.js example :
exports.FnB = (ref, page, query) => {
//API call
}
testFile.js example :
const a = require('../a')
const b = require('../b')
beforeEach(() => {
this.FnBStub = sinon.stub(b, 'FnB').returns('mocked');
});
afterEach(() => this.FnBStub.restore());
it('should mocked FnB function', () => {
try {
console.log(b.FnB()); //returns 'mocked'
console.log(a.FnA()); //return error from FnB() execution ...
} catch (e) {
console.log(e);
}
});
So as I said I'd like to stub this FnB calling method and just check if this method is called with right parameters.
If the module being exported is a function itself and not a part of an object, you can't stub it directly.
You need to use something like proxyquire. Your test code will look something like this:
const FnBstub = sinon.stub();
const proxyquire = require('proxyquire');
const a = proxyquire('../a', {
FnB: FnBstub
});
const b = require('../b');
For more info, look here: https://github.com/sinonjs/sinon/issues/664
Related
I'm using mocha to test a function and I'm facing an error while running the test file.
The file structure is as follows
server
|-test
| |-customer.test.ts
|-customer.js
This is the customer.js file function
module.exports = (instance) => {
instance.validate = async (ctx) => {
// some code here
}
}
This is the mocha test case file customer.test.ts
const instance = require("../customer")
/* eslint-disable no-undef */
describe('customer', () => {
describe('/POST customers', () => {
it('Create Buy customer', (done) => {
instance.validate({
})
done();
});
})
});
But when I run the file using the command mocha .\customer.test.ts it shows me the following error
TypeError: instance.validate is not a function
How do I make the above function execute?
What you're exporting and what you're doing with the import don't match. The problem is (probably) the export. What you have is this:
module.exports = (instance) => {
instance.validate = async (ctx) => {
// some code here
}
}
That exports a function that, when called, will add a validate method to the object that you pass to it. It does not export an object with a validate method, that would look like this:
module.exports = {
validate: async (ctx) => {
// some code here
},
};
So you need to either fix the export (which I suspect is the problem), or (if the export is really meant to do that), test what it actually does by passing in an object and then checking that, after the call, the object has a validate method.
I'm having a bit of trouble unmocking a function.
I first mock it and now I can't unmock it
//myClass.js
class myClass {
static check(v1,v2) {
return v1 > v2;
}
static async getinfo(v1,v2) {
if (this.check(v1,v2)) {
return await get('api.google.com');
}
return [];
}
}
//myclass.spec.js
describe('Testing myClass', () => {
describe('testing processing', () => {
it('should return result', () => {
const mockPatch = jest.fn().mockImplementation((version, solution) => false);
myClass.check = mockCheck;
try {
const result = await myClass.getinfo(1,2);
expect(result).toBe.([]);
}catch(e) {
throw e;
}
})
})
describe('Testing check', () => {
it('should return true', () => {
expect(myClass.check(2,1)).toBe.true
})
})
})
I already try with
myClass.check.mockRestore()
beforeEach(() => {myClass.check.mockRestore()})
jest.unmock('./myClass.js)
Is there anyway I can solve this? I read all the jest doc and i couldn't find anything
Methods should never be mocked by reassigning them, there is no way how Jest could restore their original implementation this way.
This should always be done with spyOn:
jest.spyOn(myClass, 'check').mockReturnValue(false)
This way a method can be restored with restoreMock or restoreAllMocks. This should be preferably enabled globally in Jest configuration.
I'm assuming that what you're hoping to do is to mock an implementation for use in a specific test, but then have your other tests function without the mocking.
If so, I think you could use the module mocking strategy in conjunction with mockReturnValueOnce.
Be sure to import your module at the top of your tests, then to call jest.mock with the same path. After that, you should be able to call myClass.check.mockReturnValueOnce, and it will be mocked until the next time it is called. After that, it will function normally 👍
I have this code:
import * as a from 'a-a';
jest.mock('a-a');
describe('a-a', () => {
beforeAll(async () => {
const x = await a.x(1); // Calls the mock
console.log(x); // 1
console.log(a.x.mock) // Undefined
});
});
The mock function is:
export async function x(data) {
cache.push(data);
console.log('HERE'); // this is printed
return data;
}
The mock of the module is in the __mocks__ directory.
The a.x() calls the mocked function, but a.x.mock is undefined.
How is that possible? Where is the .mock property?
So, after some investigation I found out that the functions declared in the __mocks__ directory aren't wrapped by jest.fn() by default.
Personally I find the thing a bit confusing.
So you can do both
function x(data) {
cache.push(data);
return cache;
}
jest.mock('a-a', () => ({x: x}))
if you do everything in the same file, or
jest.mock('a-a');
and then in the __mocks__/a-a.js file
export const x = jest.fn(async (data) => {
cache.push(data);
return cache;
});
I have a Node module where I try to connect to a host with:
const testConnection = net.createConnection(port, hostname);
testConnection.on('connect', () => {
// connected
});
testConnection.on('error', (err) => {
// error
});
I am using Sinon to test the method like this:
sinon.stub(net, 'createConnection', (port, hostname) => {
return {
on: (string, cb) => {
switch(string) {
case 'connect':
return cb;
case 'error':
return cb;
case 'close':
return cb;
}
}
}
});
const testConnection = net.createConnection(10, 'hostname');
testConnection.on('error', () => {
console.log('here I am');
});
But I cannot wrap my head around how I should no stub/mock or fake-call the on-method so it returns an error!
Am I missing something here?
I'd stub createConnection return value with a fake EventEmitter instance:
const EventEmitter = require('events');
const fakeEE = new EventEmitter();
sinon.stub(net, 'createConnection', (port, hostname) => fakeEE);
// require your code
// emit events
fakeEE.emit('error', new Error('Smth bad happened'));
// observe the result
// e.g. expect(something).toBeCalled();
As net is dependency of your module, I would use proxyquire to fake that dependency. Works great for us also with ES6 + Babel combo.
I have a service module that is exported as a function. I need to pass a couple of things into it, like a configuration object so it does need to retain this structure. I am trying to stub out a function from the service but can't figure it out. In my app, I have a function that makes an API call that is problematic during testing so I'd like to stub it. (I understand I'd have to write my test differently to handle the async issue)
// myService.js
module.exports = function(config) {
function foo() {
returns 'bar';
}
return {
foo: foo
};
};
// test.js
var config = require('../../config');
var request = require('supertest');
var chai = require('chai');
var expect = chai.expect;
var sinon = require('sinon');
var myService = require('./myService.js')(config);
describe('Simple test', function(done) {
it('should expect "something else", function(done) {
var stub = sinon.stub(myService, 'foo').returns('something else');
request(server) // this object is passed into my test. I'm using Express
.get('/testRoute')
.expect(200)
.expect(function(res) {
expect(res.body).to.equal('something else');
stub.restore();
})
.end(done);
});
});
* /testRoute I set up as a simple GET route that simply returns the value from myService.foo()
The above is not working, and I believe it has to do with the way my service is exporting. If I write the service as below, the stub works fine.
module.exports = {
test: function() {
return 'something';
}
};
But again, I need to be able to pass in information to the module so I would like to keep my modules in the original structure above. Is there a way to stub a function from a module that exports in that manner? I was also looking into proxyquire but not sure if that is the answer.
The reason why your test stub does not work is that the foo function is created every time the module initializer is called. As you discovered, when you have a static method on the module, then you are able to stub.
There are a variety of solutions to this problem-- but the simplest is to expose the method statically.
// myService.js
module.exports = function(config) {
return {
foo: foo
};
};
var foo = module.exports.foo = function foo() {
return 'bar'
}
It's ugly, but works.
What if the foo function has a closure to variables within the service (which is why it lives within the service initializer). Then unfortunately these need to be explicitly passed in.
// myService.js
module.exports = function(config) {
return {
foo: foo
};
};
var foo = module.exports.foo = function(config) {
return function foo() {
return config.bar;
}
}
Now you can safely stub the module.
However, how you are stubbing should be considered unsafe. Only if your test works perfectly does the stub get cleaned up. You should always stub within the before and after (or beforeEach and afterEach) fixtures, such as:
// We are not configuring the module, so the call with config is not needed
var myService = require('./myService.js');
describe('Simple test', function(done) {
beforeEach(function () {
// First example, above
this.myStub = sinon.stub(myService, foo).returns('something else');
// Second example, above
this.myStub = sinon.stub(myService, foo).returns(function () {
returns 'something else';
});
});
afterEach(function () {
this.myStub.restore();
});
it('should expect "something else", function(done) {
request(server) // this object is passed into my test. I'm using Express
.get('/testRoute')
.expect(200)
.expect(function(res) {
expect(res.body).to.equal('something else');
})
.end(done);
});
});
There are other options to be able to stub dependencies using dependency injection. I recommend you look at https://github.com/vkarpov15/wagner-core or my own https://github.com/CaptEmulation/service-builder