I'm trying to learn how to use NodeUnit to test my NodeJs code. Ive written the following code, however each time I run the test, the result is OK: 0 assertions, no matter whether the input parameter is valid or not. Can anyone explain why this doesn't work and how I can fix it?
auth.class.js: This function accepts a user ID and returns a username.
exports.username = function(uid, callback) {
db.query('SELECT username FROM ul_logins WHERE id=?', uid, function(err, results){
if (err) throw new Error(err);
if(results.length > 0)
{
callback(null, results[0].username);
}
else
throw new Error("No results.");
});
};
authtest.js: This test will run successful every time, no matter what the uid is, and count 0 assertions.
var auth = require('./auth.class.js');
exports['username'] = function (test) {
auth.username(1, function(err, data){
return test.equal(data, "joe#example.com");
});
test.done();
};
The function you are testing is asynchronous (see the rewritten function below). You need to put the test.done() in the callback function:
exports['username'] = function (test) {
test.expect(2);
auth.username(1, function (err, data) {
test.ifError(err);
test.equal(data, 'joe#example.com');
test.done();
});
};
In your version, test.done gets called before the callback to auth.username is called. Use test.expect to tell nodeunit how many asserts it should receive before test.done is called.
You have a serious problem in your auth.username function. You should not throw in asynchronous code since a try-catch cannot be used to catch the error, leading to uncaught exceptions. You should always pass errors in asynchronous code to a callback as the first argument (convention). Your function should look like:
exports.username = function (uid, callback) {
var query = 'SELECT username FROM ul_logins WHERE id=?';
db.query(query, uid, function (err, results) {
if (err) {
return callback(err);
}
if (results.length === 0) {
return callback(new Error('No user found.'));
}
callback(null, results[0].username);
});
};
Note that errors are handled first (keeps the code neat), and callback calls in the branches are returned to avoid calling the callback multiple times (using else adds a level of indentation).
I get the impression that you are new to Node, and I remember having difficulty over this point too. Consider any function that does something over the network as asynchronous. This could take a long time, so to avoid blocking the process Node gets the OS to handle the task, and takes a callback to call at some point in the future when the OS gives it a result. This is why Node relies so heavily on callbacks. It leaves the Node process free to do other things (like call test.done in your question) while it waits. It also means that try-catch (which can only catch errors thrown in the same 'tick') no longer works. The conventional way to handle errors is to call the callback with the error as the first argument. All other arguments are for actual results.
Related
I am starting with nodejs and read basics on callback, here i have a code,
exports.handler = (event, context, callback) => {
var bx = require('barcode-js');
// Set default values.
var params = {
input: './1.bmp',
type: 'qrcode'
};
bx.analyze(params, function (err, results) {
if (err) {
callback('There was an error processing this image: ' + err)
}
results.forEach(function(result) {
callback(null,'Result type :' + result.type + '\t'+'Value: '+result.value);
});
});
};
what is happening bx.analyze(params, function (err, results) { in this line. why can't we just use bx.analyze(params) ?
The second parameter is function. Called a callback.
When you execute an async function, you can't wait for its returned value:
var result = bx.analyze(params); //you can't do this
So you tell the function that when it finishes its job, just call the callback (the function you passed as second parameter).
//so `analyze()` will call your passed function rather than `return` the result
//`err` will contain the error object if anything wrong happened in the analyze() function
//`results` will contain result if everything was fine
bx.analyze(params, function (err, results) {
if (err)
callback('There was an error processing this image: ' + err)
});
I strongly recommend you to learn how async code works in javascript. You can't learn Nodejs untill then..
Update:
In your code, the function handler is an async function so it takes a callback as a parameter (Just like analyze()).
When this function done with its job, it calls the callback.
Now in your code, it is called 2 times:
1) When an error occured, this function will call the callback and pass the error into it:
if (err) {
callback('There was an error processing this image: ' + err); //its passing "err" returned from analyze()
}
2) When everything goes well, it passes result set:
callback(null, 'Result type :' + result.type + '\t'+'Value: '+result.value); //the 1st parameter is being passed as "null" because there is no error in it, and second parameter passes the result
This is callback function which make the code asynchronous.
Means you are passing a function as argument to your bx.analyze(params) method. This callback method is executed once your bx.analyze(params) is finished, so its not blocking the other code, making the code asynchronous.
If you need how this call back is executed , then you have to look for Event loop, search it in Google,have lots of documentation.
if we use bx.analyze(params) then it is blocking (synchronous) code. event loop stop until bx.analyze(params) did not return any value and
there is no error handling.
if we use bx.analyze(params, function (err, results) { }); then it is asynchronous (non-blocking) code. event loop will not wait for returning value it goes to next statement and when bx.analyze(params, function (err, results) { return the callback event loop process it.
There is error handlation is also done
for deep understanding see this video https://www.youtube.com/watch?v=8aGhZQkoFbQ
router.post("/application_action", function(req,res){
var Employee = req.body.Employee;
var conn = new jsforce.Connection({
oauth2 : salesforce_credential.oauth2
});
var username = salesforce_credential.username;
var password = salesforce_credential.password;
conn.login(username, password, function(err, userInfo, next) {
if (err) { return console.error(err); res.json(false);}
// I want this conn.query to execute first and then conn.sobject
conn.query("SELECT id FROM SFDC_Employee__c WHERE Auth0_Id__c = '" + req.user.id + "'" , function(err, result) {
if (err) { return console.error(err); }
Employee["Id"] = result.records[0].Id;
});
//I want this to execute after the execution of above query i.e. conn.query
conn.sobject("SFDC_Emp__c").update(Employee, function(err, ret) {
if (err || !ret.success) { return console.error(err, ret);}
console.log('Updated Successfully : ' + ret.id);
});
});
I have provided my code above. I need to modify Employee in the conn.query and use it in conn.sobject. I need to make sure that my first query executes before 2nd because I am getting value from 1st and using in the 2nd. Please do let me know if you know how to accomplish this.
New Answer Based on Edit to Question
To execute one query based on the results of the other, you put the second query inside the completion callback of the first like this:
router.post("/application_action", function (req, res) {
var Employee = req.body.Employee;
var conn = new jsforce.Connection({
oauth2: salesforce_credential.oauth2
});
var username = salesforce_credential.username;
var password = salesforce_credential.password;
conn.login(username, password, function (err, userInfo, next) {
if (err) {
return console.error(err);
res.json(false);
}
// I want this conn.query to execute first and then conn.sobject
conn.query("SELECT id FROM SFDC_Employee__c WHERE Auth0_Id__c = '" + req.user.id + "'", function (err, result) {
if (err) {
return console.error(err);
}
Employee["Id"] = result.records[0].Id;
//I want this to execute after the execution of above query i.e. conn.query
conn.sobject("SFDC_Emp__c").update(Employee, function (err, ret) {
if (err || !ret.success) {
return console.error(err, ret);
}
console.log('Updated Successfully : ' + ret.id);
});
});
});
});
The only place that the first query results are valid is inside that callback because otherwise, you have no way of knowing when those asynchronous results are actually available and valid.
Please note that your error handling is unfinished since you don't finish the response in any of the error conditions and even in the success case, you have not yet actually sent a response to finish the request.
Original Answer
First off, your code shows a route handler, not middleware. So, if you really intend to ask about middleware, you will have to show your actual middleware. Middleware that does not end the request needs to declare next as an argument and then call it when it is done with it's processing. That's how processing continues after the middleware.
Secondly, your console.log() statements are all going to show undefined because they execute BEFORE the conn.query() callback that contains the code that sets those variables.
conn.query() is an asynchronous operation. It calls its callback sometime IN THE FUTURE. Meanwhile, your console.log() statements execute immediately.
You can see the results of the console.log() by putting the statements inside the conn.query() callback, but that is probably only part of your problem. If you explain what you're really trying to accomplish, then we could probably help with a complete solution. Right now, you're just asking questions about flawed code, but not explaining the higher level problem you're trying to solve so you're making it hard for us to give you the best answer to your actual problem.
FYI:
app.locals - properties scoped to your app, available to all request handlers.
res.locals - properties scoped to a specific request, available only to middleware or request handlers involved in processing this specific request/response.
req.locals - I can't find any documentation on this in Express or HTTP module. There is discussion of this as basically serving the same purpose as res.locals, though it is not documented.
Other relevants answers:
req.locals vs. res.locals vs. res.data vs. req.data vs. app.locals in Express middleware
Express.js: app.locals vs req.locals vs req.session
You miss the basics of the asynchronous flow in javascript. All the callbacks are set to the end of event loop, so the callback of the conn.query will be executed after console.logs from the outside. Here is a good article where the the basic concepts of asynchronous programming in JavaScript are explained.
I try to understand how I can stop or exit on error in a Nodejs route.
In the code below, I check if header UID is sent and if the fiels group is also sent.
The problem is that nodejs continues to execute the rest of the code even if I use res.end () + return; I wish that Node Js stop everything when I display an error. Perhaps because I do not know much in Node Js I myself take it badly and I have to work otherwise. Can you explain to me and give me an example of how I should do?
var uid;
var group;
if (typeof req.headers['uid'] == 'undefined' || req.headers['uid'] == '') {
res.status(404);
res.json('user_id not set');
res.end();
return;
}
else
{
uid = req.headers['uid'];
User.find({_id:uid}).exec(function(err, data)
{
if(err){
res.status(404);
res.json('user not found');
res.end();
return;
}
});
}
if (typeof req.body.group == 'undefined' || req.body.group == '') {
res.status(500);
res.json('group not defined');
res.end();
return;
}
else
{
group = req.body.group;
}
it is unclear exactly what you mean by "node js stop everything". If you want to stop the entire nodejs process, you can use process.exit().
If you're trying to keep some code after your error from executing and your error occurs in an async callback, then you can't do that. The other code has already executed.
If you want to serialize asynchronous operations so that you complete one async operation BEFORE you decide whether to start the next operation, then you will need to code that differently. You will need to execute the second block of code from within the completion callback of the first async operation.
One aspect of your code that you may not understand is that this block is asynchronous:
User.find({_id:uid}).exec(function(err, data)
{
if(err){
res.status(404);
res.json('user not found');
res.end();
return;
}
});
The callback you pass to .exec() is called sometime LATER. Meanwhile, the rest of your JS has already executed. In addition, when you do a return from within that callback that doesn't return from your outer function, it only returns from that callback function back into the bowels of .exec(). It stops any more of the callback from executing, but has no effect at all on the outer function because that outer function.
So, if you want the .find() operation to finish before you execute the rest of your code in that function, you have to put that code inside the callback function.
I've just started out with NodeJS and trying to get the hang of callbacks.
Today I've seen null passed by as the first argument to the callback in many examples. Please help me understand why it's there and why I need it.
Example 1
UserSchema.methods.comparePassword = function(pwd, callback) {
bcrypt.compare(pwd, this.password, function(err, isMatch) {
if (err) return callback(err);
callback(null, isMatch);
});
};
Example 2
example.method = {
foo: function(callback){
setTimeout(function(){
callback(null, 'foo');
}, 100);
}
}
By convention in node, the first argument to a callback is usually used to indicate an error. If it's something other than null, the operation was unsuccessful for some reason -- probably something that the callee cannot recover from but that the caller can recover from. Any other arguments after the first are used as return values from the operation (success messages, retrieval, etc.)
This is purely by convention and there is nothing to stop you from writing a function that passes success as the first argument to a callback. If you plan to write a library that is adopted by other node users, you will probably want to stick with convention unless you have a very good reason not to.
function searchCoords(){
var result = result;
connection.query('SELECT * FROM monitoring', function(err, result){
if(err){
console.log(err);
}
return{
result: result};
});
}
That's my code. I'm using that code to find the last coordinates of some devices and display them in google maps. but i need to first be able to access the array from the ouside so i can do something like:
myModule.searchCoords().result
or
myModule.searchCoords()().result
However I still can't access the array (result) from the outside function, let alone from another module.
I've been reading on closures, scopes, nested functions, anonymous functions, etc. but i still can't find the solution. What am i doing wrong?
Problem is, that the query is asynchronous, so it can't return a value in the normal flow. If you pass a function when you call searchCoords, then that function can be called after the results come back - which could be after a long delay. This is necessary to prevent the program flow from being blocked whilst potentially long operations are in process.
// accept a callback function to execute after getting results...
function searchCoords(callback){
var result = result;
connection.query('SELECT * FROM monitoring', function(err, result){
if(err){
console.log(err);
}
// run the callback function, passing the results...
callback({result: result});
});
}
// call like this...
// pass a function accepting results object that will be executed as callback
// once results have been returned...
searchCoords(function(resultsObject){
console.log(resultsObject.result)
})