simple ProxyRequire is not working? - node.js

i have been stuck with making Proxy-require work, below is my code and test file. I am trying to stub a function inside the code file using proxyRequire
//createSignature.js
'use strict';
var keys = require('../../../../utils/keys');
module.exports = function createSignature(transaction) {
try {
let prvkeyDecoded = keys.bs58_encode('test');
return true
} catch (err) {
}
};
here is the test file
//createSignature_unit.js
'use strict';
const sinonChai = require("sinon-chai");
const chai = require('chai');
chai.use(sinonChai);
const sinon = require('sinon');
const createSignature = require('./createSignature');
const proxyquire = require('proxyquire').noPreserveCache().noCallThru();
const keysMock =
{
bs58_encode: sinon.stub()
};
const test =
proxyquire('./createSignature', {
'../../../../utils/keys': keysMock
})
describe('test backend', () => {
it("Create Signature with stubs", function() {
test('test')
expect(keysMock.bs58_encode).to.have.been.calledOnce;
});
});
my test function is not called, and keysMock.bs58_encodealso is not been called even once. Am i missing something?
//output window
1) Create Signature with stubs
0 passing (9ms)
1 failing
1) test backend
Create Signature with stubs:
AssertionError: expected stub to have been called exactly once, but it was called 0 times
at Context.<anonymous> (createSignature_unit.js:37:46)
In addition to this if i just call
it("Create Signature with stubs", function() {
expect(test('fg')).to.be.true
//expect(keysMock.bs58_encode).to.have.been.calledOnce;
});
i get output as AssertionError: expected undefined to be true

Your stub wrong function as mock. In test, you stub bs58_encode but in the source file, you use bs58_decode. Change it into bs58_decode should fix it.
const keysMock = {
bs58_decode: sinon.stub() // change to decode
};
const test =
proxyquire('./createSignature', {
'../../../../utils/keys': keysMock
})
describe('test backend', () => {
it("Create Signature with stubs", function () {
test('test')
expect(keysMock.bs58_decode).to.have.been.calledOnce; // change to decode
});
});

Related

Node, Sinon - unable to test constructor agruments

I need to test/assert the constructor call with expected arguments while calling a function but getting an error AssertError: step1,step2 is not a function. I'm using sinon, chai libraries for testing function in nodejs
// pipeline.js
class Pipeline {
constructor(steps) {
this.steps = steps;
}
run(data) {
console.log('run steps with data');
}
}
// job.js
function peformJobs(data, steps) {
const pipeline = new Pipeline(steps)
pipeline.run(data)
}
// jobs.test.js
const sinon = require('sinon');
const Pipeline = require('./pipeline')
onst peformJobs = require('./job')
describe('test performJobs function', () => {
it('should call pipeline with step1, step2', () => {
sinon.spy(Pipeline, 'constructor');
const data = { some: 'data' };
const steps = ['step1', 'step2']
peformJobs(data, steps)
// want to test Pipeline constructor called with the required arguments or not
sinon.assert.calledWithNew(steps)
});
});

sinon stub calls fake calling actual function

I'm having situation where I want to write unit test cases for a function to make sure if it is working fine or not. So I have created stub for that specific function and when I tries to calls fake that stub, the function is actually getting called instead of fake call. Below is my scenario:
I have an main function from where I'm calling the function saveData(**).
saveData(**) function is calling AWS SQS to save an message to DB
Below is my main function:
'use strict';
async function mainFunction() {
try {
await saveData(
name,
age,
);
return true;
} catch (e) {
console.log('Error - [%s]', e);
return null;
}
}
module.exports = { mainFunction };
Below is my saveData(**) function:
'use strict';
const AWS = require('aws-sdk');
const sqs = new AWS.SQS();
const saveData = async (
name,
age,
) => {
await sendMessage(JSON.stringify(dbData));
const params = {
DelaySeconds: <some_delay>,
MessageAttributes: <messageAttributes>,
MessageBody: {name:name, age:age},
QueueUrl: <URL_FOR_QUEUE>,
};
return sqs.sendMessage(params).promise();
return true;
};
module.exports = {
saveData,
};
And my test case is,
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
require('app-module-path').addPath('./src');
const sinon = require('sinon');
const app = express();
const sqsSender = require('lib/queue');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const main = require('../../../src/main-function');
const routes = require('routes');
routes.configure(app);
let mainFunctionStub;
let saveDataStub;
describe('/v1/main', () => {
beforeEach(() => {
mainFunctionStub = sinon.stub(main, 'mainFunction');
saveDataStub = sinon.stub(sqsSender, 'saveData');
});
describe('Test', () => {
it(`should return success`, (done) => {
const name = 'Name';
const age = 'Age';
saveDataStub.resolves({
name,
age,
});
});
});
afterEach(() => {
mainFunctionStub.restore();
mainFunctionStub.reset();
saveDataStub.restore();
saveDataStub.reset();
});
});
But this test is returning,
error: Jun-20-2021 20:07:05: Error - [Error [ConfigError]: Missing region in config
and,
Error: Timeout of 3500ms exceeded.
From this error I can say that this is actually calling SQS function instead of faking. How can I resolve this or how can I fake call to this function? I'm new to this unit testing so any help would be appriciated.
Stubbing works by replacing the property on the exports object. Since the require happens before sinon replaces the function, you capture the reference to the original function instead of dynamically using the currently set one.
You haven't showed your require calls in the main file, but from the call-site I infer you're importing it like const { saveData } = require('../foo/sqsSender'). This means you're grabbing the function off of the object when first loading the code. If you instead keep a reference to the sqsSender module instead, and reference the function on invocation, the stub should work.
'use strict';
// Don't destructure / grab the function.
const sqsSender = require("../foo/sqsSender")+
async function mainFunction() {
try {
// Use reference through module
await sqsSender.saveData(
name,
age,
);
return true;
} catch (e) {
console.log('Error - [%s]', e);
return null;
}
}
module.exports = { mainFunction };

How to test for an event to have been fired and its value?

I couldn't find any working examples to test for whether an event was emitted and whether the emitted value is as expected.
Here is the class that emits messages and its parent:
const EventEmitter = require('events').EventEmitter;
class FileHandler extends EventEmitter {
constructor() {
super();
}
canHandle(filePath) {
emit('not super type');
}
parseFile(filePath) {
emit('supper parsing failed');
}
whoAmI() {
return this.emit('who',"FileHandler");
}
}
module.exports = FileHandler;
//diff file
const FileHandler = require('./FileHandler');
class FileHandlerEstedamah extends FileHandler {
constructor() {
super();
}
canHandle(filePath) {
this.emit('FH_check','fail, not my type');
}
parseFile(filePath) {
this.emit('FH_parse','success');
}
}
module.exports = FileHandlerEstedamah;
Here is my current test code:
var sinon = require('sinon');
var chai = require('chai');
const FileHandlerEstedamah = require("../FileHandlerEstedamah");
describe('FH_parse', function() {
it('should fire an FH_parse event', function(){
const fhe = new FileHandlerEstedamah();
var fhParseSpy = sinon.spy();
fhe.on('FH_parse',fhParseSpy);
fhe.parseFile("path");
//I tried a large number of variants of expect, assert, etc to no avail.
});
});
I expected this to be straightforward but somehow I am missing something.
Thank you,
Jens
You can assert the spy was called once and called with expected arguments as below
sinon.assert.calledOnce(fhParseSpy);
sinon.assert.calledWith(fhParseSpy, 'success');
You almost nearly there. To check the value, we must call done() after that in mocha to tell that our test is finish.
The code
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');
const FileHandlerEstedamah = require("../FileHandlerEstedamah");
describe('FH_parse', function() {
it('should fire an FH_parse event', function(done){ // specify done here
const fhe = new FileHandlerEstedamah();
fhe.on('FH_parse', (data) => {
assert.equal(data, 'success'); // check the value expectation here
done(); // hey mocha, I'm finished with this test
});
fhe.parseFile("path");
});
});
Hope it helps

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