Sinon mocking with Sequelize - node.js

I have the following nodejs function using Sequelize:
var processDatabase = function (dbConnection, schema, recordsets) {
var myLogTable = dbConnection.define(schema.tableName, schema.myLogSchema, schema.myLogSchemaIndex);
myLogTable.sync({
force: false,
freezeTableName: true,
logging: console.log
}).then(function () {
console.log('Table synced...');
for (k = 0; k < recordsets.length; k++) {
var query = "Some query";
dbConnection.query(
query, {
type: dbConnection.QueryTypes.SELECT
}
)
.then(function (results) {
console.log('MYSQL Selection Done');
})
.catch(function (err) {
console.log('MYSQL Error: ' + err.message);
});
}
}).catch(function (err) {
console.log('MYSQL Sync Error: ' + err.message);
});
};
I am new to mocking and do not especially know how to test the catch part.
This is my unit test which I can come up with, but I do not know how a call to sync can go to the catch part:
describe('when call processDatabase', function () {
it('should process successfully when sync fails', function (done) {
seqConnection.define = function (tableName, schema, schemaIndex) {
return mockMyLogModel;
};
processProfilesNotMapped(seqConnection, {
tableName: 'SomeTable',
myLogSchema: myLogSchema,
myLogSchemaIndex: myLogSchemaIndex
}, []);
done();
})
});
How would I write my mocking so that I can test both catch and also then so that they can be covered?

You need to defer an exception in your mock, since "sync" is using promises. You can use q library or any other. This way when you execute the sync function it will go to the catch section
Example using q:
describe('when call processDatabase', function () {
it('should process successfully when sync fails', function (done) {
seqConnection.define = function (tableName, schema, schemaIndex) {
const mock = {
sync: function(){
const deferred = q.defer();
deferred.reject(new Error('Some error'));
return deferred.promise;
}
}
return mock;
};
expect(
function(){
cmdManager.execute("getProfileDummy","hosar#gmail.com")
}
).to.throw(Error);
processProfilesNotMapped(seqConnection, {
tableName: 'SomeTable',
myLogSchema: myLogSchema,
myLogSchemaIndex: myLogSchemaIndex
}, []);
done();
})
});

Related

how can I get, fetched data from neo4j?

I was trying to fetch data from neo4j database.
Here is my function for getting data from database which I found on their official website and have modified it little bit:
function receiveDataFromDB() {
var neo4j = require("neo4j-driver");
var driver = neo4j.driver(
"neo4j://localhost",
neo4j.auth.basic("neo4j", "something")
);
console.log(driver);
var session = driver.session({
database: "neo4j",
defaultAccessMode: neo4j.session.READ,
});
session.run(`match (n) return n`).subscribe({
onKeys: (keys) => {
console.log(keys);
},
onNext: (record) => {
console.log(record.get("n"));
},
onCompleted: () => {
session.close(); // returns a Promise
},
onError: (error) => {
console.log(error);
},
});
}
So this function only console.log-s it:
but I want it to use outside the function. I've tried returning return record.get("n") inside onNext but got errors instead.
You can simply use the try-catch equivalent of your query, like this:
try {
const result = session.run(`match (n) return n`);
} catch (error) {}
finally {
session.close();
}
Or try setting your result in a variable, like this:
const result = [];
session.run(`match (n) return n`).subscribe({
onKeys: (keys) => {
console.log(keys);
},
onNext: (record) => {
result.push(record.get("n"));
},
onCompleted: () => {
session.close(); // returns a Promise
},
onError: (error) => {
console.log(error);
},
});

Async series is not calling properly

I have 3 function has to call in series one after the other. but first function is exeucting and in between second and third are executing.
var tasklist=[api_hit,delay,mysql_check];
if(task_list.length>0){
async.series(
tasklist,
function(err, response) {
console.log(err);
console.log(response);
results.data=response;
results.message="Completed";
console.log(results);
}
);
}
Internal functions:
function api_hit(callback){
console.log("Inside api");
var ele=task_list[0];
var apidata=[];
var msg={'data':[]};
apiinfo.forEach((item,key)=>{
if(item.Method_name==ele.Parameters){
//Here checking random Int value
if(item.Value=="{{$randomInt}}"){
item.Value = generate(25);
}
apidata.push(item);
}
});
var data=[];
data['api']=apidata;
apiModel.validateAPI(data,function(res){
console.log("result api");
msg.data=res;
msg.case='api_hit';
callback(msg);
});
}
function delay(callback){
console.log("Inside delay");
var msg={'data':[]};
global_vars.sleep(1000);
msg.data='success';
msg.case='task';
console.log("after delay");
callback(msg);
}
function mysql_check(callback){
console.log("inside mysql");
var ele=task_list[2];
var dbdata=[];
var msg={'data':[]};
dbchecks.forEach((item,key)=>{
if(item.query_id==ele.Parameters){
console.log(item.query+" ::: "+ele.Parameters);
dbdata.push(item);
}
});
data['dbdata']=dbdata;
apiModel.checkmysql(data,function(err,res){
if(err) throw err;
console.log("inside mysql res");
msg.data=res;
msg.case='task2';
callback(msg);
});
}
My intention is to call these function after completing of others and all the results has to process in a single variable. but in api_hit method when it is executing another function inside of it then delay()(second function of async) is executing. how to stop this and make it in sequence. thanks in advance.
The first argument to the callback function is the error, pass null in case of success.
'use strict'
const async = require('async')
function api_hit(callback) {
setTimeout(() => {
console.log('Completed api_hit')
callback(null, 'api_hit')
}, 1000)
}
function delay(callback) {
setTimeout(() => {
console.log('Completed delay')
callback(null, 'delay')
}, 100)
}
function mysql_check(callback) {
setTimeout(() => {
console.log('Completed mysql_check')
callback(null, 'mysql_check')
}, 500)
}
var tasklist = [api_hit, delay, mysql_check];
if (tasklist.length > 0) {
async.series(
tasklist,
function (err, response) {
console.log(err);
console.log(response);
}
);
}
Doc link: https://caolan.github.io/async/docs.html#series

TypeError: Cannot read property 'drop' of undefined

I am doing mocha testing. I have to connect to MongoDB in before function and I need to remove the documents in the collection in after function.
before("authenticate user", async () => {
mongoose.connect('mongodb://localhost:27017/mo-identity')
db = mongoose.connection;
db.once('open', function() {
console.log('We are connected to test `enter code here`database!')
})
.on('error', ()=>{console.error.bind(console, 'connection error')})
})
after(()=>{
db.User.drop()
})
Above is my code.
user is a collection. While executing this code I am getting this error TypeError: Cannot read property 'drop' of undefined. Help me out this error
I am afraid that you cannot drop collection like that:
db.User.drop()
If you want to drop collection then you should do something like this:
mongoose.connection.db.dropCollection('User', function(err, result) {...});
As #drinchev said, you can remove all documents by doing this :
Model.remove({}, function(err) {
console.log('collection removed')
});
In your case :
after(()=>{
db.User.remove({}, (err) => {
if (err) throw err;
});
})
Hope it helps.
/*import mongoose connection*/
const { mongodb } = require("./database/mongodb");
const collectionDrop = (collection) => {
return new Promise(function (resolve, reject) {
mongodb.connection.dropCollection(collection, function (err, result) {
var success = `\n🗑️ DropCollection '${collection}': Success!`;
var failure = `\n🗑️ DropCollection '${collection}' Error! ${err}`;
if (err) {
//if it doesn't exist, it's not an error.
if (err.message.includes("not found")) {
resolve(success);
} else {
reject(failure);
}
}
if (result) {
resolve(success);
}
resolve(success);
});
});
};
(() => {
try {
(async () => {
const collections = ["users", "aaaa"];
for (let i = 0; i < collections.length; i++) {
const result = await collectionDrop(collections[i]);
console.log(result);
}
/* In my case, I'm using it as a "pretest" script, in package.json.
Then I close the process to proceed with the test */
process.exit(0);
})();
} catch (error) {
console.trace(error.message);
}
})();

Stub doesn't return a value

I'm using Mocha as test runner, Chai for assertion and Sinon.
I'm having trouble using sinon, I have the following function that I want to test in PrestigeQuoteService.js file
find: function (criteria) {
return PrestigeQuote.find(criteria)
.populate('client')
.populate('vehicle')
.populate('quoteLogs');
},
and here is my test case
describe('find()', function () {
describe('prestige quote found', function () {
before(function () {
sandbox = sinon.sandbox.create();
var mockChain = {
populate: function () {
return this;
}
};
sandbox
.stub(PrestigeQuote, 'find').returns(mockChain);
});
it('should return a particular quote', function (done) {
PrestigeQuoteService.find({id: 1}, function (err, result) {
result.should.exist;
done();
});
});
after(function () {
sandbox.restore();
});
});
});
yet I get this error, even thought I have done() and should return value by default.
Error: timeout of 10000ms exceeded. Ensure the done() callback is being called in this test.
Use time out inside it() function .
describe('find()', function () {
describe('prestige quote found', function () {
before(function () {
sandbox = sinon.sandbox.create();
var mockChain = {
populate: function () {
return this;
}
};
sandbox
.stub(PrestigeQuote, 'find').returns(mockChain);
});
it('should return a particular quote', function (done) {
this.timeout(50000);
PrestigeQuoteService.find({id: 1}, function (err, result) {
result.should.exist;
done();
});
});
after(function () {
sandbox.restore();
});
});
});
I solved it by adding a return in mockChain
describe('prestige quote found', function () {
before(function () {
sandbox = sinon.sandbox.create();
var err = null;
var mockChain = {
populate: function () {
return this;
},
return:function () {
return {};
}
};
sandbox
.stub(PrestigeQuote, 'find').returns(mockChain);
});
it('should return a particular prestige quote', function (done) {
PrestigeQuoteService.find({id: 1}, function (result) {
result.should.exist;
});
done();
});
after(function () {
sandbox.restore();
});
});

Trouble to synchronise promises in Node.js using Q

I am currently doing an API in Node.JS with the framework Sails.js. I am using promises for the first time and I have some troubles to sync my promises like I want.
My main function is the following :
createCard: function(req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount())
.then(function cardCreated() {
res.send(200, {
msg: 'Card created'
});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
Obviously I can't add a credit card to a stripe account if the user doesn't have one.
The function checkIfUserHasStripeAccount() checks if the account exists and if not, create it.
Here is the code for this part :
function checkIfUserHasStripeAccount(user) {
var deferred = q.defer();
if (!user.idStripe) {
createStripeAccountToUser(user)
.then(function(savedUser) {
deferred.resolve(savedUser);
})
.catch(function(err) {
deferred.reject(err);
})
} else {
deferred.resolve(user);
}
return deferred.promise;
}
function createStripeAccountToUser(user) {
var deferred = q.defer();
var jsonUserToCreate = {
description: user.firstname + ' ' + user.surname,
email: user.email
};
stripe.customers.create(jsonUserToCreate, function(err, customer) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
} else {
user.idStripe = customer.id;
user.save(function(err, savedUser) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
}
deferred.resolve(savedUser);
});
}
});
return deferred.promise;
}
The problem is that the .then(addCreditCardToStripeAccount()) is executed before checkIfUserHasStripeAccount() is finished.
I can't figure out why. I thought the .then(addCreditCardToStripeAccount()) would only be executed if it received a reject or resolve.
You are correct in your line of thought.
The problem is that you are invoking your function instead of referencing it:
.then(addCreditCardToStripeAccount())
should be:
.then(addCreditCardToStripeAccount)
I expect this to work:
createCard: function (req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount)
.then(function cardCreated(){
res.send(200, {msg: 'Card created'});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
For future, note that the () after the function name invokes the function, as order of execution in JS will evaluate it first due to being inside the then's ().
In promise chains, always invoke only the first function. Example:
function first () { /*...*/ } // All return promise.
function second() { /*...*/ }
function third () { /*...*/ }
first() // Invoked
.then(second) // Not invoked. second() will have been bad here.
.then(third);

Resources