Reputation: 1165
Using Java and Selenium.
We have a method waitForXPathVisibility(xpath) which eventually ends up calling a wait.untilExpectedConditions... visibilityOfElement. This method works fine. I just abbreviated it here. So trus me that waitForXpathVisibility(xpath) will wait until it is visible.
So we have a page of medical specialties. It was originally just in English. So if you search for "neuro", the HTML will look something like
<ul id="ui-id-1" tabindex="0" class="ui-menu ui-widget ui-widget-content ui-autocomplete ui-front" style="width: 476.672px; position: relative; top: -1005px; left: 542.828px; display: none;">
<LI class="ui-menu-item"> Neurology</Li>
<LI class="ui-menu-item"> Neuro Surgeon </li>
</UL>
then they added Spanish, so not still all results will return but only the Spanish will be visible. A new
<ul id="ui-id-2" tabindex="0" class="ui-menu ui-widget ui-widget-content ui-autocomplete ui-front" style="width: 476.672px; position: relative; top: -1005px; left: 542.828px; display: none;">
<LI class="ui-menu-item"> Neurologa </LI>
<LI class="ui-menu-item"> Neurologo Cirujano </LI>
</UL>
There is a class field in the LI but it is the same for every LI (i.e., no way to distinguish the language from the LI. In addition, the value of 'id' for each is calculated randomly so there is no way to determine from the id. In addition, each new search appends a new ... to the bottom of the previous one. And the UL's, even the displayed one, have "display; none" as part of the style id.
Previously, when doing a search, I would do a
waitForXpathVisibility("//li[@class='ui-menu-item']");
which would return. But the search always finds the first one, so the xpath above will point to the first English one, which will no longer be visible, so it will time out.
Is there a way to wait for any element matching an xpath to be visible? Note that visibilityOfAllElements() will not work, because they will not all be visible.
I suppose what could be done is beforehand get a count of all the elements with @id and with "width" as part of the style. "display; none" will not work because there are other s with this value. Then do the search and wait for the number of s to increase by 1, get the id of the last and then wait for an
Upvotes: 2
Views: 881
Reputation: 25611
I think what you are looking for is
//ul[contains(@class,'ui-menu')][last()]/li
^ finds a UL
^ that contains the 'ui-menu' class
^ get the last one (the one that contains visible elements)
^ get the LI children
You should be able to wait until all of those are visible using visibilityOfAllElements
.
Side note... don't write a method waitForXPathVisibility()
that is restricted to only XPath. That makes it to where you have to write a method for each locator type you use (CSS selector, name, id, etc.). Instead take a By
as a parameter and make it generic. See below.
public void waitForVisibilityOfElement(By locator)
{
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(locator));
}
You can also write one for more than one element
public void waitForVisibilityOfElements(By locator)
{
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(locator));
}
and you use it like
By someElementLocator = By.id("someId");
By someElementLocator = By.xpath("//ul[contains(@class,'ui-menu')][last()]/li"); // or this
By someElementLocator = By.cssSelector("ul.ui-menu"); // or this
waitForVisibilityOfElement(someElementLocator);
Upvotes: 1
Reputation: 33384
Use JavaScript
executor to get the hidden value. If you want to get the value of Neurologa
Try below code.Hope this help.
WebElement element=driver.findElement(By.xpath("(//ul[@id='ui-id-2']/li[@class='ui-menu-item'])[1]"));
JavascriptExecutor js = (JavascriptExecutor) driver;
String output=(String) js.executeScript("return arguments[0].innerHTML;", element);
System.out.println(output);
OR
WebElement element=driver.findElement(By.xpath("//li[@class='ui-menu-item'][normalize-space(text())='Neurologa']"));
JavascriptExecutor js = (JavascriptExecutor) driver;
String output=(String) js.executeScript("return arguments[0].innerHTML;", element);
System.out.println(output);
Upvotes: 0