Does grunt silent errors in (bluebird) promises? - node.js

I have a npm module which has main() function as its starting point.
Now, lets say I throw an Error immediently in that main() as shown below:
function main() {
throw new Error("An error!");
}
And then execute it with node my-app-that-launchers-main.js then obviously, the error is thrown and I get a stacktrace.
If I write a grunt task for this:
var mynpm = require("mynpm");
module.exports = function(grunt) {
grunt.registerTask("build",function() {
mynpm.build();
});
}
And execute it via Grunt, then it fails. The error is thrown and grunt fails, as expected.
However, if I wrap this throw inside a Bluebird Promise:
function main() {
Promise.try(function(resolve) {
throw new Error("An error!");
} ).catch(function() {
console.log("error");
} ).finally(function() {
console.log("finally");
});
}
And run it via node then I see that the catch function is invoked. As expected.
However, if I run the same code via Grunt's registertask, everything becomes dead silent. Nor the catch or the finally is called.
What could be causing this. It seems like Grunt hijacks errors are thrown.
Its a super easy to reproduce this, yet I am so puzzled about why.
Does Grunt hijack errors that are thrown, somehow, so not even the Promise's catch and finally functions gets invoked?
How can the execution and the error handling be so different if its executed manually, compared with if Grunt executes the code?

You are looking to define an async task. This can be done using this.async():
grunt.registerTask("build",function() {
// Tell Grunt this task is asynchronous.
var done = this.async();
mynpm.build();
});
More information about async tasks here : https://gruntjs.com/api/inside-tasks

Related

Why won't this Azure time triggered function fail?

I'd like to know why my function is succeeding, even though I'm purposely throwing an exception inside the function. I created a new timer function and all I did is added a try/catch block and an always throwing error:
module.exports = async function (context, myTimer) {
try {
if (myTimer.isPastDue) {
context.log('Node is running late!');
}
context.log('TEST');
throw 'Error occurred';
} catch (err) {
context.log(err);
}
};
After deploying the above function to Azure and manually triggering it, will result in a succeeded function execution and the logs showing 'TEST' but not 'Node is running late!':
2022-04-08T13:32:30Z [Information] TEST
2022-04-08T13:32:30Z [Information] Executed 'Functions.TEST' (Succeeded, Id=..., Duration=36ms)
the docs only state that I should use a try/catch at the highest level of the function. I couldn't find any information on why this function would succeed with an error happening in execution.
Any help will be appreciated, many thanks in advance!
It does not fail because you are catching the error, meaning it is not surfaced, it expects you to actively decide what to do, log and re throw the exception is one option, log only is another it really depends on your business needs.
You need to either remove the try/catch blocks or add a throw to your catch similar to this
catch (err) {
context.log(err);
throw;
}

How to stub an uncaughtException listener in node with sinon

i have a custom handler for uncaught exceptions that i want to test. with all the attempts, i have also tried inside a forked child process as well.
this is a contrived example...
process.on('uncaughtException', function(err) {
otherFunction(err.message);
});
it('should catch exceptions', function() {
stub(otherFunction);
throw new Error('foo');
assert.calledWith(otherFunction, 'foo');
});
is there something i need to use with my stubbing tool (currently using sinon), or is this entirely the wrong approach?
Any error thrown inside an itfunction should fail that test. You can wrap the throw statement with try{} and in catch block you can write the assert function.

Why does the selenium function elementLocated in node.js throw an error only on Jenkins?

I'm using the function driver.wait(until.elementLocated()) below, written with node.js, as an explicit wait on my Selenium tests to ensure that the pages in my test load properly. When I run the tests from my local CLI they work perfectly, headlessly and with GUI.
const loadMyPage = {
loadThePage: async function(driver) {
try {
await driver.wait(
until.elementLocated(
By.css("div.radio-select span:nth-child(7)")
),
20000
);
} catch (e) {
console.trace(loadMyPage.loadThePage);
throw e;
}
}
However, when I run the tests in Jenkins headlessly I receive the following error every time I use the function elementLocated().
TypeError: Wait condition must be a promise-like object, function, or a Condition object[0m[90m
at Driver.wait (node_modules/selenium-webdriver/lib/webdriver.js:928:13)
at Object.loadMyPage (foobar-tests/page.js:35:20)
at Context.<anonymous> (foobar-tests/foobar.test.js:32:30)
at <anonymous>
Is there anything specific that could cause this error in Jenkins? I have managed to narrow it down to this specific function, elementLocated().
I was able to find a workaround for my issue, however it appears that there is a larger issue at play with selenium. More information on the core issue can be found at https://github.com/SeleniumHQ/selenium/issues/5560.
I updated my explicit wait by passing an additional async function, and this cleared up the problem entirely in Jenkins. Example is below.
loadMyPage: async () => {
//The second async is necessary to run explicit wait functions like the one below.
//This issue is specific to selenium, more information can be found at https://github.com/SeleniumHQ/selenium/issues/5560.
loadThePage: async () {
try {
async driver =>
await driver.wait(
until.elementLocated(
By.css("div.radio-select span:nth-child(7)")
),
10000
);
} catch (e) {
console.trace(loadMyPage.loadThePage);
throw e;
}
}

Catch error inside express route

I have a node.js service that is being called from a main application. I've had issues where an error occurs in the service and the service hangs preventing any other requests from being handled. I have code to catch errors in common places like after doing a mongodb query.
model.aggregate(
[
...
],function (err, result) {
if (err) {
next(err);
}
else {
//other code
}
I am also catching uncaught exceptions and killing the service in this case with the following code.
process.on('uncaughtException', function (er) {
console.error(er.stack);
logger.log('info','Cbt Dev Service crashed',er);
process.exit(1);
});
These seem to be working fine except I occasionally run into issues where an error occurs but isn't caught by either. An exmple of an error in this case is after getting a result from a mongodb query and getting an error like "Cannot read property 'subjectAreas' of undefined. This error seems to get caught by the mongodb middleware. The code looks like this.
function (err, result) {
if (err) {
res.send(errorHandler(err, req));
}
else {
var subjectAreas = result[0].subjectAreas.sort();
}
In this case result is an empty array so obviously throws an error. I understand that I can prevent this with better written code like using try/catch but if I'm not aware this issue exists and the service hangs up again, I don't know what the error is in order to fix it so that's why I need to log it.
Is there something else I can do that will catch these kinds of errors?

Using a domain to test for an error thrown deep in the call stack in node.

I'm trying to write some tests that catch errors that are potentially thrown deep in a nest of callbacks and I decided to try using domains for this. I've managed to simplify to the following test case:
"use strict";
var assert = require("assert");
var domain = require("domain");
function wrapInDomain(throwsAnError, callback) {
var thisDomain = domain.create();
thisDomain.on("error", function(error) {
console.log("calling callback");
//thisDomain.destory(); // I'm not sure if I should do this
callback(error);
});
thisDomain.run(function() {
process.nextTick(function(){
throwsAnError();
});
});
}
function throwsAnError() {
process.nextTick(function(){
throw new Error("I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.");
});
}
describe("describe something that throws an error", function(){
it("it clause", function(done) {
wrapInDomain(throwsAnError, function(theError) {
console.log("got an error " + theError);
assert(false); //Assert something
done();
});
});
});
If the assert passes mocha gives the nice colourful summary of how many tests passed or failed. But if an assert fails, node seems to crash and drops directly. The error listed is the original rather than the failed assert.
Am I doing something very wrong here? Or is this some kind of bug that needs reporting?
calling callback
got an error Error: I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.
/home/gareth2/cloud/apifacade/src/test/resources/testCase.js:23
throw new Error("I sensed a great disturbance in the force, as if mill
^
Error: I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.
at /home/gareth2/cloud/apifacade/src/test/resources/testCase.js:23:15
at process._tickDomainCallback (node.js:463:13)
*node crashes*
I'm using the following version of node.
$ node --version
v0.10.33
The problem is that you need to exit the domain before Mocha can trap the failing exception, because event handlers that are bound to a domain execute in the domain. If you change your error handler to this, it will work:
thisDomain.on("error", function(error) {
thisDomain.exit();
process.nextTick(function () {
callback(error);
console.log("calling callback");
});
});
You need to call process.nextTick (or setImmediate or setTimeout(..., 0)) in the code above so that the statement callback(error) executes in the domain that becomes effective after thisDomain.exit() runs. The way Node works, when you create a new callback for handling an event or to run with process.nextTick (or equivalent functions), then the callback as a whole is associated with a specific domain. Suppose the following callback
myDomain.on("error", function () {
A;
myDomain.exit();
B;
});
Any error caused by A will be handled in myDomain, but the same is true of B because B belongs to the same callback as A.
By using process.nextTick, we create a new callback which is associated with the new domain that takes effect after thisDomain.exit() executes. Modifying the example above, it would be:
myDomain.on("error", function () {
A;
myDomain.exit();
process.nextTick(function () {
B;
});
});
Now B belongs to a different callback from A and this callback was created after we exited myDomain so it executes in the domain that was in effect before myDomain was created.

Resources