Making both parts of expect resolve promises - javascript

The Problem:
In Protractor, expect() is patched to implicitly understand promises which enables a shorthand assertion style. E.g.:
expect(elm.getText()).toEqual("expected text");
elm.getText() here does not need to be explicitly resolved with then() and would be implicitly resolved by Protractor before the expectation is checked.
But, what if the "to equal" part is also a promise. For instance, a text from an another element. In this case we have to resolve the second part explicitly:
elm2.getText().then(function (text2) {
expect(elm1.getText()).toEqual(text2);
});
The Question:
Is it possible to patch Jasmine/Protractor to make it understand promises on both sides of the assertion? To be able to write:
expect(elm1.getText()).toEqual(elm2.getText());

Just tested with promises for both sides - and it resolves them OK.
Try at your project. Maybe you have nothing to do:
describe('ololo', function () {
it('both sides are promises', function () {
browser.get('http://www.protractortest.org/testapp/ng1/#/form');
let elementText1 = $('.ng-scope p').getText();
let elementText2 = $('#transformedtext>h4').getText();
//Will fail here, but you can see that it successfully resolved promises
expect(elementText1).toEqual(elementText2);
});
});
If this does not work for you - i think you can use protractor.promise.all, just example:
protractor.promise.all([elm2.getText(), elm1.getText()])
.then(texts=> expect(texts[0]).toEqual(texts[1]), 'texts should be same')
Or harder way - create own matchers. See how i work with promises inside matcher in my lib:
https://github.com/Xotabu4/jasmine-protractor-matchers/blob/master/index.js#L39

Not pretty, but you could resolve the param. It's a no-op for non promises...
expect(elm1.getText()).toEqual(Promise.resolve(elm2.getText()));

Related

Promises and async functions "borrowing" variables from concurrently running promises

I have this Waterline async call inside helper function answerUserTag:
theQuestion = await UserTag.findOne({id: answerObject.tag});
This is how I call the above helper:
const promises = userTagAnswers.map(userTagAnswer =>
sails.helpers.answerUserTag.with(
{
userTagAnswer: userTagAnswer,
answeringUserId: inputs.userId,
userType: inputs.userType
}));
await Promise.all(promises);
If there's just one userTagAnswers (i.e. one promise), it works fine. But if there's two userTagAnswers and I set a breakpoint after the theQuestion query in the helper, I see the following non-sensible values:
answerObject.tag is equaled to 5c338ae267a1983e84340388
theQuestion.id is equaled to 5c27227ac1e60913703f3002
It seems like there's an illogical overlap between variables when multiple promises are called.
Try to debug it through Promise.each() perhaps? Since the iteration is sequential, you'll know which Promise is troubling you.
Secondly, it would be great if you specify the helper function.
Thirdly, why with? If you check MDN - with, it clearly states and I quote:
Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues. It has Ambiguity contra. The with statement makes it hard for a human reader or JavaScript compiler to decide whether an unqualified name will be found along the scope chain, and if so, in which object.
The inconsistant results are because the promises are resolving async
this may help: toniov.github.io/p-iteration

Promise not working in chain of javascript /jquery functions

I have a series of async functions that i want to execute in a sequence, i tryed using promises but the exmple i followed tho it works, does not execute then in orther, and many times one resolves the content, before the other draws the container. i have tryed to understand the promises thing and it seems that the promises is being rejected, but i dont know what im doing wrong, or if i should use other method to "chaing" the functions. Thanks for the help!
var chain = new Promise(function(){
statusUp();
});
chain.then(p_view(pid)).then(pu_list(pid)).then(pm_list(pid));
You're looking for something similar to this
Promise.resolve(statusUp())
.then(function(pid) {
return p_view(pid)
})
.then(function(pid) {
return pu_list(pid)
})
.then(function(pid) {
return pm_list(pid)
});
I made some (a lot of...) assumptions here regarding statusUp, p_view, pu_list and pm_list so this might need some tweaking.

Avoid forgotten promise returns

When I'm using promises to express dependencies between jobs, where the resolved value becomes unimportant, there is some danger that I might be forgetting a return somewhere. Example:
startSomething().then(function() {
Q.all(tasks.map(function(task) { return task.startIt(); }))
}).then(collectOutput).done();
Here the Q.all returns a promise, and I should have returned that. Not doing so means that by the time collectOutput gets called, all tasks have been started, but there are no guarantees that they finished.
This kind of error results in a race condition, and may be extremely hard to reproduce and track down. So I wonder, is there some tool to help detect and avoid this kind of problem? Perhaps some promise library which warns when a function along the way returns undefined? Or detects promises with no listeners, the way Bluebird does for unhandled rejections?
Actually, bluebird will warn you if you created a promise in a handler but did not return it. If you're willing to drop Q.
Here's a more in-depth explanation about bluebird's warnings
Warning: a promise was created in a handler but none were returned from it This usually means that you simply forgot a return statement
somewhere which will cause a runaway promise that is not connected to
any promise chain.
For example:
getUser().then(function(user) {
getUserData(user);
}).then(function(userData) {
// userData is undefined
});

Bluebird Promise: any() collection return value undefined

Using bluebird promises, I am trying to check if a certain version of a file exists (always only ONE of those files exists but i don't know which one). To speed things up, I am using the any() collection to get all checking out concurrently:
Promise.any([
fs.existsAsync('./foo/image1.jpg'),
fs.existsAsync('./foo/image2.gif'),
fs.existsAsync('./foo/image3.png')
]).then(function(result) {
console.log(result); //remains undefined
});
I am always getting an undefined result. According to (How do I return the response from an asynchronous call?) this is normal behaviour of a resolved promise. Still, I need to know, which of my three promises resolved or maybe I just can't use any() for that purpose?
The callback for fs.exists() does not follow the expected calling convention of callback(err, value) so it doesn't work with generic promisify. It uses just callback(value).
You could either use fs.statAsync() instead or you could create your own promisification for fs.exists() that would work properly.
Of course, fs.exists() is deprecated anyway for race condition reasons so you should perhaps rethink your tactic here anyway.
Here's a properly promisified fs.existsAsync():
fs.existsAsync = function(path) {
return new Promise(function(resolve) {
fs.exists(path, resolve);
});
}
You would assign this after you've done the general promisification of the fs module to replace the wrong fs.existsAsync that Bluebird did automatically.

multiple functions inside of angular then()

Sometimes I see more than two functions separated by comma, inside of promise then() in AngularJs. Could anyone here help to explain what the structure mean?
e.g.
then(function(response){..}, function(response){..}, function(response){..}, function(response){..});
I understand that, if there are two functions inside of then(). The first function will run if it fulfill the promise, otherwise the second will run if there is any error occurs. This structure doesn't look like chained promise either...
Thank you very much for any help here :-)
Well:
The first function is the fulfillment handler, it will execute when the promise resolves to a value (normally).
The second function is the rejection handler, it will execute when the promise resolves with an error by rejecting (or throwing an exception in a handler).
The third function is for progress, this is a nonstandard and deprecated feature that will never be a part of ECMAScript promises - it is best to avoid it altogether since it does not compose well. It is also not supported in Angular's new $q API.
Anything past the third function passed in is ignored by the handler and will have no effect.
Here is an example for all three being called:
var good = $q.when(3);
good.then(x => console.log("Successful"));
var bad = $q.reject(Error("Bad")); // always reject with errors
bad.then(null, x => console.log("Failed"));
var d = $q.defer(); // don't do this like... ever
d.promise.then(null, null, x => console.log("Progressed"));
d.notify("event notification"); // never use this in real code ;)

Categories

Resources