QUnit has an assertion for testing that a function raises an exception (QUnit/raises). Is it possible -- using QUnit -- to assert that a function does not raise an exception.
I realize that it is possible to test it like in the following code:
try {
theTest();
ok(true);
} catch (e) {
ok(false, "Expected to succeed");
}
But I think it ought to be possible using QUnit. Any clues?
There is no such method in qunit
However, if you just write the following code which is much shorter, you will obtain the same result with additionnal benefits
theTest();
ok(true, "My function does not crash");
1/ If the code of a test raises an exception, qunit will mark the test as failed.
2/ If you check the "no try/catch" checkbox, you will be able to debug where the exception was thrown, which is not the case with your try/catch
I had the same issue as you mentioned in the comment whereby my test which tests no Error is thrown would stop "badly" showing a badly formatted Died on test #1 message without any useful information.
I ended up using a mix of both; raises() for one test and try/catch for the other.
I used raises() for the test which tests that an Error is thrown, similar to this:
test("When myFunction() is called with a invalid instance Then Error is thrown", function () {
// Arrange
var testInstance = {};
// Act
raises(function() {
myFunction(testInstance);
}, Error, "myFunction() should throw an Error");
// Assert
// raises() does assertion
});
If the above throws an Error all is fine and if not a nice formatted message is displayed, similar to this:
myFunction() should throw Error
Result: No exception was thrown.
I then used try/catch for the tests which have to ensure no Error is thrown, similar to this:
test("When myFunction() is called with a valid instance Then no Error is thrown", function () {
// Arrange
var testInstance = new myObject();
var result;
// Act
try {
myFunction(testInstance);
result = true;
} catch(error) {
result = false;
}
// Assert
ok(result, "myFunction() should not throw an Error");
});
If the above throws no Error all is fine and if an Error is thrown a nice formatted message is displayed, similar to this:
myFunction() should not throw an Error
Source: ...
Related
I've seen both:
throw new Error(error);
&
console.error(error);
E.G:
jQuery:
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
&
Vue.js:
if (config.warnHandler) {
config.warnHandler.call(null, msg, vm, trace);
} else if (hasConsole && (!config.silent)) {
console.error(("[Vue warn]: " + msg + trace));
}
Both error handling ways seem reliable and used. But my question is:
Is there a difference between them? And if there is, when should I use which?
The key difference: throwing halts the execution, while console.error does not.
Most of the time, it's better to throw an error.
That's a built-in way to signal that something failed and normal execution cannot continue unless the error is expected, caught and handled properly.
In the most platforms, an uncaught exception will be logged to the console as well to warn the developer about it, but caught exceptions won't be logged, since they are assumed to be handled by the code.
Using console.error can be good for cases where the error happened isn't fatal, but you'd like to warn the developer.
However, overusing this feature can easily cause other errors and harder-to-debug code. For example, consider this code:
const elem = document.querySelector('.elem')
if(!elem)
console.error('elem cannot be found!')
const returnValue = functionThatDoesSomethingWithElem(elem)
if(!returnValue.success)
console.error('Doing something with elem has failed!')
if(!returnValue.doSomethingElse())
console.error('Doing something else with elem has failed!')
The above code will log three errors if there's no elem, but execution still continues, maybe causing even more errors.
By throwing an exception, this is avoidable:
const elem = document.querySelector('.elem')
if(!elem)
throw new Error('elem cannot be found!')
const returnValue = functionThatDoesSomethingWithElem(elem)
if(!returnValue.success)
throw new Error('Doing something with elem has failed!')
if(!returnValue.doSomethingElse())
throw new Error('Doing something else with elem has failed!')
This will print only the first error message, and execution halts, unless you put it inside a try..catch structure, like:
try{
const elem = document.querySelector('.elem')
if(!elem)
throw new Error('elem cannot be found!')
const returnValue = functionThatDoesSomethingWithElem(elem)
if(!returnValue.success)
throw new Error('Doing something with elem has failed!')
if(!returnValue.doSomethingElse())
throw new Error('Doing something else with elem has failed!')
}catch(exception){
console.error(exception)
fallbackMethod()
}
There's another difference: thrown errors can be caught by the caller of your function, so it can programmatically handle them (causing the execution to continue, and the error isn't displayed). On the other hand, if you use console.error, the caller can not decide if an error is expected, causing to log the error even if it is normal, so the console can become messy (you can't decide what's a real error and what's not.
Those two are completely different, let's see documentation of each one:
console.error:
Outputs an error message to the Web Console.
Throw:
throws a user-defined exception. Execution of the current function
will stop (the statements after throw won't be executed), and control
will be passed to the first catch block in the call stack. If no catch
block exists among caller functions, the program will terminate.
So, as you can see, they work differently, you can use both in your code, so keep in mind that just a console.error will probably pass unseen by the user, only those with console open will see the message, while throw will be noted, since everything will stop.
Let's see some functional examples:
console.error
Note that the "custom" error will show on console, but code stills executing, you only see the error message because console is showing here in stackOverflow. To stop execution you would need a return right after the console.error
function changeString(currentString, append) {
if (typeof append != 'string') {
console.error("Cannot change string!");
}
//THIS PART BELOW WILL EXECUTE, even with error logged
console.log(currentString + append);
}
changeString("I will show up even with error logged ", null)
Throw
Note that code stops execution when error is thrown and also the message of the error is different from the one that console.error shows.
function changeString(currentString, append){
if (typeof append != 'string'){
throw new Error("Cannot change string!");
}
//THIS PART BELOW WONT EXECUTE
console.log(currentString + append);
}
changeString("I wont show up in the console", null)
Here I added a try/catch, note the catch block being executed, this way I have control over the error and what should happen after the error being thrown, also, I mixed both: Throw and console.error
function changeString(currentString, append) {
try {
if (typeof append != 'string') {
throw new Error("Cannot change string!");
}
console.log(currentString + append);
} catch (er){
console.error("I'm being logged from inside a catch block because an error was thrown");
//DO WHATEVER YOU NEED TO FIX THE ERROR AND ALERT THE USER HERE
}
}
changeString("I wont show up in the console", null)
Further read on official documentations:
Throw
console.error
I would not consider them to be interchangeable. Console.error() simply logs your error to the console with special formatting.
When you actually throw an error you are essentially terminating execution unless you catch the error using a try catch block or some other form of error handling.
Why not have both, like this:
throw new ConsoleError('bad thing');
Source:
// based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
class ConsoleError extends Error {
constructor(...args) {
const returnValue = super(...args);
console.error(...args);
// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ConsoleError);
}
this.name = 'ConsoleError';
this.message = args[0];
// Pass remaining arguments (including vendor specific ones) to parent constructor
return returnValue;
}
}
window.ConsoleError = ConsoleError;
You may also want show the user when some errors happen, for this, use
// this to avoid crashing:
window.toastError('nice user error message', 'extra developer data:', someObject)
// this to crash:
throw new ToastError('we made a mistake')
Source:
window.toastError = (userMsg, ...developerDebugArgs) => {
// TODO: implement toast notifications
// only use userMsg for the toast notification
// Using DOMPurify and rendering userMsg as (potential) html may be nice,
// but backend team may prefer to simple return plain text instead of html
// may need to de-dupe messages being sent to toast component
console.log(
`%c${userMsg}`,
'color: orangered;font-style:italic;',
...developerDebugArgs
);
};
class ToastError extends Error {
constructor(...args) {
const returnValue = super(...args);
window.toastError(...args);
// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ToastError);
}
this.name = 'ToastError';
this.message = args[0];
// Pass remaining arguments (including vendor specific ones) to parent constructor
return returnValue;
}
}
window.ToastError = ToastError;
You could also rename the ToastError class ToastException instead, if it suits your fancy
I am creating HTTP tests with frisby.js which works on top of jasmine.js.
I also have to create some mongoDB objects to test against.
The problem is when I want to clean up these DB objects. When one of the expects fail I want to intercept that and call my own cleanup function. This means that after each failed test, I won't be able to remove the test objects from the DB.
The afterEach function in jasmine does not work properly and jasmine does not have any support for afterAll or beforeAll yet.
That is why I have made the tests as they are today.
it("testing userform get with correct userID and expect correct return", function() {
var innerUserId = userID;
frisby.create('Should retrieve correct userform and return 200 when using a valid userID')
.get(url.urlify('/api/userform', {id: innerUserId}))
.expectStatus(200)
.afterJSON(function(userform){
// If any of these fail, the after function wont run.
// I want to intercept the error so that I can make sure that the cleanUp function is called
// afterEach does not work. I have tried with done()
var useridJSON = userform.UserId.valueOf();
var firstnameJSON = userform.firstname.valueOf();
var surnameJSON = userform.surname.valueOf();
expect(firstnameJSON).toMatch(testUser.firstName);
expect(surnameJSON).toMatch(testUser.surname);
expect(useridJSON).toMatch(innerUserId);
})
.after(function(){
cleanUp(innerUserId);
})
.toss();
});
I am wondering if there is a way to intercept the error for "expect" in frisby or jasmine so that I can make a call to my own cleanup function before exiting.
Full example here
The quickest solution to this problem is to wrap the error code in a try-catch.
This is because if a javascript error occurs, jasmine will NOT keep running assertions. This is different from an assertion error. If an assertion error occurs, jasmine and frisby will keep on testing all the other assertions and then do the "after"-function.
.afterJSON(function(userform){
try {
var useridJSON = userform.UserId.valueOf();
var firstnameJSON = userform.firstname.valueOf();
var surnameJSON = userform.surname.valueOf();
catch(e) {
cleanUp(innerUserId);
// Can do a throw(e.message); here aswell
}
expect(firstnameJSON).toMatch(testUser.firstName);
expect(surnameJSON).toMatch(testUser.surname);
expect(useridJSON).toMatch(innerUserId);
})
This is not the pretty way, but works.
I ended up adding the throw(e) and placed the expects in a finally scope. This way I got jasmine to present all the errors that occured in the test.
As for "before exiting", how about this:
process.on('uncaughtException', function(err) {
console.error(' Caught exception: ' + err);
});
So, I'm using mocha with chai to do my front-end testing, but I'm starting to incorporate sinon and really liking it. Except that testing throwing errors isn't working quite how the sinon docs seem to indicate.
Basically, I've got this method:
create: function(bitString, collectionType) {
var collection;
switch(collectionType) {
case 'minutesOfHour':
collection = this.createMinutesOfHour(bitString);
break;
case 'hoursOfDay':
collection = this.createHoursOfDay(bitString);
break;
case 'daysOfWeek':
collection = this.createDaysOfWeek(bitString);
break;
case 'daysOfMonth':
collection = this.createDaysOfMonth(bitString);
break;
case 'monthsOfYear':
collection = this.createMonthsOfYear(bitString);
break;
default:
throw new Error('unsupported collection type ' + collectionType);
}
return collection;
},
and I'm testing it with this expectation:
it('throws error if missing second arguement', function() {
sinon.spy(factory, 'create');
factory.create();
expect(factory.create).to.have.thrown();
factory.create.restore();
});
however, the error, which I'm try to test for, also seems to halt the execution of the test
I'd thought sinon.spy would include some try / catch logic internally, spy.throw doesn't seem as useful without it.
http://sinonjs.org/docs/#spies
Am I doing something wrong??
I think one thing you could try is asserting against a spy object instead of the method, assign it to a variable. Not really knowing how sinon deals with all this exception magic...I think it might just work as you had expected.
it('throws error if missing second argument', function() {
var spy = sinon.spy(factory, 'create');
factory.create();
expect(spy).to.have.thrown();
factory.create.restore();
});
If that still doesn't work I think you could also do this test with standard chai if need be, leaving sinon out of the equation and actually gaining the check that the error has the correct message.
it('throws error if missing second argument', function() {
expect(function() {
factory.create();
}).to.throw(/unsupported collection type/);
});
Or more concisely:
it('throws error if missing second argument', function() {
expect(factory.create).to.throw(/unsupported collection type/);
});
In your expectation, you mixed chai and sinon syntax. Try
expect(factory.create.threw()).to.be.ok();
Sometimes you'd like to check that errors were thrown on a function that you're not directly testing, i.e. the error method of an ajax call.
This approach worked swell for me:
errorStub = sinon.stub(jQuery, "ajax").yieldsTo("error");
try {
triggerError(); // triggers ajax call which yields to an error
}
expect(errorStub.threw()).to.be.true
I am calling a function from the console but when it throws an exception I do not receive a stack trace like I would if the code was executed normally.
Is there a way I can modify my command (perhaps with try/catch) to have it provide me this information?
to clarify:
page.js:
function otherStuff() { return ['a','b',undefined,'c'];
function doStuff() {
var x = otherStuff();
var z = parseInt(x[2]); // this will throw an error
}
console, after loading a html page that links page.js
> otherStuff();
I get no line number from the Error that is returned to me. When running it from the page (instead of the console) i would receive a line number and a stack trace.
Although verbose, this will print the stack trace of an interactive error in the Chrome JS console:
try {
throw new Error();
} catch (e) {
console.error(e.stack);
}
Unfortunately this won't work if a non-Error object is thrown.
You have an error in your code.
You are missing a closing brace:
function otherStuff() { return ['a','b',undefined,'c']; //} where am i?
function doStuff() {
var x = otherStuff();
var z = parseInt(x[2]); // this will throw an error
}
Side point:
parseInt(undefined) does not throw an error. case in point: http://jsfiddle.net/maniator/Zequj/2/
UPDATE
[Rewriting question to focus on the problem I am trying to understand.]
Is there a means in JavaScript to throw Exceptions that notify the line number where the problem occurs? Similar to C#'s debugger, if an error is thrown on line 50 then I will be taken to line 50.
For example, according to MDN EvalError represents an error with eval(). So, let's say I have a function that uses eval(). I want to use a specific error that is representative of the problem at hand, EvalError:
//As written here the error implies there is a problem on this line. See Firebug console window
var evalErra = new EvalError('required element missing from evaluation');
var stringFunc = "a=2;y=3;document.write(x*y);";
EvalString(stringFunc);
function EvalString(stringObject) {
//Some arbitrary check, for arguments sake let's say checking for 'x' makes this eval() valid.
if(stringObject.indexOf('x') !== -1) {
throw evalErra;
//throw 'required element missing from evaluation';//This way offers no line number
}
eval(stringFunc);//The problem really lies in the context of this function.
}
If I'm going about this all wrong, then please tell me how I should approach these kinds of issues.
When you throw an error, execution of the current code will stop and JS will work its way back up the execution tree until it finds a catch () which handles the particular type of error being thrown, or gets all the way up to the top of the tree, causing an "unhandled exception" error: You threw an error, and nothing caught it, and now someone's window got broken.
try {
if (true) {
throw 'yup'
}
} catch (e) { // catches all errors
... handle the error
}
When doing error handling you want to do the following
throw new Error("message");
Then if you ever handle this error look at err.stack (firefox/opera/chrome) or err.line (Safari) or err.IE_Y_U_NO_SHOW_ME_ERROR_LINE_NUMBER (IE) to find the line number.
If you want you can subclass Error.