I have a service layer that calls a database layer where a query is run. I am trying to stub the data layer returning a value but I keep getting this error
TypeError: User.find(...).exec is not a function.
I am using the bluebird module and am also using sinon for stubbing
//Service Layer
var dbLayer = require('../dbLayer');
exports.getUsers = function (req, res) {
dbLayer.GetUsersThatNeedToBeApproved(req.body.domain)
.then(function (data) {
res.json(data);
})
.catch(function(error){
routesLogger.logError(req.session.user.role, "getUsers", error);
res.status(400).send({error: StatusCodes.DBERROR});
});
};
//DB Layer
module.exports.GetUsersThatNeedToBeApproved = function (domain) {
return new Promise.resolve(User.find({$and: [{'domain.upgradeRequest': true}, {'domain.access': constants.ACCESSPRIVATE}, {'domain.name': domain}]}).exec())
.then(function (data) {
return data;
}).catch(function (error) {
routesLogger.logError("userDAL", "GetUsersThatNeedToBeApproved", error);
return error;
});
This is my test case
describe("Suite to get users in portal that need to be approved",function(){
var request = null;
var response = httpMocks.createResponse();
it("Should get a list of all users that need to be approved for a specific domain",function(done){
request = {
session: {
user: {
domain:{
name:'domain'
},
email: 'testUser#test.com',
role: 'Admin'
}
}
};
var expectedFindResponse = [
{
email: "test#xxx.com",
role: "T",
domain:{
upgradeRequest:true,
access:'private',
name:'domain'
}
},
{
"email": "test1#xxx.com",
"role": "T",
domain:{
upgradeRequest:true,
access:'private',
name:'domain'
}
}
];
var find = sinon.stub(mongoose.Model, "find").returns(Promise.resolve(expectedFindResponse));
admin.getUsers(request, response);
var responseData = response._getData();
});
});
Related
I want to make 100% coverage on this function with node-tap but I can't mock the error part, it always throw
Cannot find module 'create' Require stack: - /home/mptr8/Code/Projects/me/fastify-example/fastify-postgres/test/integration.js
But I have create function on my query.js file, what do I do wrong here? Why it doesn't invoke the method?
t.mock("../query.js", {
create: () => {
throw new Error();
},
});
I also try this combination, because query.js are dependent on db.js. Now the mock error gone but still I'm not getting the error throw from my fastify.inject.
t.mock("../db.js", {
"../query.js": {
create: () => { throw new Error() },
},
});
app.post("/", async (request, reply) => {
try {
const { body } = request;
const book = create(body.title);
reply.send(book);
} catch (error) {
// this part are not covered
reply.code(500).send({ message: "internal server error" });
}
});
here are my complete code. You can see the full code on this github repository.
// server.js
const fastify = require("fastify");
const {
migration,
create,
} = require("./query");
const db = require("./db");
function build(opts = {}) {
const app = fastify(opts);
migration();
app.post("/", async (request, reply) => {
try {
const { body } = request;
const book = create(body.title);
reply.send(book);
} catch (error) {
reply.code(500).send({ message: "internal server error" });
}
});
app.addHook("onClose", (_instance, done) => {
db.close();
done();
});
}
module.exports = build;
// db.js
const { Pool } = require("pg");
const pool = new Pool({
connectionString:
"postgresql://postgres:postgres#localhost:5432/fastify_postgres?schema=public",
});
module.exports = {
query: (text, params) => pool.query(text, params),
close: () => pool.end(),
};
// query.js
const db = require("./db");
async function migration() {
await db.query(`
CREATE TABLE IF NOT EXISTS books (
id serial PRIMARY KEY,
title varchar (255) NOT NULL
)
`);
}
async function create(title) {
return await db.query("INSERT INTO books (title) VALUES ($1)", [title]);
}
module.exports = { migration, create };
// test.js
const tap = require("tap");
const fastify = require("../server");
tap.test("coba", async (t) => {
const app = await fastify();
t.test("should success create books", async (t) => {
const response = await app.inject({
method: "POST",
url: "/",
payload: {
title: "Hello,World!",
},
});
t.equal(response.statusCode, 200);
});
t.test("should throw error", async (t) => {
const app = await fastify();
// it doesn't throw the error :((
t.mock("../query.js", {
create: () => {
throw new Error();
},
});
const response = await app.inject({
method: "POST",
url: "/",
payload: {
title: "Hello,World!",
},
});
t.equal(response.statusCode, 500);
// call app close on last test child to close app and db properly
app.close();
});
});
You should use the returned value by the t.mock function:
const build = t.mock({
"../server": {
"./query.js": {
create: () => { throw new Error() },
}
}
})
const app = await build({})
I am new to Node.js technology and facing some issues in recursive concept.
I have a main.js which contains list of username and a soap method call Soap.js contains soap method which will fetch email id from username.
------------- Main.js ----------------
'use strict'
var emailService = require('./emailService .js').emailService ;
var emailService1 = new emailService ();
var emailList = [];
var psList = ['1062','10465','10664','10681'];
emailService1.helpdeskEmailService(psList, 'abcabc', 'abcabc', function(err,result) {
console.log('in service -------------------------');
if (err) {
console.log("Error while api call :: " +err);
} else {
console.log("response from soap service - " + result);
}
});
console.log('my email list' +result);
------------- SoapService.js ----------------
'use strict'
var c_instancename = '';
var soap = require('soap');
var l_args;
var c_url = "http://airinmsbmcarmt.lntinfotech.com/arsys/WSDL/public/172.21.103.136/zlandt:FetchEmailID";
class emailService {
constructor(p_instanceName) {
c_instancename = p_instanceName;
}
helpdeskEmailService (ps_number,p_username,p_password,p_callback) {
var l_header = {
'authentication': '',
'locale': '',
'timeZone': '',
'AuthenticationInfo': {
'userName': p_username,
'password': p_password
}
}
soap.createClient(c_url, function(err, client) {
//var soapheader = l_header;
client.addSoapHeader(l_header);
var l_args = {LoginID:ps_number};
client.EmailID(l_args, function(err, result) {
if(err) {
console.log('error page');
} else {
console.log('my resultttttttt in soap...');
p_callback(err,result);
}
});
});
}
}
module.exports.emailService = emailService;
In this case, I'm getting late response from soap service.
Can I have sync call for webservice because I am getting NULL values for emailList.
I have a main.js which contains list of username and a soap method call.
Soap.js contains soap method which will fetch email id from username.
You can return a promise from your service and if you're using Node 8.0+ you can also make the call synchronous. If not at least it makes it easier to deal with asynchronous call.
helpdeskEmailService (ps_number,p_username,p_password) {
var l_header = {
'authentication': '',
'locale': '',
'timeZone': '',
'AuthenticationInfo': {
'userName': p_username,
'password': p_password
}
}
return new Promise (function (resolve, reject) {
soap.createClient(c_url, function(err, client) {
//var soapheader = l_header;
client.addSoapHeader(l_header);
var l_args = {LoginID:ps_number};
client.EmailID(l_args, function(err, result) {
if(err) {
console.log('error page');
reject(err);
} else {
console.log('my resultttttttt in soap...');
resolve(result);
}
});
});
}
}
// You can then call like this
var promise = emailService1.helpdeskEmailService(psList, 'abcabc', 'abcabc');
promise.then((result) => {
console.log("response from soap service - " + result);
}).catch ( (err) => {
console.log("Error while api call :: " +err);
});
You can also use await to make this synchronous (depending on the version of Node you're using):
async function waitForresult() {
try
{
const result = await emailService1.helpdeskEmailService(psList, 'abcabc','abcabc');
console.log(result);
} catch (e) {
console.log('Error occurred: ' + e);
}
};
waitForresult();
i am completely newbie in node.js, and trying learn how it actually works. I know that by default all node.js function calls are asynchronous. Now i need LDAP authentication in my application where i need wait for the server response to check whether the user credentials are right or wrong.The ldap part is working fine but i am not sure on how to return data from a function call in synchronous way. below is the part of my code.
router.js
var express = require('express');
var router = express.Router();
var tools = require('./authenticateUser');
router.post('/authenticateUser', function(req, res) {
// In the below line i am calling the method which
// should return the userDN (a string)
tools.searchUser(req.body.user, req.body.passwd);
res.render('home.jade');
});
authenticateUser.js
module.exports = {
searchUser : function (username, password) {
adminDN = *************;
adminPassword = '*********';
baseDN = '***';
var ldap = require('ldapjs');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var adminClient = ldap.createClient({
url: '*******'
});
var opts = {
filter: '(&(objectClass=userProxyFull)(sAMAccountName=' + username + '))',
scope: 'sub',
attribute: ['sAMAccountName']
};
console.log('--- going to try to connect user ---');
try {
adminClient.bind(adminDN, adminPassword, function (error) {
if (error) {
console.log(error.message);
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('adminClient disconnected');
}
});
} else {
// Searching Client ID in LDS
adminClient.search(baseDN, opts, function (error, search) {
console.log('Searching.....' + userDN);
search.on('searchEntry', function (entry) {
if (entry.object) {
// Here i need to return the object back
//to the router.js from where i call in a synchronous way
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
}
});
}
});
search.on('error', function (error) {
console.error('error: ' + error.message);
});
});
}
});
} catch (error) {
console.log(error);
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('client disconnected');
}
});
} finally {
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('client disconnected');
}
});
}
},
};
You have to pass res.render('home.jade') as a function(the callback) to your searchUser function.
It should look like
tools.searchUser(req.body.user,
req.body.password,
res}
)
searchUser function
searchUser : function (username, password,res) {
...
finally(){
res.render('home.jade');
}
}
In the function below I'm retrieving an entity by id from a Mongo DB using Mongoose.
var Recipe = require('models/recipe').model;
exports.findById = function(req, res) {
Recipe.findById(req.params.id, function(err, docs) {
if (err) {
console.error(err);
res.status(500).send(err);
}
res.json(docs);
});
}
I would like to use Jasmine to test if I return a 500 when an error has been raised and I want to test if I put the JSON entity on the reponse when everything was successful.
I solved it by creating a closure containing the callback function, the advantage is that it's also reusable:
exports.jsonCallback = function(res) {
return function(err, docs) {
if (err) {
console.error(err);
res.status(500).send(err);
}
res.json(docs);
}
};
This allowed me to mock the response in a Jasmine test for the closure:
var resMock = {
status : function(status) {
return {
send : function() {}
}
},
json : function(json) {}
};
var mongooseCallback = require('controllers/callbacks/mongooseCallback').jsonCallback(resMock);
describe("when a json callback has been called", function() {
it("should return status 500 when an error has been raised", function() {
var returnStatusMock = { send : function() {}};
var errorMessage = "errorMessage";
spyOn(resMock, 'status').and.returnValue(returnStatusMock);
spyOn(returnStatusMock, 'send');
mongooseCallback(errorMessage, null);
expect(resMock.status).toHaveBeenCalledWith(500);
expect(returnStatusMock.send).toHaveBeenCalledWith(errorMessage);
});
it("should return the corresponding document in a json format", function() {
spyOn(resMock, 'json');
var jsonString = "{ 'name' : 'value' }";
mongooseCallback(null, jsonString);
expect(resMock.json).toHaveBeenCalledWith(jsonString);
});
});
Thank in advance for the help.
While using Bluebird promises, I have a series of promises running. During the last promise, I want to run one function multiple times for each object in an array.
Below there is the pseudocode:
var userArray = [
{
name: "John",
email: "John#email.com"
},
{
name: "Jane",
email: "jane#email.com"
}];
var functionOne = function() {
//returns Promsie object
};
var functionTwo = function() {
//returns promise object
};
var createUser = function(user) {
return User.findOrCreate({email: user.email},{
name: user.name,
email: user.email
});
};
functionOne()
.then(functionTwo)
.each(createUser(userArray))
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
I know I'm not using the each function correctly. What's the correct way to implement this using Bluebird?
As I understand you want to take some asynchronous actions for elements from array. Then please check the following example:
var Promise = require('bluebird');
function createUsersFromArray(userArray){
return Promise.each(userArray, function(signleUser){
return createUserFunction(signleUser);
});
}
or
return Promise.each(userArray, createUserFunction);
functionOne()
.then(functionTwo)
.then(function(){
return createUsersFromArray(userArray);
})
//or just .then(createUsersFromArray) if functionTwo return this array
.then(function(createdUsers){
//here you may retrieve users and make some magic with them
console.log(createdUsers);
})
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
I also recommend using "all" instead of "each"
Check the examples below:
return Promise.all(userArray.map(function(singleUser){
return doSomethingWithUser(singleUser);
}));
or
return Promise.all(userArray.map(doSomethingWithUser));
'all' will notify you if all the actions are taken correctly.
How to use promises (best practice):
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
https://blog.domenic.me/youre-missing-the-point-of-promises/
The most straightforward implementation:
functionOne()
.then(functionTwo)
.then(function(){
return bluebird.each(userArray, createUser);
})
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
You should use .map instead of .each if you want to access the results of all of those creates.
Thanks #Roman #Yuri for the help! My now working code is below:
var userArray = [
{
name: "John",
email: "John#email.com"
},
{
name: "Jane",
email: "jane#email.com"
}];
var functionOne = function() {
//returns Promise object
};
var functionTwo = function() {
//returns Promise object
};
var createUser = function(singleUser) {
//returns Promise object containing creating User
};
functionOne()
.then(functionTwo)
.then(function() {
return Promise.map(userArray, createUser);
})
.then(function onComplete(response) {
console.log("Complete:" + JSON.stringify(response));
})
.catch(function onError() {
console.log("Um...it's not working");
});