Serenity BDD - How to reload page elements using pagefactory - serenity-bdd

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();

Related

Robot Framework- Loading Spinner selector

I have this problem where I have to validate if a loading spinner is present, it's present for about 1 second on the page, i have found the xpath selector of the loading spinner but selenium library could not find it is there another way to find out a selector of something that dissapears after a short while? Note: The xpath is definitely correct. There is no id on the loading spinner either.
This is the code i have tried
Validate Loading Spinner
Wait until page contains xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I have also tried Element should contain and Page should contain but that does not find the locator.
You should be using one of the keywords that is validating an element is present - Wait Until Element Is Visible, or Wait Until Page Contains Element - both of which support a timeout argument, for how much to wait.
Afterwards, you'd better use the opposite keyword - Wait Until Element Is Not Visible, to make sure the spinner disappears and you can continue with the test.
There is a problem with your locator - xpath has some issues if the element is svg, most of the times it can't address it directly. So instead of specifying it explicitly in the path, look for a node whose name happens to be "svg"; e.g.:
xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
(^ changed the last element in the path)
Slightly offtopic - try to have less rigid locators - this one specifies an absolute path from the element with id "app" and down (a div child, then its first div child, then that one's third div child, and so on and so forth). If the element structure changes even slightly, the locator will stop working (say, in a bug fix, or re-positioning it, or just with using a HF of an JS library).
Try to find an element that's 1-2 levels higher than your target svg - by a solid class value, or structure that's unique, and use it as an anchor.
I reckon you used wrong keyword
Validate Loading Spinner
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
Both work:
Validate Loading Spinner
wait until page contains element xpath=//*
[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
and
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I had a very similar issue

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.

Using pagefactory can initialize webelement with visible element, if FindBy matches multiple webelement on the page

I have a page which has multiple button 'OK' for different sections. However, at any given point of time only one 'OK' button is visible and can be identified using advanced xpath mechanisms (But not always)
//button[#value='OK' and not(#style='')]
My Question here is that, can i extend the class PageFactory and override the initialize function by enhancing it by adding a mechanism which processes all the webelements returned by #FindBy decoraters. I will check which one is visible using .isDiplayed() and assign the visible one? This way, i need not have multiple lines of code across pages.
Currently more elements are matched for xpath //button[#value='OK'] and hence i am getting NoSuchElementException. Ideally there should be AmbiguousElementException, but we dont have any such...
Any help or pointers here please?

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

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)
}

How to click on Toolbar Item with selenium?

Web page contain a button with some text for example "Test". This button actually is a toolbar element. ( class ="tbButton" id="id",text="Test") and redirects to a certain table when press on it.
When try to use the following click methods
selenium.click("id");
selenium.doubleClick("id");
selenium.click("//*[text()='Test'and contains(#class, 'tbButton')] ");
the button does not react
Could enybody show an alternative methods that is able to resolve a problem
It's hard to know exactly what the problem is without knowing more about the actual contents of the page you are testing. Is there an example of the toolbar online somewhere?
With modern interfaces, locating elements with Selenium is not always an exact science. Here are a few suggestions:
With modern interfaces you often find that the DOM is being manipulated, so it is possible that the identifier you are using is no longer valid by the time you get to your click(). Use Firebug to check that you have the correct element.
Often it helps to click on the parent of the element, such as a div or the parent table cell. Again, use FireBug, to try some other elements near your toolbar button. Alternatively, Firebug sometimes reveals that the element contains other elements. You might have more luck changing the target to a contained element instead.
Sometimes you have to play around with some of the alternative actions. For instance, some controls respond to a mouseDown() followed by a mouseUp(), but not to a click(). Again you can often get hints from looking at the source with Firebug.