Node, Sinon - unable to test constructor agruments - node.js

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)
});
});

Related

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 };

simple ProxyRequire is not working?

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
});
});

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);
});
});
});

Best way to pass data to a Mocha test that's run programmatically?

Trying to solve a problem where I can't seem to pass dynamically gathered data to Mocha tests.
Here is the logic of my application:
Client submits their Github url. Request is made to Express/Node application.
Express/Node application takes repo and username and makes request to Github API for data and adds the content of the files to an object as base64.
The object with the files are passed to the relevant test files and then executed.
The results are processed and preliminary grades are created. These are then sent back to the client.
Here is what a test file can look like:
const chai = require('chai');
const chaiSubset = require('chai-subset');
chai.use(chaiSubset);
const expect = chai.expect;
const base64 = require('base-64');
const HTML_CONTENT = require('../../00-sandbox-files/basic-portfolio-solution.json').html;
const CSS_CONTENT = require('../../00-sandbox-files/basic-portfolio-solution.json').css;
const decodedCSS = base64.decode(CSS_CONTENT[1].content);
const cheerio = require('cheerio');
const juice = require('juice');
let decodedHTMLcontact;
let decodedHTMLindex;
let decodedHTMLportfolio;
for (const obj in HTML_CONTENT) {
if (HTML_CONTENT[obj].path == "contact.html") {
decodedHTMLcontact = base64.decode(HTML_CONTENT[obj].content);
} else if (HTML_CONTENT[obj].path == "index.html") {
decodedHTMLindex = base64.decode(HTML_CONTENT[obj].content);
} else if (HTML_CONTENT[obj].path == "portfolio.html") {
decodedHTMLportfolio = base64.decode(HTML_CONTENT[obj].content);
}
}
tests = function (html, css) {
describe('HTML Elements tests that should pass for contact.html', function () {
let $ = cheerio.load(decodedHTMLcontact);
describe('HTML Elements that should exist in contact.html', function () {
it('should contain a header element', function () {
expect($('body').find('header').length).to.equal(1);
});
it('should contain a section element', function () {
expect($('body').find('section').length).to.equal(1);
});
it('should contain several anchor elements', function () {
expect($('nav').find('a').length).to.be.at.least(3, 'You need an additional anchor elements for your navigation elements');
});
it('should contain an h1 element', function () {
expect($('body').find('h1').length).to.equal(1);
});
it('should contain a form element', function () {
expect($('body').find('form').length).to.equal(1);
});
it('should contain a footer element', function () {
expect($('body').find('footer').length).to.equal(1);
});
});
Here is the execution file for the Mocha tests:
const Mocha = require('mocha');
// Instantiate a Mocha instance.
const mocha = new Mocha();
const HW_PORTFOLIO_PATH = './server/05-run-testing-suite/HW-Week1-portfolio-wireframe/HW-1-portfolio.js';
function homeworkRouter(contentObj, repo) {
switch (repo) {
case "Basic-Portfolio":
mocha.addFile(HW_PORTFOLIO_PATH);
break;
case "HW-Wireframe":
mocha.addFile('./server/05-run-testing-suite/HW-Week1-portfolio-wireframe/HW-1-wireframe.js');
break;
default:
console.log("No homework provided");
break;
}
}
module.exports = {
// Run the tests and have info about what can be returned
runTests: function(contentObj, repo) {
homeworkRouter(contentObj, repo);
console.log("Content Object", contentObj);
console.log("Repo", repo);
mocha.run()
.on('fail', function (test, err) {
console.log('Test fail');
console.log(err);
})
.on('end', function () {
console.log('All done');
});
}
}
Solutions we've come up with involve using vm(), setting data into globals, and/or building up and tearing down files. I'd like a solution that it's much more efficient and doesn't pollute global.

sinon stub fails for promise functions if not exported within class

I'm trying to get sinon.stub to work for async function. I have created promiseFunction.js:
let functionToBeStubbed = async function() {
return ("Text to be replaced by stub.");
};
let promiseFunction = async function() {
return(await functionToBeStubbed());
};
module.exports = {
promiseFunction: promiseFunction,
functionToBeStubbed: functionToBeStubbed
};
and test promiseFunction.spec.js:
let functionstobestested = require('./promiseFunction.js');
describe('Sinon Stub Test', function () {
var sandbox;
it('should return --Text to be replaced by stub.--', async function () {
let responsevalue = "The replaced text.";
sandbox = sinon.sandbox.create();
sandbox.stub(functionstobestested, 'functionToBeStubbed').resolves(responsevalue);
//sandbox.stub(functionstobestested, 'functionToBeStubbed').returns(responsevalue);
let result = "Empty";
console.log(`BEFORE: originaldata = ${result}, value = ${responsevalue}`);
result = await functionstobestested.promiseFunction();
console.log(`AFTER: originaldata = ${result}, value = ${responsevalue}`);
expect(result).to.equal(responsevalue);
sandbox.restore();
console.log("AFTER2: Return value after restoring stub: " + await functionstobestested.promiseFunction());
});
});
when running the test, I will get
test failure
If I modify export slightly, it still fails:
var functionsForTesting = {
promiseFunction: promiseFunction,
functionToBeStubbed: functionToBeStubbed
};
module.exports = functionsForTesting;
I do not understand why this test fails, as it should pass. If I change the way I export functions from promiseFunction.js - module, the test pass correctly. Revised promiseFunction.js:
const functionsForTesting = {
functionToBeStubbed: async function() {
return ("Text to be replaced by stub.");
},
promiseFunction: async function() {
return(await functionsForTesting.functionToBeStubbed());
};
module.exports = functionsForTesting;
Test pass
What's wrong in my original and modified way to export functions?

Resources