How to move to geb page content that is not visible in the browser window? - selenium

How can I get the geb webdriver to move to an element on the page that may not be in the view of the browser. The element exists on the page and is displayed but there may be a possibility that the element will appear on the bottom of the page and the browser would need to scroll down in order to bring the element into view.
import geb.Page
class myPage extends Page {
static url = "mypage.xhtml"
static at = {title == "myPage"}
static content = {
someElement = {$("#bottomOfPage")}
anotherElement = {$(".someClass",5)}
}
void clickElement(){
//possibility to fail because element may not be displayed in browsers view
//if not in view, scroll to element, then click
someElement.click()
}
}
Using this page as an example, If an element is not in view on the page and possibly at the very bottom, how can I tell the webdriver to bring the element into view? I have some complicated tests that are failing when the page contents are not in view. In some cases, the driver will move to the element even if it's not in view. But I would like to explicitly tell the driver to move to an element if its not in view for the cases that it does not move on its own.
The selenium library does have a moveToElement() function but it only accepts objects of the WebElement class. Using geb, when creating page classes, all elements that are used in my tests are declared in the content section and thus are of the SimplePageContent class. SimplePageContent cannot be casted to a WebElement either. moveToElement(By.id("bottomOfPage")) does work but is not ideal because I do not want hard coded values. Id much rather pass the page content object itself if possible.

From my experience I can say that if you ask WebDriver to click on an element that is not currently in view it will first scroll to that element and then click on it. So you're either hitting some kind of bug if it does not happen or the fact that the element is not in view is not what's causing your element not to be clicked.
If you still want to move to the element explicitly using Actions.moveToElement() then you can easily turn objects returned from your content definition using the fact that they implement Navigator which comes with a firstElement() which you should use if you want to get the first WebElement of a multi element Navigator or singleElement() when your Navigator has exactly one WebElement.
There is also a simpler way, which won't require extracting WebElements from your Navigators - use an interact {} block:
interact {
moveToElement(someElement)
}

Related

Selenium and StaleElementReferenceException

I am using selenium 3.9.1 and java to automate testing of a web application. The web application has some dynamic content based on pressing of a button for example. The page refreshes whenever this button is clicked. A java script runs on button click and updates the DOM I think. At this time, when I try to access the button (which is visible on the page), I get a staleElementReferenceException.
Does Selenium automatically reload the DOM once it is changed? I am relatively new to selenium. I have researched into this and I have tried to refresh the page using driver.navigate().Refresh() to try to see whether this will solve the problem. It does not solve the issue.
Any pointers will be deeply appreciated.
Since the page has been refreshed, the button reference you have is to the button on the old page that no longer exists.
I'd say you need to get a new reference to the button on the refreshed page (eg call FindElementById).
If the page is refreshed all the items in the DOM are now stale. What this means is that all items found before the button press will have to be found again. Any attempts to use those items will more than likely be treated with a stale element exception.
However, if the button click mearilly affects items on the page without having to ask the webserver to give you a new page you could interact with the old items.
You could do something like this:
public void SaveAndAgainClick() throws Exception{
try{
clicksaveButton(); //method to click save button
WebElement someValue = driver.findElement(By.xpath("(//input[#name='someValue'])[1]"));
someValue.click();
}catch (StaleElementException e){
WebElement someValue = driver.findElement(By.xpath("(//input[#name='someValue'])[1]");
someValue.click();
}
}
If findElement gets staleElementError while looking for (//input[#name='someValue'])[1] then it will again try one more time in the catch block and most certainly find the element and clicks on it. Your test will pass if you follow this approach.
Here are the answers to your questions :
A java script runs on button click and updates the DOM I think : If you inspect the HTML of the element through Development Tools / Inspect Element the element attributes will reveal it all.
Consider the following HTML :
<input value="Click me" onclick="alert('Click!')" type="button">
In the given HTML as per the onclick attribute of this element, if you invoke click() method on the WebElement, an alert would be generated. Similarly the onclick attribute may invoke a JavaScript or Ajax which may bring-in/phase-out new/old elements from the HTML DOM
At this time, when I try to access the button I get a staleElementReferenceException : In this case you should induce WebDriverWait for the WebElement to be interactive before attempting to interact with the element. Else you may face either of the following exceptions :
StaleElementReferenceException
WebDriverException
ElementNotInteractableException
InvalidElementStateException
Does Selenium automatically reload the DOM once it is changed? Short answer, Yes it does.
Refresh the page using driver.navigate().refresh() : No invoking driver.navigate().refresh() wouldn't be a optimum solution as it may not invoke the intended JavaScript or Ajax properly. Hence the intended WebElement may not be interactive in a optimum way.

Serenity BDD - How to reload page elements using pagefactory

i'm having a issue regarding element loading using pagefactory:
#Findy(id = painelDeContole)
private WebElementFacade painelDeControleBtn;
The trick is,
on this menu i have to do a mouse-over action on "... mais" to open a sub-menu like this:
But when i call painelDeControleBtn.isVisible() it's return false. (Last image, second icon)
I need some way to reload the page element and truly verify if the element is visible after the mouse-over action.
I've already searched for some method to do this inside PageObject and WebElementFacade but hasn't found any.
I'd like to maintaing the usage of pagefactory if possible..
Because of the way #FindBy loads elements, it may be present on the screen but not yet visible, or it may not wait until the element appears before returning the result. To do this reliably you will get better results with dynamic lookups, e.g.
$("#painelDeContole").isVisible();
or
$("#painelDeContole").waitUntilVisible();

how to override findElements() implementation in selenium with moveTo() each element using java?

I am using selenium webDriver with Java and looking for a solution to find elements by moving to each element in the List at the time of selenium locating it. A solution I am looking for specific to 'ChromeDriver', as chrome driver works with point/coordinates, each time my script failed to execute drag and drop list of elements identified from one location to another.
Scenario description: My application is having two tables (T1 and T2) with the list of 'li and ui' as subitems under each table row. I need to drag and drop 'T2' row/rows 'web elements' to matching web element under 'T1' row(same may be visible or not visible in the viewport during drag and drop- But I have used moveTo() method).
Issue: When I am executing the scripts in Chrome, web elements not present in the current viewport of 'T2' are clicked and dragged to matching 'parent web element' in 'T1'. But after the first run, web page alignment breaks and subsequent drag and drops are failing due to 'previously' identified elements position changed.
I have tried multiple approaches like, click the 'T2 element 1 and move and perform drag and drop, Using javascript executor display the element in viewport etc.. but each time the UI alignment breaks.
I would like to know that if anyone has worked on the custom implementation of 'Selenium FindElements() method with a MoveTo() function'?
something like:
#Override
public List<WebElement> findElements(By arg0) {
List<WebElement> moveAndFind = null;
try{
WebElement firstIndex = Driver.findElement();//Move to first matching element of By argument.
moveAndFind.add(firstIndex); // Collect all the matching elements in the web page by capturing the updated location - specific to Chrome driver
}catch(WebDriverException ex){
ex.printStackTrace();
}
return moveAndFind;
}
To answer specifically to your question, you cannot override the implementation of FindElement (or, since I'm not that familiar with the Java implementation, I'm not aware of something).
Now, to overcome your issue, you have several options:
Since you already have your list created, you could always move from the end of the list. This way, the order of elements is always the same with the initial index.
Use lambda expressions to identify the elements in your list by anything else but index.
Refresh and reconstruct your list after every move of an element. Depending you how many elements you need to move, this may prove to be the worse option performance wise.

Selenium element is hidden behind floating header

The Selenium webdriver locator always puts elements on top of the page if scrolling is needed, but it wont take into account a floating header. At the moment I created a workaround with
Actions actions = new Actions(this.webdriver);
actions.sendKeys(Keys.ARROW_UP).perform();
Isnt there a nicer solution to tell the webdriver to center an element in the middle of the screen instead or with a fixed distance to the top?
The orange part is from the button the blue part is the header:
hidden button in orange
In my case, I choose to hide that floating element.
top = dr.find_element_by_xpath('//div[#node-type="top_all"]')
dr.execute_script("arguments[0].setAttribute('style','display:none')", top)
After that, move to the element I want, I can even add an offset.
Bring the element into view using javascript. Here is a possible solution:
Bring the element into the view port using selenium api.
Use javascript to figure out if the element is obstructed by another element, (floating header / footer etc...).
Use javascript to scroll to the middle of the view port.
See the javascript utility class I created here: https://github.com/gterre/stuff
usage...JavascriptUtils.bringIntoView(WebElement element);
I'm sure you can modify the script to your needs.
Selenium also has the ability to not scroll items to the top of the window before interacting with them (and therefore hiding them behind a floating header) but instead to the bottom.
This is achieved via the 'elementScrollBehavior' capability which can be set to 1 to scroll stuff to the bottom.
See this stack overflow for how it's done in capybara.
I solved the problem like this, so you just need to define in which cases your element is not in scope and add this method, it will automatically scroll it into view:
public void scroll_element_into_view(WebElementFacade element) {
int Y = (element.getLocation().getY() - 200);
JavascriptExecutor js = (JavascriptExecutor) getDriver();
js.executeScript("javascript:window.scrollTo(0," + Y + ");");}
Works for every element you can find by id, css, xpath or whatsoever.

Selenium Webdriver drag'n'drop from parent to child iframe

I've been looking for any working solution to drag'n'drop for the past 5 days.
So,
Selenium.WebDriver 2.44.0
WebDriver.ChromeDriver.win32 2.13.0.0
Chrome latest version.
C#, Page object pattern.
Sorry for russian descriptions on screens :)
We have .net cms. It has pages Editor. Editor opens in parent page, page to edit if loaded in iframe from the same domain.
I need to drag'n'drop items (pictures, video, etc) to a concrete containers in iframe.As far as I understood the following is used in CMS: This file contains following files: jQuery 1.11.1 + jQuery UI 1.10.4 + jQuery Migrate 1.2.1 */).
Piece of code: http://screencast.com/t/ArEk54ue
Here is a scenario during drag'n'drop:
In parent content I select some element id=someelement. (String is not active).
I click and hold on element, pulling it into iframe.
The following code appears in parent page:
Child element appear in String from the 1-st step. It's our element.
See screen: http://screencast.com/t/Cio4knwp
When I pull element to iframe onmouseover event fires and child string appear in the following string:
http://screencast.com/t/cpj3ihlE959
Containers change their color to green on mouseover.
Container code inside iframe:
http://screencast.com/t/Z6QBD6IYuB
What I've tried to do:
Simple webdriver drag'n'drop doesn't work since target element inside iframe.
Drag'n'drop by X,Y offset doesn't work too.
Drag'n'drop using Actions:
MoveToElement:
public Actions MoveToElement(IWebElement element)
{
var builder = new Actions(Webdriver);
return builder.MoveToElement(element);
}
source - picture which I pull
target - container.
WrapperSelenium.MoveToElement(source)
.ClickAndHold(source)
.Build()
.Perform();
WrapperSelenium.SwitchToFrame("WebsiteFrame");
WrapperSelenium.MoveToElement(target)
.Release(target)
.Build()
.Perform();
Doesn't work too.
4.I've tried to use some Javascript hacks, don't remember exactly what - no success.
Now I'm trying ro use jquery-simulate (https://github.com/j-ulrich/jquery-simulate-ext) - I can click an hold element, containers become active, but I can't release element and find target.
Please help!
I decided to use AutoIt - developers made to complex code structure