Here is my code. For some reason it cannot detect the element present, and just times out. Site is in angular. I have tried isPresent, as well as ExpectedConditions and it times out nonetheless. For some reason, it just cannot detect the element no matter how I try to locate it. I have tried multiple elements as well. I'm open to any ideas.
browser.wait(function()
{
return browser.isElementPresent(by.xpath('//[#id="ngdialog1"]/div[2]/div/div')).then(function(present)
{
console.log('\n' + 'looking for element')
if(present)
{
console.log('\n' + 'recognized dialog');
var jccSelect = element(by.xpath('//*[#id="ghId_GameSelectBottomRow"]/div[1]'));
jccSelect.click();
return true;
}
})}, 50000);
});
You have kept return statement in if(present){return true;}, if present value is false then control will not be return, that's why your getting timed out issue.
I have rearranged the code as below:
EC = protractor.ExpectedConditions;
targetElement=element(by.xpath('//[#id="ngdialog1"]/div[2]/div/div'));
browser.wait(function(){
return EC.visibilityOf(targetElement).call().then(function(present){
console.log('\n' + 'looking for element')
if(present)
{
//do what would you like to do
return true;
}
else{
//do what would you like to do
return false;
}
});
}, 50000);
Related
My if condition in the following code is not working ....
I thought my if condition would be wrong but then the code should have invoked the else condition but it is not doing soo.
class polyline {
List<LatLng> _listltlg=[];
start_record() {
BackgroundLocation.startLocationService();
BackgroundLocation.getLocationUpdates((location) {
if(_listltlg.isEmpty){
print('2nd if statement');
_listltlg.add(LatLng(location.latitude, location.longitude));
}
else{
print('Else case');
}
});
}
It is correct, the first time the callback is called, the list "_listltlg" IS empty.
I am doing E2E Test with protractor, using cucumber for test scenarios.
I face a strange problem: I lost the values I set inside of the promise.
What am I doing wrong?
My step-file.js:
var loggedUser = new User("dummyname", "dummyrole");
this.When(/^I click on a user name$/, function(){
userelem.element(by.className('username')).getText().then(function (txt) {
loggedUser.username = txt;
});
});
this.Then(/^The username of the object "loggedUser" is set to a new value$/, function(){
var answer = "dummyname" != loggedUser.username;
assert.isOk(answer, "username is still dummyname!"); //this line fails since usrname is set back to dummyname again!
});
Thank you #yong for your suggestion on my first post (which I have deleted meanwhile). Finally I understood what you meant. Here is the solution:
(Instead of upgrading to cucumber 2,) I "return" the promise from within the "When-Step", so that protractor waits until it is fullfilled before it executes the next step-function:
var loggedUser = new User("dummyname", "dummyrole");
this.When(/^I click on a user name$/, function(){
return userelem.element(by.className('username')).getText().then(function (txt) {
loggedUser.username = txt;
});
});
Now in the next step-functions, the username is the updated username.
The root cause is you need to make each step definition return a promise, I write a simple code for you and it worked well.
Make step definition return a promise is the key point.
For Cucumber 2:
var { defineSupportCode } = require("cucumber");
defineSupportCode(function({ Given, When, Then }) {
let title = 'test';
Given(/^open npmjs.com$/, function() {
browser.get("http://www.npmjs.com");
return browser.getTitle().then(function(title1){
title = title1;
console.log('title: ' + title);
});
});
Then(/^verify page title$/, function() {
return expect(title).to.equal('npm');
});
});
For Cucumber 1:
module.exports = function() {
let title = 'test';
this.Given(/^open npmjs.com$/, function() {
browser.get("http://www.npmjs.com");
return browser.getTitle().then(function(title1){
title = title1;
console.log('title: ' + title);
});
});
this.Then(/^verify page title$/, function() {
return expect(title).to.equal('npm');
});
};
I am using protractor-cucumber-framework and I wanted to generate html report for the tests I wrote. I decided to use cucumber-html-reporter to achieve it. In my hooks.js I wrote a this.After object to take screenshot on test failure:
this.After(function(scenario, callback) {
if (scenario.isFailed()) {
browser.takeScreenshot().then(function(buffer) {
return scenario.attach(new Buffer(buffer, 'base64'), function(err) {
callback(err);
});
});
}
else {
callback();
}
});
Everything works just fine, the report is generated and the screenshots are taken and attached only on test failure. But I also got an error message when After step is proceeded (so when there is some failure):
function timed out after 5000 milliseconds
I would like to get rid of this message as it also appears on my html report. Can anyone provide me solution to do that?
Below code is working for me. I have added this in step definition js file. At the end of scenario in the report, it adds the screenshot.
defineSupportCode(({After}) => {
After(function(scenario) {
if (scenario.isFailed()) {
var attach = this.attach;
return browser.takeScreenshot().then(function(png) {
var decodedImage = new Buffer(png, "base64");
return attach(decodedImage, "image/png");
});
}
});
});
I had similar problem and it failed even after waiting for 60 seconds. The issue was that i didn't had proper callback implemented.
The below code worked for me. ( I am new to JavaScript and so my callback usage might be the right way. Please feel free to educate me if there is better way to do it. :))
After(function(scenario,done)
{
const world = this;
if (scenario.result.status === 'failed') {
browser.takeScreenshot().then(function (stream) {
let decodedImage = new Buffer(stream.replace(/^data:image\/(png|gif|jpeg);base64,/, ''), 'base64');
world.attach(decodedImage, 'image/png');
}).then(function () {
done();
});
}else {
done();
}
});
Your code seems absolutely fine.
Perhaps, it just needs longer timeouts?
You can set a timeout on hooks like this:
this.After({ timeout: 20 * 1000 }, function (scenario, callback) {
if (scenario.isFailed()) {
browser.takeScreenshot().then(function(buffer) {
return scenario.attach(new Buffer(buffer, 'base64'), function(err) {
callback(err);
});
});
}
else {
callback();
}
});
am trying to check element on regular interval and click only if it is present. Some times this element appears in 2-3 minutes. If it is not present, i want to wait for few seconds and then refresh page
Here is what i tried:
for(var i = 1; i < 60; i++){
element(that.proposalByOrderPath(num)).isPresent().then(function(result){
if(result){
console.log(i);
return element(that.proposalByOrderPath(num)).click();
}
else{
browser.sleep(15000);
browser.refresh();
}
});
}
As an output, it prints 60 twice. It clicks on the element once but tries to look again for the element and throws "element not visible" error.
This is a closure issue. For more understanding read the following-
How do JavaScript closures work?
http://www.w3schools.com/js/js_function_closures.asp
We can solve async call in for loop with any of following 3 ways:
Callback
var a = function(callback){
//code
callback();
}
var b = function(){
for(loop details){
that.a(function(){
})
}
}
By recursive call of function instead of using for loop
By self iteration
for(loop details){
(function(i){
//your code
})(i);
}
It seems if I use element(by.css('#id')); protractor sometimes finds it, sometimes doesn't. Depends if the DOM is settled down or not. I've gone and some this:
getElementsByCss: function (cssVal) {
// return element.all((by.css(cssVal)));
return self.wait(function () {
return element.all((by.css(cssVal))).then(function (els) {
return els;
}, function () {
return false; // Don't fail, we want to retry
});
}, GET_ELEMENT_TIMEOUT, 'Elements not found by css: ' + cssVal);
},
which plays a game of retrying to get the element for some timeout period. We use 5 seconds. This seems to work, most of the time. When running locally we have no issues.
When we run on the cloud (sauce labs) they have exceedingly slow VMs. We still get random issues. Unfortunately these games have to be played everywhere, for example:
getText: function (el) {
return self.wait(function () {
return el.getText();
}, 1000, 'Could not get element text.');
},
or
expectBulletin: function () {
var el, text;
return self.wait(function () {
// Find the bulleting element, make sure it's visible and grab its text.
// If any of those three fail, try all of them again.
return self.getElementByCss('.bulletin')
.then(function (elm) {
el = elm;
return self.isElementVisible(el);
}, function () {
return false;
})
.then(function () {
return self.getText(el).then(function (text) {
return text;
}, function () {
return false;
});
}, function () {
return false;
});
}, 10000, 'Count not get bulletin text.')
.then(function (result) {
text = result;
return self.executeScript('arguments[0].click();', el.getWebElement());
})
.then(function () {
return self.isElementNotVisible(el);
})
.then(function () {
return text;
});
},
all the self.waits are just a browser.driver.wait wrapper...
wait: function (fn, timeout, msg) {
return browser.driver.wait(fn, timeout, msg);
},
This feels like a big pack of bandaids and its not working all the time. expectBulletin works 99% of the time locally, but when run remotely on the slow VMs, it works about 50% of the time. Sometimes the text comes back blank, or issues about clicking an invisible element or just not finding the bulletin element.
Is there any better way to do this?
it seems if I use element(by.css('#id')); protractor sometimes finds
it, sometimes doesn't.
You know that it returns a promise right? If you want to get the absolute value of an element, you have to handle its promise first.
Protractor waits for the page to be ready before doing any assertions. If your page is "ready" but some data is missing, there is something wrong with your angular application.