Sinon mock is calling the real method - node.js

I want to mock a method on a class so that a dummy method is called which I can obtain stats on such as how many time it was invoked etc...
I'm trying to do it this way using Sinon, but the actual method is still invoked (and verify isn't registering the call)
I'm using Sinon with Jest ... yes I know Jest has it's own mocking /stubbing/spying capabilities but I've been having trouble with them in Node so I'm looking at Sinon. I can't use Mocha instead of jest which usually pairs with Sinon (sigh, corporate).
Test
const sinon = require('sinon')
const Cache = require('../../../adapters/Cache')
const Fizz = require('../Fizz')
describe('CACHE', () => {
it('should return a mock', () => {
const mockCache = sinon.mock(Cache.prototype, 'retrieveRecords')
const fizz = new Fizz()
fizz.doStuff()
mockCache.expects('retrieveRecords').once()
mockCache.verify()
})
})
Fizz
const Cache = require('../../adapters/Cache')
const Thing = require('../../adapters/Thing')
class Fizz {
doStuff() {
const thing = new Thing()
const cache = new Cache()
return cache.retrieveRecords('foo')
}
}
module.exports = Fizz

I got my syntax wrong. Needed to call mockCache.expects('retrieveRecords') to make it not call the real method, I was thinking this counted the invocations, but that's what I get from not RTFM. This works:
const sinon = require('sinon')
const Cache = require('../../../adapters/Cache')
const Fizz = require('../Fizz')
describe('CACHE', () => {
it('should return a mock', () => {
const mockCache = sinon.mock(Cache.prototype)
const expectation = mockCache.expects("retrieveRecords")
expectation.once()
const fizz = new Fizz()
const res = fizz.doStuff()
mockCache.verify()
})
})

Related

stubbing AWS Dynamodb documentClient for integration test

im having some issues stubbing this dependency. I know there ir a aws-sdk-mock modules but mi goal its to stub it with sinon and chai.
Here is mi code,
Test code
const chai = require('chai');
const sinon = require('sinon');
const chaiHttp = require('chai-http');
const app= require('./app');
chai.use(chaiHttp);
const queryMock =sinon.stub();
const dynamoMock = {
DocumentClient:sinon.fake.returns({
query:queryMock
})
}
let awsDynamoMock;
describe.only('Integration test for activation',()=>{
beforeEach(() => {
awsDynamoMock = sinon.stub(require('aws-sdk'),'DynamoDB');
awsDynamoMock.returns(dynamoMock);
})
afterEach(() => {
awsDynamoMock.restore();
})
it('Request /endpoint returns HTTP 200 with {} when user exist and all task are done',(done)=>{
const params = {
TableName:'table',
KeyConditionExpression: `client_id= :i`,
ExpressionAttributeValues: {
':i': '23424234'
},
ConsistentRead:true
};
const userWithNoPendingsMock = {
Items: [
{
client_id: "23424234",
},
],
Count: 1,
ScannedCount: 1,
}
queryMock.withArgs(params).returns({
promise:() =>sinon.fake.resolves(userWithNoPendingsMock)
})
chai
.request(app)
.post("/endpoint")
.end( (err, res) => {
chai.expect(res.status).to.be.eql(200);
chai.expect(res.body).to.eql({});
done();
});
});
})
Connection to dynamoDB to stub
const AWS = require('aws-sdk');
AWS.config.update({region:'REGION'});
let docClient = false;
const getDynamoSingleton = async () => {
if (docClient) return docClient;
docClient = new AWS.DynamoDB.DocumentClient();
console.log(docClient)
return docClient
}
module.exports = getDynamoSingleton
Using DynamoDB example
const getElementById = async (TableName,key,id)=>{
const docClient = await getDynamoSingleton();
//Make query params.
const params = {
TableName,
KeyConditionExpression: `${key} = :i`,
ExpressionAttributeValues: {
':i': id
},
ConsistentRead:true
};
//Run query as promise.
return docClient.query(params).promise();
}
Im really stuck on this problem, so any help would be useful. I know the problem has something to do with de documentclient
Thanks for the help
I realize this is an old question, but you can set up a resolvable object with a little trickery. Some inspiration from this answer.
const sandbox = require('sinon').createSandbox();
const AWS = require('aws-sdk');
describe('...', () => {
it('...',
 (done) => {
// Create a dummy resolver, which returns an empty object.
const dummy = {func: () => {}};
sandbox.stub(dummy, 'func').resolves({some: 'fake response'});
// Mock docClient.query. Binding to .prototype should make this apply to any `new AWS.DynamoDB.DocumentClient()` calls.
sandbox.stub(AWS.DynamoDB.DocumentClient.prototype, 'query').returns({promise: dummy.func});
// Run your tests here.
});
});
This is cut down to remove a lot of the extra configuration you are doing (and probably need). We create a dummy object with the function func which returns a sinon promise.
Next, we stub the AWS.DynamoDB.DocumentClient prototype so that new AWS.DynamoDB.DocumentClient() will receive our sinon stub.
Third, we configure our DocumentClient prototype stub to return a plain javascript object with a property called promise. This property points to the first dummy object's promise-returning func method.
Now calls to docClient.query(params).promise() should receive a mocked promise. docClient.query(params) will receive the stub sandbox.stub(AWS.DynamoDB.DocumentClient.prototype, ...). And .promise() will be processed from {promise: dummy.func} to refer to the dummy resolver.

How to mock npm module with sinon/mocha

I'm trying to test a function that calls the module cors. I want to test that cors would be called. For that, I'd have to stub/mock it.
Here is the function
cors.js
const cors = require("cors");
const setCors = () => cors({origin: 'http//localhost:3000'});
module.exports = { setCors }
My idea of testing such function would be something like
cors.test.js
describe("setCors", () => {
it("should call cors", () => {
sinon.stub(cors)
setCors();
expect(cors).to.have.been.calledOnce;
});
});
Any idea how to stub npm module?
You can use mock-require or proxyquire
Example with mock-require
const mock = require('mock-require')
const sinon = require('sinon')
describe("setCors", () => {
it("should call cors", () => {
const corsSpy = sinon.spy();
mock('cors', corsSpy);
// Here you might want to reRequire setCors since the dependancy cors is cached by require
// setCors = mock.reRequire('./setCors');
setCors();
expect(corsSpy).to.have.been.calledOnce;
// corsSpy.callCount should be 1 here
// Remove the mock
mock.stop('cors');
});
});
If you want you can define the mock on top of describe and reset the spy using corsSpy.reset() between each tests rather than mocking and stopping the mock for each tests.

Mock new Function() with Jest

I'm having trouble trying to mock a module with a constructor
// code.js
const ServiceClass = require('service-library');
const serviceInstance = new ServiceClass('some param');
exports.myFunction = () => {
serviceInstance.doSomething();
};
And the test code:
// code.test.js
const ServiceClass = require('service-library');
jest.mock('service-library');
const {myFunction} = require('../path/to/my/code');
test('check that the service does something', () => {
// ????
});
It's not like the Documentation example Mocking Modules because you need to instantiate the module after importing it. And isn't either like Mocking a Function.
How could I mock this doSomething() function while testing?
For reference, I'm trying to mock #google-cloud/* packages here. And I have a few projects that could take advantage on this.
You need to mock the whole module first so that returns a jest mock. Then import into your test and set the mock to a function that returns an object holding the spy for doSomething. For the test there is difference between of a class called with new and a function called with new.
import ServiceLibrary from 'service-library'
jest.mock( 'service-library', () => jest.fn())
const doSomething = jest.fn()
ServiceLibrary.mockImplementation(() => ({doSomething}))
Following #andreas-köberle solution I was able to mock #google-cloud/bigquery like so:
// mock bigquery library
const BigQuery = require('#google-cloud/bigquery');
jest.mock('#google-cloud/bigquery', () => jest.fn());
const load = jest.fn(() => ({'#type': 'bigquery#load_job'}));
const table = jest.fn(() => ({load}));
const dataset = jest.fn(() => ({table}));
BigQuery.mockImplementation(() => ({dataset}));
// mock cloud storage library
const {Storage} = require('#google-cloud/storage');
jest.mock('#google-cloud/storage');
const file = jest.fn(name => ({'#type': 'storage#file', name}));
const bucket = jest.fn(() => ({file}));
Storage.mockImplementation(() => ({bucket}));
I'm leaving this here as a reference in case someone else googles something similar. But to make it clear, thats just a particularization for #andreas-köberle answer

Sinon: Mocking websockets/ws

How can I mock up websockets/ws using Sinon? I'm trying to test that my application behaves as expected when using WebSockets, without necessarily needing to connect each time (eg: testing event handlers, etc).
Coming from a C# background, I'd just mock out the whole interface using a library like Moq, and then verify that my application had made the expected calls.
However, when trying to do this with Sinon, I'm running into errors.
An example of a test:
const WebSocket = require('ws');
const sinon = require('sinon');
const webSocket = sinon.mock(WebSocket);
webSocket.expects('on').withArgs(sinon.match.any, sinon.match.any);
const subject = new MyClass(logger, webSocket);
This class is then calling:
this._webSocket.on("open", () => {
this.onWebSocketOpen();
});
But when I try and run my tests, I get this error:
TypeError: Attempted to wrap undefined property on as function
What's the correct way to mock out an object like this using Sinon?
Thanks.
If your just trying to test if the given sockets 'on' method was called when passed in, this is how you would do it:
my-class/index.js
class MyClass {
constructor(socket) {
this._socket = socket;
this._socket.on('open', () => {
//whatever...
});
};
};
module.exports = MyClass;
my-class/test/test.js
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const sinon_chai = require('sinon-chai');
const MyClass = require('../index.js');
const sb = sinon.sandbox.create();
chai.use(sinon_chai);
describe('MyClass', () => {
describe('.constructor(socket)', () => {
it('should call the .prototype.on method of the given socket\n \t' +
'passing \'open\' as first param and some function as second param', () => {
var socket = { on: (a,b) => {} };
var stub = sb.stub(socket, 'on').returns('whatever');
var inst = new MyClass(socket);
expect(stub.firstCall.args[0]).to.equal('open');
expect(typeof stub.firstCall.args[1] === 'function').to.equal(true);
});
});
});

Stub class instance method to return resolved Promise (using Sinon)

I am writing controller unit tests for a Node Express app.
The controller creates an instance of a model class and then calls one of its method that returns a resolved Promise. I need to stub the class constructor and then the method so that it returns a Promise resolved with test data.
Controller:
const Model = require('../../models/model');
module.exports = function (req, res, next) {
const instance = new Model(req.body);
instance.method()
.then(result => {
// do something with result
})
.catch(err => next(err));
};
Test:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
require('sinon-as-promised');
const Model = require('../../../../server/models/model');
const stubs = {
model: sinon.stub(Model.prototype, 'method', function () { sinon.stub().resolves('foobar') })
};
const subject = proxyquire('../../../../server/controllers/models/method', {
'../../models/model': stubs.model
});
Sinon.JS Documentation Stub API says:
var stub = sinon.stub(object, "method", func);
Replaces object.method with a func, wrapped in a spy.
But I get this error when the test code hits .then in the controller:
instance.method(...).then is not a function
Calling .resolves() (from sinon-as-promised) directly on the stub gives the then/catch/finally methods to the class instance rather than to the class instance method as required:
sinon.stub(Model.prototype, 'method').resolves('foobar')
Thanks in advance for help!
You need to return sinon.stub().resolves('foobar') from your stub function.
const stubs = {
model: sinon.stub(Model.prototype, 'method',
function () { return sinon.stub().resolves('foobar') })
};
But you'd probably just be better off returning a native Promise since you aren't keeping a reference to the inner stub:
const stubs = {
model: sinon.stub(Model.prototype, 'method',
function () { return Promise.resolve('foobar') })
};
Have discovered this solution where you make your own fake Model:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
require('sinon-as-promised');
const methodStub = sinon.stub().resolves('foobar');
const ModelStub = function () {
this.method = methodStub;
};
const subject = proxyquire('../../../../server/controllers/models/method', {
'../../models/model': ModelStub
});
Credit goes to Darren Hurley.

Resources