Should I await expect(<async>) conditions - protractor

https://www.protractortest.org/#/async-await shows an example of using async/ await in protractor, but includes the line:
expect(await greeting.getText()).toEqual('Hello Julie!');
But I don't understand how that can be correct: if the greeting.getText() is async (indicated by the await), then the text won't be known until after that line has completed. Isn't:
await expect(await greeting.getText()).toEqual('Hello Julie!');
So we definitely wait for the text to be obtained (and checked) before we move on. In this example, it's not too important (assuming the expect check does execute), but in general, is there any risk of re-ordering the getText() with further operations (which may remove it from the DOM, for example).
Is it in practice safe if it's only browser-based async operations, as they execute serially anyway (so the getText() will complete before a subsequent operation?
Presumably if we included non-browser based async operations (e.g. we did a http request to a server), then the ordering wouldn't be guaranteed, so best practice would be to write 'await expect(...).toX(...)' (which is safe even if the expect expression is not async).
Of course, with all that, we end up with 'await' on the beginning of nearly every line, which looks a bit ugly.

expect(await greeting.getText()).toEqual('Hello Julie!');
is the correct way to go.
await stops execution queue and waits until first command is done before moving on to the second one, IN ORDER TO RESOLVE PROMISE. So if your function is synchronous and doesn't return a promise, why await it?
From protractor page, .getText() returns !webdriver.promise.Promise.<string> - long story short, it returns you a promise, thus it needs to be resolved
expect(await greeting.getText()).toEqual('Hello Julie!'); on the other hand returns undefined (try to console.log it). And since it doesn't return promise, and there is nothing to resolve, await is not needed
Additional example
Lets assume you want a synchronous function to take parameters:
someFunction("2" === "1", 1, await $welcomeMessage.getText());
First thing js does, is it runs each argument of the function as a separarte statement. i.e.
"2" === "1" // false
1 // 1
await $welcomeMessage.getText() // 'welcome user'
So by the time when function will be ready to be executed the overall statement will look like so
someFunction(false, 1, 'welcome user');
In other words, even though it looks like the function takes asynchronous promise which you need to wait for, in fact, this promise is resolved before it's executed. So if someFunction itself is synchronous, it doesn't need to be awaited

Protractor is really simple after the introduction of await, don't need to complicate it
First disable selenium control flow in config file, just add this line in config file:
SELENIUM_PROMISE_MANAGER: false
https://www.protractortest.org/#/control-flow
Now in test use:
it('should find an element by text input model', async function() {
await browser.get('app/index.html#/form');
var username =element(by.model('username'));
await username.clear();
await username.sendKeys('Jane Doe');
var name = element(by.binding('username'));
expect(await name.getText()).toEqual('Jane Doe');
});
Note that i am not using await for
var name = element(by.binding('username'));
This is because in protractor the find element action is not triggered unless you call a method on it
so you don't have to use await there
you won't get element not found unless you call any method on it .

Related

Why should we use batch() instead of Promise.all?

From the pg-promise FAQ Why use method batch instead of promise.all?:
It is quintessential to settle all the promises-queries created within your task or transaction, before the connection is released
I don't see why this should be a problem.
For example when we have an array of queries like this:
[
t.any("SELECT pg_sleep(2) as a"),
t.any('this will fail'),
t.any("SELECT pg_sleep(3) as b")
]
Note: pg_sleep is only used for testing.
In production this would be Insert/Update/Delete statements. And we only want to commit the transaction when all have been successful: i.e. return an error when any of them fails.
When we use batch():
the first promise will resolve after 2 seconds
the 2nd promise will reject
the 3rd query will still be sent to the databsae and returns after 3 more seconds
finally (after a total of 5 seconds), batch is done and we can return an error to the caller.
When we use Promise.all():
the first promise will resolve after 2 seconds
the 2nd promise will reject - and this will rollback the transaciton and release the database connection
now we can already return an error to the caller
the 3rd request would fail immediately with Querying against a released or lost connection.. This is anyway expected, so we can igonre it.
So I'd say that Promise.all is better, because:
it returns immediately after the first error
will not even send the 3rd useless query to the datababase
What am I missing?
Does this maybe this causes other issues: e.g. that a broken connection is returned to the pool, etc.
Method batch caters for scenario where there may be dynamic number of queries created.
It makes sure that all queries are settled (resolved or rejected), so you do not end up with queries being executed against a closed connection, and getting that Querying against a released or lost connection error. It can be bad/confusing, to start getting those errors occur outside of the context, and you can't diagnose what's going on.
Method Promise.all does not settle promises, it stops processing and rejects when the first promise in the array rejects.
And while method batch is still quite useful, as it is more flexible in how it can handle the values, and gives better result/error details than Promise.all, its use today is no longer necessary. It was developed during the ES5 era, when async/await did not exist. But today you can easily replace it with async/await:
Old style:
db.task('get-all-records', t => {
return t.batch([
t.any('SELECT * FROM apples'),
t.any('SELECT * FROM oranges')
]);
})
.then([apples, oranges] => {
// process data here
})
.catch(error => {});
New style:
const {apples, oranges} = await db.task('get-all-records', async t => {
const apples = await t.any('SELECT * FROM apples');
const oranges = await t.any('SELECT * FROM oranges');
return {apples, oranges};
});
The result from the two examples above will be identical, though they are not the same in terms of the execution logic, as the first one is fully asynchronous, while the latter uses async/await, which are blocking operations, they prevent you from even creating the next query, if one before fails.
Extras
The best-performing approach when it comes to executing multiple independent queries (that do not depend on each other), is by concatenating all queries, and executing them all as one query.
For that there is method helpers.concat, plus database method multi, to handle multiple results:
const queries = [
{query: 'SELECT * FROM apples WHERE color = $1', values: ['green']},
'SELECT * FROM oranges'
];
const sql = pgp.helpers.concat(queries);
const [apples, oranges] = await db.multi(sql);
You won't even need a transaction for it, unless some of your independent queries change data.

Async/Await/then in Dart/Flutter

I have a flutter application where I am using the SQFLITE plugin to fetch data from SQLite DB. Here I am facing a weird problem. As per my understanding, we use either async/await or then() function for async programming.
Here I have a db.query() method which is conducting some SQL queries to fetch data from the DB. After this function fetches the data, we do some further processing in the .then() function. However, in this approach, I was facing some issues. From where I am calling this getExpensesByFundId(int fundId)function, it doesn't seem to fetch the data properly. It's supposed to return Future> object which will be then converted to List when the data is available. But when I call it doesn't work.
However, I just did some experimentation with it and added "await" keyword in front of the db.query() function and somehow it just started to work fine. Can you explain why adding the await keyword is solving this issue? I thought when using .then() function, we don't need to use the await keyword.
Here are my codes:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
// The await in the below line is what I'm talking about
await db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
return expenseList;
}
In simple words:
await is meant to interrupt the process flow until the async method has finished.
then however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async method is finished.
In your example, you cannot achieve what you want when you use then because the code is not 'waiting' and the return statement is processed and thus returns an empty list.
When you add the await, you explicitly say: 'don't go further until my Future method is completed (namely the then part).
You could write your code as follows to achieve the same result using only await:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
List<Map<String,dynamic>> expList = await db.query(expTable,where: '$expTable.$expFundId = $fundId');
expList.forEach((Map<String, dynamic> expMap) {
expenseList.add(Expense.fromMap(expMap));
});
return expenseList;
}
You could also choose to use only the then part, but you need to ensure that you call getExpensesByFundId properly afterwards:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
return db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
}
// call either with an await
List<Expense> list = await getExpensesByFundId(1);
// or with a then (knowing that this will not interrupt the process flow and process the next instruction
getExpensesByFundId(1).then((List<Expense> l) { /*...*/ });
Adding to the above answers.
Flutter Application is said to be a step by step execution of code, but it's not like that.
There are a lot of events going to be triggered in the lifecycle of applications like Click Event, Timers, and all. There must be some code that should be running in the background thread.
How background work execute:
So there are two Queues
Microtask Queue
Event Queue
Microtask Queue runs the code which not supposed to be run by any event(click, timer, etc). It can contain both sync and async work.
Event Queue runs when any external click event occurs in the application like Click event, then that block execution done inside the event loop.
The below diagram will explain in detail how execution will proceed.
Note: At any given point of application development Microtask queue will run then only Event Queue will be able to run.
When making class use async for using await its simple logic to make a wait state in your function until your data is retrieve to show.
Example: 1) Its like when you follow click button 2) Data first store in database than Future function use to retrieve data 3) Move that data into variable and than show in screen 4) Variable show like increment in your following/profile.
And then is use one by one step of code, store data in variable and then move to next.
Example: If I click in follow button until data store in variable it continuously retrieve some data to store and not allow next function to run, and if one task is complete than move to another.
Same as your question i was also doing experiment in social media flutter app and this is my understanding. I hope this would help.
A Flutter question from an answer from your answer.
await is meant to interrupt the process flow until the async method has finished. then however does not interrupt the process flow but enables you to run code when the async method is finished. So, I am asking diff. between top down & bottom down process in programming.

Protractor: Why cucumber steps shows as executed before the actual execution happened

I am new to protractor-cucumber. I am trying to execute below step definition from protractor conf.js.
this.Given(/^I go to sparqHomePage$/, function (callback) {
homepage.goToHomePage()
homepage.login(data[0].UserName,data[0].Password).then(callback);
});
this.Then(/^I create a process$/, function () {
homepage.clickDesign();
homepage.clickFlowDesigner();
console.log(params.flow.procName + ' '+ params.flow.procDesc);
designPage.createNewProc(params.flow.procName, params.flow.procDesc);
});
this.Then(/^I should see process is saved in db$/, function (callback) {
var sql = "select * from process where name = ?";
sql = mysql.format(sql, params.flow.procName);
console.log(sql);
dbConn.query(sql, function(err, rows, fields){
if(!err) {
procDbObj = rows;
console.log(rows);
expect(procDbObj[0].name).to.eventually.equal( params.flow.procName);
expect(procDbObj[0].description).to.eventually.equal(params.flow.procDesc).and.notify(callback);
}
});
});
As soon as I start the execution, the console log shows, feature file execution was completed, but the actual execution is not yet completed.
In my 3rd step I am doing some db validation based on the step 1 and step 2 actions. As cucumber trying to execute all the steps before the completion of real execution with browser, my 3rd test is always failing.
How can I make cucumber to wait for step execution is completed before moving to the next step.
You are calling
homepage.goToHomePage() and homepage.login(data[0].UserName,data[0].Password).then(callback);. Are both methods correct promises that are correctly handled? It now looks like it is calling both methods but giving a direct callback before resolving the promise.
As Ross stated, you can also chain the promises, but first be sure the promises are correctly handled
Edit:
As Ross stated, you can also chain the promises, but first be sure the promises are correctly handled.
You can also return the promise in stead of the callback, just use it as this
this.Given(/^I go to sparqHomePage$/, function () {
homepage.goToHomePage();
return homepage.login(data[0].UserName,data[0].Password);
});
homepage.goToHomePage()
homepage.login(data[0].UserName,data[0].Password).then(callback);
I'm not sure exactly what is happening in the first line but I assume thats going to be doing a click, you will need to make that return a promise and re-write it like
homepage.goToHomePage().then(()=>{
homepage.login(data[0].UserName,data[0].Password).then(callback);
})
And then follow this pattern for the rest of your code as I can see this same issue throughout

How to handle protractor test to run in a sequential order

This is my Block which contain an element.element(by.model("$ctrl.benchmark.name"));
This is not present on Dom. It give me error that element is not on page but still execute all lines of code written after it. I want this to handle in sequential way if above passes then go to next only. How can I handle these types of problem in Protractor.
it("Test BenchMark",function(){
browser.getTitle().then(function (name) {
console.log(name);
browser.sleep(2000);
element(by.linkText("Manage Benchmarks")).click();
browser.sleep(4000)
//element(by.xpath("//main[#class='ng-scope']//a[text()='Create Benchmark']")).click();
console.log("megha");
element(by.model("$ctrl.benchmark.name")).sendKeys("bench");
element(by.buttonText("Save")).click();
console.log(megha);
element(by.xpath("//button[#class='dropdown-toggle']")).click();
console.log("dropdown clicked")
});
The behavior which you are expecting will not be handled by Protractor, it will be by testing framework(ex: Jasmine). But
"Jasmine doesn't support failing early, in a single spec. The idea is to give
you all of the failures in case that helps figure out what is really wrong
in your spec"
You can use browser.wait() combined with Expected Conditions.
browser.wait() blocks control flow execution until a promise is resolved, and Expected Conditions all evaluate to a promise.
So in your case, you could use either presenceOf() and/or visibilityOf().
var EC = protractor.ExpectedConditions;
var el = element(by.model("$ctrl.benchmark.name"));
var present = EC.presenceOf(el); // wait for it to be added to DOM
var visible = EC.visibilityOf(el); // wait for it to be visible on page
browser.wait(EC.and(present, visible), 10000); // wait maximum of 10 seconds
// rest of code

How to log/dump/outout dom html

I've tried:
console.log(element('.users').html());
but the only thing I get is
LOG: { name: 'element \'.users\' html', fulfilled: false }
I assume you are using Angular scenario runner.
The element().html() dsl returns a future (see wikipedia). You are logging the future that will eventually contain the element, but at the point when you are calling console.log, the future is not resolved yet - there is no value in there.
Try this:
element('.users').query(function(elm, done) {
console.log(elm.html());
done();
});
The whole scenario runner works as a queue. The test code is executed (synchronously) and each command (eg. element().html in your case) adds some action into this queue. Then, these actions are executed asynchronously - once first action finishes (by calling done()), the second action is executed, etc... Therefore the individual actions can be asynchronous, but the test code is synchronous, which is more readable.