Why jest expects an anonymous function to catch an error? - testing

I have not comprehended what's the reason behind the fact that expects a curried function when I want to test the output of the error message. If it was going to be a return value a direct call to the function leads to the value to be tested correctly in .toBe
function calculateMedian({numbers}) {
if (Array.isArray(numbers) && numbers.length === 0) {
throw new Error('Cannot calcuate median without any numbers');
}
}
However, if i were to test the following snipped without the anonymous function the test will simply fail. What is the reason behind it?
Passing Test
it('should throw an error when given an empty array', () => {
expect(() =>
calculateMedian({
numbers: [],
}),
).toThrow('Cannot calcuate median without any numbers');
});
Failing Test
it('should throw an error when given an empty array', () => {
expect(calculateMedian({numbers: []})
).toThrow('Cannot calcuate median without any numbers');
});

expect and toThrow are just function calls. So, for the assertion on exception to work, the thing you pass as expect argument needs to allow for execution controlled by the testing framework.
The flow is similar to:
expect() saves the lambda as variable
toThrow() executes the saved variable in a try/catch block and tests the caught exception.
The way you would do it without the toThrow method would be similar to:
try {
calculateMedian({numbers: []};
fail();
} catch (err) {
expect(err.message).toBe('Cannot calcuate median without any numbers')
}
If, instead of passing a lambda/function you simply invoke the function, the error will be thrown before program control gets to the toThrow method. The test will fail because of the thrown error.

Related

Chai expect "not.to.throw" not catching unexpected error

I'm testing a function using Chai's expect ... not.to.throw pattern (v4.3.4):
describe('parseInt', () => {
it('does not throw TypeError', () => {
// foo is not defined, so a ReferenceError is thrown... somewhere?
expect(() => parseInt(foo)).not.to.throw(TypeError);
});
});
The closure throws an error, but I don't see this error anywhere in the output (running mocha). The test passes without the slightest indication of the problem inside the closure.
I expect to at least see the error in the console, even if the tests pass.
This answer says that such errors must be run like so:
// wrapping describe/it are elided
try {
expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
expect(e).to.be.a(ReferenceError); // should PASS, and does
}
This passes, but doesn't appear to be testing the second condition. I can flip it and the test still passes:
// wrapping describe/it are elided
try {
expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
expect(e).not.to.be.a(ReferenceError); // should FAIL, but does not
}
What am I missing?
Edit
I think the behavior you are observing is actually expected. The original post you referenced may be misleading.
Consider the following test:
// describe/it wrappers have been redacted
expect(()=>parseInt(foo)).to.not.throw(TypeError)
Should this test pass or fail? Intuitively it should pass since the assertion is met: a TypeError was not thrown.
Again for the following test, should 'hello there' be logged to the console?
// describe/it wrappers have been redacted
try {
expect(() => parseInt(foo)).to.not.throw(TypeError);
} catch (e) {
console.log('hello there')
}
If yes, then the statement expect(() => parseInt(foo)).to.not.throw(TypeError), must throw.
And for it to throw, the assertion - not throw a TypeError - must not be met, but we have already established that the assertion is met, and so no exception is thrown.
Therefore, all code in the catch block is unreachable.
This is why the second assertion in your original example is never executed. It will only be reached if the code somehow threw a TypeError and caused the assertion to fail.
Possible solution
For the approach you are taking, I think it could work if there was a way to tell mocha/chai to still go ahead and propagate the error that is thrown by the target function even if the assertion is met. I am unsure of if there is a way to do this, though.
Alternative approach
Alternatively, I think you can get the same (or similar) outcome for the test you have in mind by doing this instead:
// describe/it wrappers have been redacted
const myFunc = () => parseInt(foo)
expect(myFunc).to.not.throw(TypeError)
expect(myFunc).to.throw(ReferenceError)
Here are the assumptions underlying the above test:
You are expecting an error
The error should under no circumstances be a TypeError
The error thrown should always be a ReferenceError.
In case these assumptions do not match what you are currently testing for, or if my alternate approach does not satisfy your needs, kindly let me know!
PS, I used mocha: "^9.1.0" and chai: "^4.3.4" for these tests.

Can we overwrite 'expect' method of testcafe's TestController

I am looking for a way to overwrite expect method for TestController. My idea is existing tests whoever used t.expect method, I want to perform additional steps in those cases.
I came up with below sample code but testcafe runtime fails with below error
TypeError: Cannot read property '_expect$' of undefined
sample code attempting to override:
import { Selector } from "testcafe";
fixture`Getting Started`.page`http://devexpress.github.io/testcafe/example`;
test("My first test", async (t) => {
t = modify(t);
await t.typeText("#developer-name", "John Smith").click("#submit-button");
// Use the assertion to check if the actual header text is equal to the expected one
await t
.expect(Selector("#article-header").innerText)
.eql("Thank you, John Smith!");
});
function modify(t) {
let prevExpect = t.expect;
t.expect = (param) => {
console.log("modified expecte has been used");
return prevExpect(param);
};
return t;
}
Also, when using t.click(Selector(...).expect(...), It doesn't use my overwritten expect. How to make it work in the call chain as well?
Technically, it's possible to overwrite the expect method, but please note that this approach may lead to incorrect work and unexpected errors.
You need to modify your modify function as follows:
function modify (t) {
let prevExpect = t.expect;
t.expect = (param) => {
console.log("modified expect has been used");
return prevExpect.call(t, param);
};
return t;
}
As for the t.click(Selector(...).expect(...) issue, you call the expect method of Selector, but Selector does not have the expect method.
You need to add ) after Selector:
await t.click(Selector(...)).expect(...)

Possible to manipulate CasperJS assertions?

My CasperJS asserts seem to be overly strict. I have a function where I am trying to test the names of client logo images from an array, using Casperjs. However I do not seem to be able to use a variable from a forLoop in casperJS.
I understand there are probably hoisting issues that I am not accounting for, but this does not seem to be the primary problem. I have tried several things to resolve hoisting issues, such as immediately invoked functions, try catch blocks, and using ES6 term "Let" in my loop. None seem to work. Then I notice if I simply hard-code the string my variable should represent, and stick a console.log into my assert of a PASSING test, right before the return, the passing test fails.
Here is my failing code
var clients = 'https://www.google.com/';
var logoArray = ["images/logos/AC.png", "images/logos/Affiny.png", "images/logos/ffintus.png", "images/logos/agileAsset.png"]
function checkClientsArrayTest() {
casper.test.begin('The layout is as expected', 10, function suite(test) {
casper.start(clients, function () {
casper.then(function () {
for (var i = 0; i < logoArray.length; i++) {
try { throw i }
catch (ii) {
console.log(ii);
console.log(i);
test.assertEvalEquals(function () {
return document.querySelectorAll('div.client_logo a img')[ii].getAttribute('src')
.match(logoArray[ii]).toString();
}, logoArray[ii], 'Test searches for Client Logos in DOM.');
}
}
});
}).run(function () {
test.done();
});
});
}
If I change logoArray[ii] to a hardcoded string from the first index of the array, it passes. If I consolelog logoArray[ii], it seems to be what I expect. But if I pass a variable to the assert, or even stick a console.log inside of it, the test fails with the following
Running check for the layout of URL: https://www.google.com
0
0
FAIL Test searches for Client Logos in DOM.
type: assertEvalEquals
file: headlessTester.js
subject: null
fn: undefined
params: undefined
expected: "images/logos/AC.png"
Is this an issue of me getting hoisting wrong (shouldn't fail by sticking in a logger if this is the case afaik), or is this due to strictly structured asserts in CasperJS?

How to test if method that takes argument is throwing an exception in dart?

If I have
class ErrorThrower{
void throwAnError(String argument){
throw new Error();
}
}
I want to test if throwAnError throws Exception, or more precisely an instance of Error
This is my code but it doesn't work
test('', () {
var errorThrower = new ErrorThrower();
expect(errorThrower.throwAnError("string"), throwsException);
});
Dart's testing package can detect errors thrown, but the function either needs to be asynchronous (most commonly, return a Future), or be provided as a callback, so the expect function can lazily evaluate it. In your example:
test('', () {
var errorThrower = new ErrorThrower();
expect() => errorThrower.throwAnError("string"), throwsError);
});
... should work. Note that I wrote throwsError not throwsException, in Dart these are two different things (that do not inherit from each other), with the intention that errors are not intentionally caught in production code, but exceptions (such as FormatException) should be.

Parse Promises in Cloud Code / Express.js [duplicate]

I had a look at the bluebird promise FAQ, in which it mentions that .then(success, fail) is an antipattern. I don't quite understand its explanation as for the try and catch.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
It seems that the example is suggesting the following to be the correct way.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
What's the difference?
What's the difference?
The .then() call will return a promise that will be rejected in case the callback throws an error. This means, when your success logger fails, the error would be passed to the following .catch() callback, but not to the fail callback that goes alongside success.
Here's a control flow diagram:
To express it in synchronous code:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
The second log (which is like the first argument to .then()) will only be executed in the case that no exception happened. The labelled block and the break statement feel a bit odd, this is actually what python has try-except-else for (recommended reading!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
The catch logger will also handle exceptions from the success logger call.
So much for the difference.
I don't quite understand its explanation as for the try and catch
The argument is that usually, you want to catch errors in every step of the processing and that you shouldn't use it in chains. The expectation is that you only have one final handler which handles all errors - while, when you use the "antipattern", errors in some of the then-callbacks are not handled.
However, this pattern is actually very useful: When you want to handle errors that happened in exactly this step, and you want to do something entirely different when no error happened - i.e. when the error is unrecoverable. Be aware that this is branching your control flow. Of course, this is sometimes desired.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
That you had to repeat your callback. You rather want
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
You also might consider using .finally() for this.
The two aren't quite identical. The difference is that the first example won't catch an exception that's thrown in your success handler. So if your method should only ever return resolved promises, as is often the case, you need a trailing catch handler (or yet another then with an empty success parameter). Sure, it may be that your then handler doesn't do anything that might potentially fail, in which case using one 2-parameter then could be fine.
But I believe the point of the text you linked to is that then is mostly useful versus callbacks in its ability to chain a bunch of asynchronous steps, and when you actually do this, the 2-parameter form of then subtly doesn't behave quite as expected, for the above reason. It's particularly counterintuitive when used mid-chain.
As someone who's done a lot of complex async stuff and bumped into corners like this more than I care to admit, I really recommend avoiding this anti-pattern and going with the separate handler approach.
By looking at advantages and disadvantages of both we can make a calculated guess as to which is appropriate for the situation.
These are the two main approaches to implementing promises. Both have it's pluses and minus
Catch Approach
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Advantages
All errors are handled by one catch block.
Even catches any exception in the then block.
Chaining of multiple success callbacks
Disadvantages
In case of chaining it becomes difficult to show different error messages.
Success/Error Approach
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
Advantages
You get fine grained error control.
You can have common error handling function for various categories of errors like db error, 500 error etc.
Disavantages
You will still need another catch if you wish to handler errors thrown by the success callback
Simple explain:
In ES2018
When the catch method is called with argument onRejected, the
following steps are taken:
Let promise be the this value.
Return ? Invoke(promise, "then", « undefined, onRejected »).
that means:
promise.then(f1).catch(f2)
equals
promise.then(f1).then(undefiend, f2)
Using .then().catch() lets you enable Promise Chaining which is required to fulfil a workflow. You may need to read some information from database then you want to pass it to an async API then you want to manipulate the response. You may want to push the response back into the database. Handling all these workflows with your concept is doable but very hard to manage. The better solution will be then().then().then().then().catch() which receives all errors in just once catch and lets you keep the maintainability of the code.
Using then() and catch() helps chain success and failure handler on the promise.catch() works on promise returned by then(). It handles,
If promise was rejected. See #3 in the picture
If error occurred in success handler of then(), between line numbers 4 to 7 below. See #2.a in the picture
(Failure callback on then() does not handle this.)
If error occurred in failure handler of then(), line number 8 below. See #3.b in the picture.
1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });
Note: Many times, failure handler might not be defined if catch() is
written already.
EDIT: reject() result in invoking catch() only if the error
handler in then() is not defined. Notice #3 in the picture to
the catch(). It is invoked when handler in line# 8 and 9 are not
defined.
It makes sense because promise returned by then() does not have an error if a callback is taking care of it.
Instead of words, good example. Following code (if first promise resolved):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
is identical to:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
But with rejected first promise, this is not identical:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)