Why do some elements exist but not interactable/displayed? - java

I'm pretty new to testing, trying to gain a better understanding of what exactly is going on. I'm finding some of our test codes are failing when the css selector element has a waitUntilCanInteract or waitUntilDisplayed attached to it even though when I do a chrome inspect the element is showing up in the browser. Changing them to a waitUntilExists gets them to a passing point so I was wondering what exactly is going on to create this situation?

Precisesly Selenium deals with three unique states of an element.
Presence of element within the html: This state of an element can be detected through the ExpectedCondition presenceOfElementLocated() where the expectation is to check if the element is present in the DOM of a page. This does not necessarily mean that the element is visible.
Exmaple:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("css_of_element")));
Visibility of element within the html: This state of an element can be detected through the ExpectedCondition visibilityOfElementLocated() where the expectation is to check if the element is present in the DOM of a page and visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
Exmaple:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("css_of_element")));
Element to be clickable: This state of an element can be detected through the ExpectedCondition elementToBeClickable() where the expectation is to check if the element visible and enabled so that you can click it.
Exmaple:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("css_of_element")));
You can find a detailed discussion in Selenium: Check for the presence of element

Well, the developers decided to make it so.
See, the elements can exist on the DOM but be invisible or un-interactable. But not the other way around.
If your tests are passing when waitingUntilExists and failing otherwise, you probably have to prolong the waiting period if you want to make them pass. But this is just my guesswork without seeing any of your code.

Simple answer is that sometimes when designer work on web pages especially while working on Foundation CSS framework or bootstrap, they intentionally hide the original CSS/HTML tags and elements while placing foundation or bootstrap based design overlays like fancy buttons on the page which causes the original elements to be hidden.
The best approach may be like:
I. You can declare a WebElement while calling an element to precisely targeting it and using moveToElement command instead of simply calling FindElement.By.xxxxx
ex:
//*** Calling a WebElement and using moveToElement command***//
WebElement (anyElementname) = browser.findElement(By.partialLinkText("xxxxxxxxxxx"));
action.moveToElement(anyElementname).perform();
//*** Waiting for 8 seconds***//
Thread.sleep(8000, 80000);
II. You can use 'waits' for providing page load time and interacting between elements
III. Avoid copying the overlayed css elemenet especially xpath, instead, copy the xpath from the original source of the Div/button/li
Let me know if it works for you or not. Cheers!

Related

Is this correct way to use "switch()" method in selenium?

Aim: To count links in footer section of a webpage.
Instead of this:
WebElement footerdriver=driver.findElement(By.id("gf-BIG"));
system.out.println(footerdriver.findElement(By.tagName("a")).size());
I want to write like this:
WebElement footerdriver=driver.findElement(By.id("gf-BIG"));
driver.switch(footerdriver);
system.out.println(driver.findElement(By.tagName("a")).size());
Is this correct way to use "switch()" method in selenium ?
Unless I am mistaken, switch() is not a method belonging to the Selenium Webdriver. The method switchTo() is used to change your focus to a different window, tab or iframe.
If I am understanding your question you want to find an element that is descending from a different element. The way to do this is just find the element using the WebElement method findElement(By locator). E.g:
driver.get("https://www.wikipedia.org/");
WebElement eng = driver.findElement(By.xpath("//a[#id='js-link-box-en']"));
System.out.println(eng.findElement(By.tagName("span")).getText());
This will find a span element that descends from the element "eng".
Here is a runnable example of a test using the method.
driver.switchTo();
should only be used to either switch to
iframes/frame/frameset
newly windows/tabs
Alerts
defaultContents
therefore,
WebElement footerdriver=driver.findElement(By.id("gf-BIG"));
driver.switch(footerdriver);
this is wrong since you are saying that you want to switch to a web element.
Also in selenium it is switchTo() not switch.

Get last added element of specific class to DOM via xpath

My site generates an arbitrary number of popups (please don't judge my monitization strategy). Each popup is a complex div that I eventually want reference to via xpath, but I specifically want the last one that was added to the DOM, since that will be the one that's on top.
So I tried this
//*[#class="popupContent"][last()]
I know I could try this
(//*[#class="popupContent"])[2]
but I have no idea how many of these popups there are.
But in the case of having multiple popups on screen at once, I get a reference to the first one (I'm not sure if this is reliably the case or not). Each of these popups has a popupContainer, but for the sake of this question, it is off limits.
Given that there are multiple elements with this class, how can I get the one that is on top (and thus interactive)?
These things aren't siblings, children, or parents of each other. Also, I have no idea how many exist on the page at any given time. I also do not have any control over the content or structure of the popups beyond that I know the class for one of their internal components (popupContent).
If this is not possible, please explain why.
I'm looking for a solution that will be compatible in a Java Selenium testing environment. No jquery please.
According to this question: Do WebDriver findElements retain the Table rows order on its retrieval findElements guarantees order, so in a Selenium environment, I could get the list from that and retrieve the last item.
List<WebElement> popups = findElements(By.classname("popup"));
WebElement activePopup = popups.get(popups.size - 1);
Xpath (//*[#class="popupContent"])[last()] and code below should give you same result - last element in the DOM:
List<WebElement> popups = driver.findElements(By.className("popup"));
WebElement activePopup = popups.get(popups.size - 1);
If last element not the top one try to get focused element:
WebElement focused = driver.switchTo().activeElement();
if (focused.getAttribute("class").equals("popupContent"))
//my active/interactive popup
You can check if last one is active now:
WebElement lastOne = driver.findElement(By.xpath("(//*[#class="popupContent"])[last()]"));
if (lastOne.equals(driver.switchTo().activeElement()))
//last one is active
Another approach could be to look for the popup with the highest z-index value:
private WebElement getTopPopUp() {
List<WebElement> allPopUps = driver.findElements(By.classname("popup"));
WebElement topPopUp = allPopUs.get(0);
for(WebElement popUp : allPopUs) {
if(Integer.parseInt(popUp.getCssValue("z-index")) > Integer.parseInt(topPopUp.getCssValue("z-index"))) {
topPopUp = popUp;
}
}
return topPopUp;
}

Selenium - Check if an element is under another one

I'm using Selenium to do Java test.
I know that i can check if an element is enable or displayed with this :
isDisplayed
isEnabled
Is it possible to check if an element is not visible, in the case that this element is under another ? For example, if a div is under another one.
With that i want to check GUI element. For example if a button move under element, etc ...
Any ideas ?
thanks for helping _
selenium.isElementPresent() or selenium.isVisible()
those may help you.
isElementPresent() - This method basically tests if the element we are looking for is present somewhere on the page.
isVisible() - looks for display: none style tag - this might throw a null pointer if we aren't careful...thus to see if an element is visible first check if the element is present using isElementPresent() method. Then try checking if the element is visible!
I think constructing your locator like this might do it.
By TOP = By.xpath(".//div");
By UNDER = By.xpath("..//..//div");
By elementUNDERtheTOP = new ByChained(TOP, UNDER);
This is the equivilant of:
driver.findElement(TOP).findElement(UNDER);
This is possible to do with XPath but I don't think you could do this with a CSS locator because a CSS locator would not be able to traverse up the DOM tree to parent elements.
Lets say you want to click an element, but that element is "behind"/"below" (aka 'obstructed' by anlother element), Selenium will actually throw a ElementClickIntercepted exception. As part of the exception message, it also returns which point you tried to click and which other element (tag, class) did intercept the click. By simply attemping to click an element and specifically catching this type of exception, you get the information you're looking for, if you catch such an exception => element not clickable (at the given coordinates - in most cases the default click point (or if you use actions: the offset you define)), if no exception => element is clickable.
The solution for Python is here.
It should be easy to convert it to Java.

Selenium xpath gives matches only the visible elements

Selenium xpath gives matches only the visible elements. The HTML page contains lots of other elements which are not visible but present. When trying out the xpath on chrome console, it displays all the elements including the elements which are not visible. But when using the same xpath in selenium, it returns only elements which are visible at that point in time. Is this an expected behavior?
Yes, it's right. I also tried to made reference to elements that weren't in my page (because they were invisible) but I couldn't do that. If the elements are visible in the page you will have access to them.
I recommend you that, if this elements would be visible in some moment, for example, clicking a button, you will have to automatize all the proccess with Selenium and then made reference to them with Xpath, JQuery or whatever you want.
I expect it solves your doubts.

Selenium FirefoxDriver clicks on wrong link when animations occur

I am using Selenium 2.35 and having a unpredictable error while trying to click on an element in firefox like this:
new Actions(driver).moveToElement(element).click().perform();
The element I've located is a < span > element with a click event tied to it. The issue I am running into is occasionally when Firefox tries to click on the element is misses and clicks on an entirely different element. If I walk through my code using the debugger the issue never occurs which leads me to believe that the FirefoxDriver is just clicking on the wrong location on the browser, having to do with a timing issue. There are dynamically loaded < div >'s on my page that make the element I want to click shift down just before I locate it and send the .click() command. I believe this is the source of my issue. I can put a Thread.sleep(500) is ensure that it has enough time to finish animating and inserting the dynamic divs, but that seems sloppy to me. Is there a way I can tell my FirefoxDriver to wait until the elements on the screen are done shifting around before it tries to send the .click() event?
Also, I have tried to send just the element.click() but that seems to fail more often.
Update (9/5/13):
The solution I came to with the help of #MrTi 's comment was the following:
private void jsClickOnElementById(String id)
{
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id(id)));
JavascriptExecutor js = (JavascriptExecutor)driver;
StringBuilder sb = new StringBuilder();
sb.append("var x = $('#" + id + "');");
sb.append("x.click();");
js.executeScript(sb.toString());
}
Just to ensure the element is actually on the page I added the initial "wait" call, and then use the JavascriptExecutor to run some jquery and click on the element on the page. This seems to work great for my case. If anyone has help as to some drawbacks to this solution they would be greatly appreciated as I'm fairly new to the JavascriptExecutor class.
In addition to ensuring that the page is actually visible with ExpectedConditions, this situation could be solved by handling animations (transitions) on page.
It's possible to disable all the animations on page, until page is refreshed, by executing:
(JavascriptExecutor)driver.executeScript("$('body').append('<style> * {transition: none!important;}</style>')")
Also, If you know the specific element that got the animation you can check if it's animated (JQuery animation selector):
(Boolean)((JavascriptExecutor)driver).executeScript("return $("#ELEMENT_ID").is(":animated")")
If the specific element unknown you can determine if all animations have finished:
(Boolean)((JavascriptExecutor)driver).executeScript("return $(":animated").length == 0 ")
Sadly in 2018 (five years later) I can confirm element.click() in selenium doesn't always click the right element. I still have to shell-out to jquery with JavascriptExecutor to click on an element by ID via jquery $(selector).click() to hit the element with confidence.
And it's NOT just that it can't find the element due to scrolls, animation, or offscreen, it appears Selenium's wrapper of Marionette's internal DOM tree is out of sync with firefox's geckodriver somehow for dynamically loaded elements (in this case a table row)
I believe what is happening is that the dynamic loading is making your selector select something else. If you post your HTML, (especially the before/after the dynamic loading) that would be immensely helpful in writing a better selector.
However, there are a couple of ways to wait until the loading is finished.
The first to wait until (Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0") returns true. This waits for all JQuery on the page to finish (which is probably what is causing the dynamic loading). Its useful, but I would recomment waiting for something else.
The second option is to wait until an element that is dynamically loaded is present:
wait.until(ExpectedConditions.presenceOfElementSelectedBy(...selector...));
I like this method, as it will wait exactly as long as you need to wait, and no longer.
The final option is to write a selector that will always select the element, even if other stuff is going on. This may be your best option, but you may also run into StaleElementReferenceExceptions.

Categories

Resources