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

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

Related

Should I await expect(<async>) conditions

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 .

If one Expect fails in protractor, will the spec execution continues?

I have two "expect" in my it block and my first it block failed,it still continues the execution and executing the rest of the code in my it block.
My expectation is, if first it block failed, execution stops right there and next it block should get executed.
it ("My se", function() {
expect(true).toBe(false);// it is failing
//my rest of my below code should not get executed.
My functionality code
expect(array[0]).toBe("foo");
});
it ("Second it block", function() {
//Continue the execution
});
Could some please help me with some idea, how i can achieve this. My execution of that particualr it block should stop and the next it should continue.
Ideally, expect statement should be the last statement of the it block. You need to update the test in that way to achieve the desired results.

assert.async() never fails

I am new to OpenUI5/QUnit testing. Sorry for the newbie question.
I have added a very basic async QUnit test into my OpenUI5 project:
QUnit.test( "Test async", function( assert ) {
var done = assert.async();
setTimeout(function() {
assert.ok(true);
done();
});
});
This test passes without errors as expected.
Then I have commented out everything except for
var done = assert.async();
The test runs indefinitely without failing. I would expect that it fails after some timeout.
Pressing the "Abort" button just changes the label to "Aborting" but does not fail the test.
I have search the QUnit documentation, that suggest adding
assert.timeout( 1000 ); // Timeout of 1 second
that should be an equivalent to global setting
QUnit.config.testTimeout( 1000 );
But using either crash my test with
assert.timeout is not a function
or
QUnit.config.testTimeout is not a function
I have tried running the test in Chrome, Firefox and IE11 with the same results.
Can anyone tell me what I am doing wrong?
I have found the answer myself. The correct syntax is:
QUnit.config.testTimeout = 1000;
It is then valid for all the subsequent tests. Alternatively I can write
assert.timeout(1000);
at the beginning of the test method - must be before assert.async()

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.