How to test a promise has a catch method defined? - javascript

I have a method that returns a promise.
doStuf() {
return somePromise
.then(...)
.catch(e => {...})
}
I want to write a test that makes sure the promise returned by the doStuff method has a catch method.
How to do that ?

That is not a useful thing to test. Consider that doStuf may be refactored later into something more multi-layered, where several then-catch chains may exist, or the implementation will change in some other ways.
You don't actually want to test the implementation, because you can simply look at it to see whether the promise has a catch. No, you want to test the behaviour of doStuf. You want to assert that doStuf returns a promise, and that that promise returns the expected value given certain input. E.g.:
doStuf('foo').then(r => /* assert r equals expected outcome */)
doStuf('bar').catch(r => /* assert r equals expected error */)

Related

Having a really difficult time understand Promise chaining

(I think I learned this, it is that .then returns a promise even if it is not run, i never knew this, thank you)
Please forgive me if this is a dumb question but I simply don't get this, I've googled this many times but those articles only talk about Promise very briefly like how to create one, how to resolve, how to .then and stuff.
I'm confused about promise chaining.
This is my code:
let p = new Promise(function (resolve, reject){
let value = 19;
if(!value){
resolve(value)
} else {
reject(value)
}
})
p.then(x => {console.log(x*x); throw false})
.then(null, x => console.log(x))
//19
This code prints 19 and I have no clue why?.
I do know every .then returns a promise but in this case, p.then shouldn't have even run because the promise is not resolved. Now in a way, it seems that didnt run but if so, why did the second .then run?
Our first .then didn't run, it didnt run any promise whatsoever, so nothing should have displayed.
Now unless 2nd .then is working the same as p.then() which I hope it doesnt because that will only create more confusions, I dont understand why will the 2nd .then run?.
I'm sorry again if my question or english bad but I'm really curious about this.
The .then function takes two functions as parameters, one which is called when the Promise resolves and one when it rejects. It returns a new Promise which gets resolved or rejected with whatever value the function which was executed returns (or throws). If no handler was executed, the Promise will just resolve or reject with the same value the Promise .then was called on.
In your example the first .then call only received one argument, and as the Promise rejects it won't be executed. Therefore the Promise it returns will also reject, and thus the second argument will be executed.
// some examples
Promise.resolve()
.then(called, notCalled);
Promise.reject()
.then(notCalled, called);
Promise.resolve(1)
.then(null, notCalled)
.then(it => it + 1, notCalled)
.then(called, notCalled);
Promise.reject(1)
.then(notCalled, null)
.then(notCalled, it => it + 1)
.then(called, notCalled);
A Promise can be in one of these states:
pending -> initial state, neither fulfilled nor rejected.
fulfilled -> the operation was completed successfully.
rejected -> the operation failed.
In your code sample, the promise is being rejected (since if value is a truthy condition).
The then method accepts two arguments:
p.then(onFulfilled[, onRejected]);
p.then(value => {
// fulfillment
}, reason => {
// rejection
});
Since the then is chainable, the reject get's fired on the second chained then which is the line of code:
x => console.log(x)
Hence, printing the value 19.
Looking at your questions on the two answers above (and also, perhaps the fact that you didn't selected either answer as correct), I wonder if you're still confused about this.
Here is an explanation based on stepping through your code:
p.then(x => {console.log(x*x); throw false})
.then(null, x => console.log(x))
Reading one token at a time:
p is a promise. It has the code as you defined for p: let p = new Promise ...
We immediately call p's then function. This runs the code in p (since p has not yet been run -- promises only run once). Your code in p is a bit confusing because it defines value to be 19, but then it says if ( !value ) ... which means "if value has no value (i.e., is falsey)". In your cause value does have a value, 19. So that causes the else part to run, which says reject(value). This moves p from an "undetermined" state to a rejected state.
Back in your main code, the then clause (the first one), only has one argument. A then clause typically has two arguments, one for code to run if the promise resolves (succeeds), and one if it fails. In your case you only provided one argument to your first then call. Since p was rejected, JavaScript doesn't run the code in the first then, but (as you point out from your learning in bold) it does still return another promise.
Now that the promise from the first then has been determined, we invoke the chained (second) then. Jonas Wilms points out the key fact: If no handler was executed, the Promise will just resolve or reject with the same value the Promise .then was called on. So that means the second then gets the same result as the first then, rejected.
Since the second then has two arguments, JavaScript runs the second one (the one for the rejection case), which prints 19.

Why and when to use Promise.resolve?

As I know, Promises are used to represent success/failure of an asynchronous operation. When I am looking into one of my project, all the functions are wrapping the final result in 'Promise.resolve'. I am not understanding, what is the use of wrapping all the function results in 'Promise.resolve'. Is there any use case here?
For example, all the functions are following below template.
process = (data) => {
//Perform some operations.
return Promise.resolve(result);
}
The only reason to use Promise.resolve is converting a value that might be a promise to a promise.
Promise.resolve(value) is a convenience method that does new Promise(resolve => resolve(value). If the value is a promise it will be returned, if it is a promise from a userland promise library it will be converted to a native promise. If it is a plain value it will be converted for a promise fulfilled with that value.
Promise.resolve(5); // returns a promise fulfilled with the number 5.
This is useful in several cases, for example:
- If a function might return a promise, it should always return a promise - so for example if you have a cached value it might need to be Promise.resolved.
- If there are multiple implementations of functionality and some are synchronous - it creates a uniform interface.
Note that in practice with async functions this is not needed so much anymore since an async function always returns a promise - even if you return a plain value (in fact, whatever you return from an async function is Promise.resolved implicitly).
Also note that in particular you shouldn't make functions return promises if all they do is synchronous computation since a function returning a promise implies I/O in JavaScript.

ES6 - decide if object or promise

Is there a simple and elegant way to determinate if variable is promise or object in javascript (es6)?
I have a variable
let payment;
and at one time in app, it can be either promise or object with real values. I know I can test it it contains some properties like
if (payment.amount)
but this doesn't seems like an elegant solution to me, because properties (data structure) can change in time. Till now I was using
if (typeof payment === 'object')
but I've just figured out, that promises are basically also objects. So this condition is always true.
Is it possible to tell if it's a promise or object with real data?
Don't try to find out. Just make it always a promise.
payment = Promise.resolve(payment);
Promise.resolve creates a new promise object. If the value passed is itself a promise, the is resolved or rejected when the original one is. If it is anything else, the new promise is resolved immediately with that value.
As with all other native objects, you can use instanceof with the Promise constructor:
if (payment instanceof Promise)
However, if you don't know whether it's a native promise or from a custom library, you will usually want to detect a thenable by checking whether it has a .then method.
But you never really need to distinguish them (other than for debugging purposes). If there is a chance that something is a promise, you will always need to wait for, and construct a promise from it anyway. You don't need to do the distinction yourself, you can just use Promise.resolve to cast either promise, thenable or plain object to a promise of your favoured implementation - that's how Promise interoperability was designed in the first place, so it will absolutely work.
const promise = Promise.resolve(payment).then(value => {
// value: always a plain value
}); // promise: always a promise
Check if it has a property then that is a function:
if(payment != null && typeof payment.then === 'function')
// is a promise
else
// is not a promise
As far as I know, this is the only proper way to check if something is a promise (or a "promise-like" thenable), taking into account all different possible promise implementations.
In case you are worried about using await on a plain-old function (rather than a Promise), it's actually okay to do that in ES6. The await gets ignored - no errors are thrown.
This may resolve your need to actually perform the comparison at all (as it did in my case when I first found this question)
payment instanceof Promise
or this:
payment.constructor.toString().indexOf('Promise') > -1
payment.constructor === Promise

Wht is the difference between Q.all() and Promise.prototype.all() methods?

I'm trying to understand how promises work, so general idea is quite clear, but currently I'm stuck with all() method. I know, it used to make a promise for an array of other promises, which will be resolved when all promises from the array will resolved or will be rejected when any of the promises from the array will rejected. Here is my code snippet:
var qu = require('q');
var proArr = [];
for(var i = 0; i < 4; i++) {
var tmpDef = qu.defer();
(function(index, tmpDef) {
setTimeout(function() {
console.log('Timeout ' + index + ' has triggered!');
tmpDef.resolve();
}, (i + 1) * 1000);
proArr.push(tmpDef.promise);
})(i, tmpDef);
}
qu.all(proArr).then(function() {
console.log('All timeouts has passed with Q.all()!');
return 'some result';
});
qu.defer().promise.all(proArr).then(function() {
console.log('All timeouts has passed with promise.all()!');
return 'some result';
});
For this snippet a promise, which returned by qu.all() method will be resolved when all timeouts will be triggered, but a promise, which returned by qu.defer().promise.all() method will stay in pending state even if all timeouts will be triggered. So what the method Promise.prototype.all() have to be used for? And how it differs from Q.all() method?
Also I've looked in Q library sources, and here is a code for Promise.prototype.all() method:
Promise.prototype.all = function () {
return all(this);
};
As I can understand, this method calls Q.all() with an instance of current promise as an argument, but why? Don't the method Q.all() have to accept an array of promises? So I'll be very appreciated for clarification of all this moments.
Don't the method Q.all() have to accept an array of promises?
No, in fact the Q.all method also can take a promise for an array of promises. You can see that in the code well, it does call Q.when on the input. This might seem a bit useless, but it's a more forgiving API and apparently simiplifies the implementation of Promise.prototype.all.
What is the difference between Q.all() and Promise.prototype.all()?
Let's get back to our simpler mental model. Q.all is a static function that takes an array of promises and returns you a promise for an array of all results.
The .all prototype method is simply convenience. Instead of writing
….then(Q.all).…
you can use
….all().…
in a promise chain - these are exactly equivalent. Notice that the .all prototype method does not take any parameters - it does get the array from promise it is called on.
a promise, which returned by Q.defer().promise.all(proArr) method will stay in pending state even if all timeouts will be triggered
Yes. That's for two reasons:
Q.defer().promise is a promise that never resolves (and since you've thrown away the deferred, you never can). The chain just doesn't even advance to the .all(…) invocation.
As established above, the prototype method you're calling here doesn't take any arguments. The proArr is simply ignored.
If you want to use it, you can use the following though:
Q(proArr).all().…

Transform array of promises into array of values when fulfilled

I'm after a function that would return a resolved value of a promise. Failing gracefully is definitely a bonus, but it's an assumed precondition that when the function is called the promise is ready to be resolved.
While I'm working with webdriver.js promise implementation which allows the queue manipulations similar to below, I don't want to get too lost in semantics of queues/chains etc. For that reason alone, here is some pseudocode to cover what I'm trying to achieve:
var inputs = [...], outputs;
outputs = inputs.map(function(input){
//queue some async tasks to be performed with input
queue.enqueue(...);
//I can't return the *output* value here yet, naturally, so instead
return promise;
});
//now I'll add another task to the same queue
//this means that by the time this task is run
//the async tasks above would have been executed
//and the promises would be "resolvable"... right?
queue.enqueue(function(){
console.log(outputs); //>an array of promises
console.log(doSomeMagic(outputs)); //>resolved values as needed <<<
});
NB: afaik Q.all() would not do what I'm after - it takes an array of promises and returns a promise of an array, not its resolved value. I'm only happy to be proved wrong.
For anyone else looking for an answer based on the title of the question the following works with ES 2017+ to take an array of promises and return an array of values:
var arrayOfValues = await Promise.all(arrayOfPromises)
The only way to get the eventual value for a promise is with then. If a function performs work asynchronously, it must return a promise and under no circumstances can it return a plain value. To do so, it would necessarily have to block the thread of execution until the work completes, which is only possible with threads or fibers, which entrain the perils of deadlock and interleaving hazards.
As such, Q.all is in fact the method you need, except to follow up with then to get the eventual value.
Q.all(inputs.map(function (input) {
return promiseForOutput; // however you go about this
}))
.then(function (outputs) {
// at this event, outputs is an array of output values
});
There are ways to cheat, of course. promise.inspect() will return an object describing the state of the promise, like {state: "fulfilled", value: value} if it’s ready, or {state: "rejected", error} if it failed, or {state: "pending"}, if it is not yet ready. If, as you say, you are guaranteed that the outputs promise, returned by Q.all has been fulfilled, you can do this:
outputs = outputs.inspect().value
I don’t recommend this. The best way to know that a promise is resolved is to use then.
You could also just push values onto an outputs array of your making if you can also guarantee that all the outputs are ready through some external means.
var endResult = Q.defer();
var outputs = [];
inputs.forEach(function (input) {
outputPromise.then(function (output) {
outputs.push(output);
check();
}, endResult.reject);
});
check();
function check() {
if (outputs.length === inputs.length) {
// manipulate outputs directly, they are ready
endResult.resolve();
}
}
return endResult.promise;
The best means, however, is to just use Q.all(outputs).then to get an event that is guaranteed to be after all the outputs are ready.
Since you in general never know whether promises are resolved or not, you cannot simply transform them into a plain value. Q.all must return a promise since it cannot extract the values array from the async context. The only time you know that a promise has a value is in the success handler, and there you're getting the value anyway. You should not use another event system that tells you when a promise has settled - use the promise itself.
So instead of using queue.enqueue, just put Q.all(outputs).then(function(values){ /* do something */ }). However, if you cannot work around that, you might have a look at the Promise inspect debugging method: _.pluck(_.invoke(outputs, "inspect"), "value"). But notice that it might be easier not to store the values in promises then.

Categories