Protractor waiting for element to be in DOM - angularjs

I have been having some trouble using Protractor. I have a really weird ui-router state where its hard to go off of other elements to start working with the page. Is there any way to tell protractor to wait until an element finally appears in the DOM? Not visible/displayed, but actually created? I keep trying to use wait for the element but it is clearly not available to be selected.
browser.driver.wait(function () {
return elem.isDisplayed();
});

You should be able to use browser.wait together with the presenceOf ExpectedCondition:
var until = protractor.ExpectedConditions;
browser.wait(until.presenceOf(elem), 5000, 'Element taking too long to appear in the DOM');

Protractor has included ExpectedCondition for explicit wait which lets you wait for the element for certain period of time. You should be able to do the following:
var EC = protractor.ExpectedConditions;
browser.driver.wait(function () {
browser.wait(EC.visibilityOf(elem), 10000);
return elem;
});

the first parameter of browser.wait is a function, if we need to wait until an element is present irrespective of time, then we can use the below code, If you need to restrict the wait to a particular time please give time as second parameter of 'browser.wait'
browser.wait(function() {
return element(by.css("#edudrop1")).isPresent()});

Related

How to achieve Recursion in angularJS

if(url.toUpperCase().indexOf("SKILL") != -1) {
$timeout(function () {
$("#ABC").click();
}, 500)
}
I am using $timeout to click the skill button and load the grid on U-I . Above code is not loading the U-I, but if i increase the time from 500 to 2500 then code is working properly, but I don't want to increase the timeout. Is it possible to use recursion so my code would work without increasing timeout?
Set this condition inside document ready. Maybe javascript don't found the elements, because them must be loaded first.
$(document).ready(function(){
//here
});

Protractor - How to get the element that I just performed an action?

I am using protractor to write some e2e tests for an app written in AngularJS, and I want to perform the following task:
element(by.id('btn1')).click().then(function() {
// I want to get the element that I just clicked, and check its label
// How I can pass (if possible) the element to the then() function?
});
currently what I do is:
element(by.id('btn1')).click().then(function() {
expect(element(by.id('btn1')).getText()).toBe('cancel');
});
Thanks in advance,
Kai
The problem is, the click() promise is of type webdriver.promise.Promise.<void> so there's nothing passed in to the resolver.
Simply store the element reference in a variable to re-use it
var btn = element(by.id('btn1'));
btn.click().then(function() {
expect(btn.getText()).toEqual('cancel');
});

Watch for dom element in AngularJS

I'm looking for a pure angularJS way to call a controller method once a particular dom element is rendered. I'm implementing the scenario of a back button tap, so I need to scroll to a particular element once it is rendered. I'm using http://mobileangularui.com/docs/#scrollable.
Update: how my controller looks like:
$scope.item_ready=function(){
return document.getElementById($scope.item_dom_id).length;
};
$scope.$watch('item_ready', function(new_value, old_value, scope){
//run once on page load, and angular.element() is empty as the element is not yet rendered
});
Thanks
One hack that you could do and I emphasize hack here but sometimes it's just what you need is watch the DOM for changes and execute a function when the DOM hasn't changed for 500ms which is accepted as a fair value to say that the DOM has loaded. A code for this would look like the following:
// HACK: run this when the dom hasn't changed for 500ms logic
var broadcast = function () {};
if (document.addEventListener) {
document.addEventListener("DOMSubtreeModified", function (e) {
//If less than 500 milliseconds have passed, the previous broadcast will be cleared.
clearTimeout(broadcast)
broadcast = $window.setTimeout(function () {
//This will only fire after 500 ms have passed with no changes
// run your code here
}, 10)
});
}
Read this post Calling a function when ng-repeat has finished
But don't look at the accepted answer, use the 3rd answer down by #Josep by using a filter to iterate through all your repeat items and call the function once the $last property returns true.
However instead of using $emit, run your function...This way you don't have to rely on $watch. Have used it and works like a charm...

Dealing synchronously in Protractor tests

I'm trying to write what I think is a fairly simple test in protractor, but it would seem that the minute you try to do anything synchronously, Protractor makes life hard for you! Normally, dealing with locator functions (that return a promise) are not an issue, since any expect statement will automatically resolve any promise statement passed to it before testing the assertion. However, what I'm trying to do involves resolving these locator promises before the expect statement so that I can conditionally execute some test logic. Consider (pseudocode):
// Imagine I have a number of possible elements on the page
// and I wish to know which are on the page before continuing with a test.
forEach(elementImLookingFor){
if (elementImLookingFor.isPresent) {
// record the fact that the element is (or isnt) present
}
}
// Now do something for the elements that were not found
However, in my above example, the 'isPresent' call returns a promise, so can't actually be called in that way. Calling it as a promise (i.e. with a then) means that my forEach block exits before I've recorded if the element is present on the page or not.
I'm drawing a blank about how to go about this, has anyone encountered something similar?
I've used bluebird to do the following;
it('element should be present', function(done)
Promise.cast(elementImLookingFor.isPresent)
.then(function(present){
expect(present).toBeTruthy();
})
.nodeify(done);
});
If you have a few elements that you want to check the isPresent on you should be able to do the following;
it('check all elements are present', function(done){
var promises = [element1, element2].map(function(elm){
return elm.isPresent();
});
// wait until all promises resolve
Promise.all(promises)
.then(function(presentValues){
// check that all resolved values is true
expect(presentValues.every(function(present){
return present;
})).toBeTruthy();
})
.nodeify(done);
});
Hope this helps
So elementImLookingFor is a promise returned by element.all, I presume? Or, as stated in the Protractor documentation, an ElementArrayFinder. You can call the method .each() on it and pass it a function that expects things.

Test for scrolling

In my angular application, I have a page that has nav links on the side, that, when clicked, scrolls the page down to a matching element.
How do I write e2e test for this in protractor? Is there something like "Grab the first visible h1" or something like that?
You can use javascript's window.pageYOffset for this.
Here's how I've done it in one of my own test case:
browser.driver.sleep(2000);
browser.executeScript('return window.pageYOffset;').then(function(pos) {
expect(pos).to.be.at.most(100);
});
Where 100 is my expected position.
Note: I'm using mocha and chai instead of jasmine. So, just change the last line accordingly. Also I'm waiting 2 seconds for my scrolling to complete.
You should be able to grab the first h1 element that is in the page with something like this:
$$('h1').first().getText().then(function (h1Txt) {
expect(h1Txt).toEqual('Correct h1 text');
});
or use a specific index to find the right h1:
$$('h1').then(function (h1tagList) {
var h1Text = h1tagList[0].getText();
expect(h1Text).toEqual('Correct h1 text');
});
If it is not visible on the page at the time it tries to read the text it should throw an error like element not reachable or something like that.
You can sipmly use a scroll down function :
var filter = browser.findElement(by.id('idvalue'));
var scrollIntoView = function () {
arguments[0].scrollIntoView();
}
browser.executeScript(scrollIntoView, filter);

Resources