I use Appium with Java to automate tests for mobile application. I'm looking for a way to find element by 2 parameters. I.e. by accessibilityId and by xPath within this element. So really rough example to visualize what I mean
Element el = driver.findElementByAccessibilityId("name").isDisplayed();
Assert.assertTrue(el.findElement(By.xPath("//android.widget.TextView[#text='texty']")));
Is this correct way to do this? Is there a better way? Ideal would be one liner because it is easier to understand
isDisplayed() does not return MobileElement/WebElement it returns a Boolean so a valid way is something like mentioned below
WebElement el = driver.findElementByAccessibilityId("name");
if (e1.isDisplayed()){
WebElement e2 = el.findElement(By.XPath("//android.widget.TextView[#text='texty']"))
}
Assert.assertTrue(e2.isDisplayed());
You can chain any number of findElement e.g.
WebElement innerElement =
driver.findElement(By.AccessbilityID("someID"))
.findElement(By.xpath("someXpath"))
.findElement(By.cssSelector(".aValidCSSClass"));
If you use findElements you have to use it like this as it return List of WebElement or List of MobileElement
WebElement innerElement =
driver.findElements(By.AccessbilityID("someID"))
.get(2) //get 2nd element
.findElements(By.xpath("someXpath"))
.get(1) //get 1st element
.findElement(By.cssSelector(".aValidCSSClass"));
Related
I have the following code:
List<MobileElement> messages = driver.findElements (By.id ("body_bubble")); //find all messages
MobileElement lastMessage = messages.get (messages.size () - 1); //get last message
// xpath query to check if the message is delivered
String xpathDeliveryStatus = ".//*[contains(#resource-id, 'delivered_indicator') or contains(#resource-id, 'read_indicator') or contains(#resource-id, 'sent_indicator')]";
MobileElement deliveryStatus = lastMessage.findElement (By.xpath (xpathDeliveryStatus));
I want to do the same except that I want to find the deliveryStatus variable using explicit wait.
So I want to find the deliveryStatus variable inside the lastMessage variable using wait.until (ExpectedConditions.visibilityOfElementLocated (By.locator))
How can I do this?
I don't want to do it using one immense Xpath. Besides, I don't even know how to find the last element with the id body_bubble using Xpath, as the number of these elements is not fixed and always changing.
P.S. For example, in Python we can define WebDriverWait with an element in the constructor instead of driver:
WebDriverWait(webelement, self.timeout)
Unfortunately, it does not work in Java.
Based on the Java documentation on ExpectedConditions, it looks like we can use presenceOfNestedElementLocatedBy to add explicit wait on the child element:
WebDriverWait wait = new WebDriverWait(driver, 15);
WebElement childElem = wait.until(
ExpectedConditions.presenceOfNestedElementLocatedBy(lastMessage, By.xpath(xpathDeliveryStatus)));
First one in list is easy since you can use find Element. I find the element and need to get information from preceding and following divs. For the "n" element in the list, what is the xPath syntax for moving/backwards to other associated divs?
I have tried various x path following syntax such as:
following-sibling::div
/following-sibling::div
./following-sibling::div
And many others. I just have not found the documentation for the correct syntax.
Preceding:
Select all nodes that come before the current node as shown in the below screen.
Following-sibling:
Select the following siblings of the context node. Siblings are at the same level of the current node as shown in the below screen. It will find the element after the current node.
Here you can find the correct syntax with examples.
You can also use drive.findElements(); method in order to find similar elements. It will return you the collection of elements which you can iterate to get the information.
This answer is entirely dependent on what HTML is displayed on the page you are trying to automate.
Without that context, I can only provide a generic answer, but here's how I would loop through a list of elements and grab information from preceding / following div's:
// locate the elements you want to iterate
List<WebElement> elements_to_iterate = driver.findElements(By.xpath(someLocatorHere))
// iterate the elements in a foreach loop
for (WebElement element : elements_to_iterate) {
// get preceding sibling
WebElement preceding_element = element.find_element_by_xpath("./preceding-sibling::div")
print(preceding_element.getText())
// get following sibling
WebElement following_element = element.find_element_by_xpath("./following-sibling::div")
print(following_element.getText())
}
As I mentioned, this is just a generic solution to give you an idea of how this would work. If you want some assistance with the locator strategy, posting your HTML would be helpful.
If you want to find multiple elements then please find below example for your reference. Based on your site you need to implement same kind of logic.
Please refer above screenshot where I am trying to get label of two highlighted button from google
public static void main(String[] args) throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.google.com"); // URL in the browser
driver.manage().window().maximize(); // Maximize the browser
String expectedTooltip="Search";
List<WebElement> Listelements = driver.findElements(By.xpath("//div[#class='FPdoLc VlcLAe']//input"));
for (WebElement element: Listelements)
{
System.out.println("Element Text::"+element.getAttribute("aria-label"));
}
driver.close();
}
output:
Element Text::Google Search
Element Text::I'm Feeling Lucky
since the first one is easy; each elementList has a current-time and at least one picture
for (i=1; i < elementList.size(); i++) {
WebElement nextInList = elmentList(i);
WebElement getTime = nextInList.findElement(By.xpath("following::div[contains(#class, 'current-time')]"));
.
.
.
WebElement picture = nextInList.findElement(By.xpath("preceding::a[1]"));
.
}
I have the following HTML code:
I need to refer to the span element (last element in the tree) in order to check if it exists.
The problem is, I can't find the right XPath to it and was not able to find any question already concerning this specific issue.
I tried:
"//span[#data-highlighted='true']"
and also further successional XPaths referring to its previous nodes but was not able to actually get a working Xpath. The difficulty for me is that it has no id or title so I tried to get it through its "data-highlighted" but that does not seem to work.
Just for the sake of completeness:
I have written the following Java method which is meant to get an Xpath as its input:
public Boolean webelementIsPresent (String inputXpath) throws InterruptedException {
return driver.findElements(By.xpath(inputXpath)).size()>0;
}
Then in a test class I perform an assertTrue wether the webelement exists (the method returns a True) or wether it doesn't.
I'm open for any help, thanks in advance! :)
To identify the element "//span[#data-highlighted='true']" you can use the following xpath :
"//table[#class='GJBYOXIDAQ']/tbody//tr/td/div[#class='GJBYOXIDPL' and #id='descriptionZoom']/table/tbody/tr/td/div[#class='GJBYOXIDIN zoomable highlight' and #id='description']/div[#class='gwt-HTML' and #id='description']//span[#data-highlighted='true']"
You can get element by text
driver.findElement(By.xpath("//span[contains(text(), 'Willkommen')]"));
Or find div with id and based on that, find span element. There are 2 options to do that:
driver.findElement(By.xpath("//div[#id='description']//span"));
OR
WebElement descriptionDiv = driver.findElement(By.id("description"));
descriptionDiv.findElement(By.tagName("span"));
OR
driver.findElement(By.cssSelector("#description span"));
Your XPath looks fine, my guess is that it's a timing issue and you need a brief wait. It could also be that the page was in a certain state when you captured the HTML and it's not always in that state when you reach the page.
There are other locators that should work here.
XPath
//span[contains(., 'Willkommen')]
CSS selectors (These may or may not work based on your current XPath results)
span[data-highlighted='true']
#description span[data-highlighted='true']
For your function, I would suggest a change. Replace the String parameter with a By for more flexibility. You can then locate an element using any method and not be restricted to just XPath.
public Boolean webElementIsPresent(By locator)
{
return driver.findElements(locator).size() > 0;
}
or if you want to add a wait,
public Boolean webElementIsPresent(By locator)
{
try
{
new WebDriverWait(driver, 5).until(ExpectedConditions.presenceOfElementLocated(locator));
return true;
}
catch (TimeoutException e)
{
return false;
}
}
OS: Windows 10
Selenium Version: 3.4
#FINDALL annotation is supposed to match at least one of the given criteria.
Here is the OR :
URL for WebPage : http://store.demoqa.com/
WebElement : -
#FINDALL ({
#findby(xpath = "//input[#name='s']"),
#findby(xpath = "//a[contains(.,'Magic Mouse')]")
})
public WebElement Header__txtSearch;
I am trying to verify element on page with multiple locators.
When I give 2 correct values of XPath, then the driver identifies it quickly on the webpage and returns normally. But when I give the first one as Correct and second one as Incorrect , then it still returns true that element is found but it waits for the object timeout that was provided while initializing the driver(implicit wait).
Isn't there a way where if it finds the first element then it immediately returns us as true instead of going to match the next locator, So that no more time is taken for the test execution to move forward.
How can it be stopped after finding the correct locater info ??
Or is there a workaround for this in which I can use multiple locators for one element so that driver return true as soon as it matches the one locator correctly?
did you try to combine selectors into one by "|"? like:
#findby(xpath = "//input[#name='s']|//a[contains(.,'Magic Mouse')]")
public WebElement Header__txtSearch;
You can use or in the to get the first matching locator.
#findby(xpath = "//input[#name='s'] or //a[contains(.,'Magic Mouse')]")
public WebElement Header__txtSearch;
I'm wondering if it's possible to pass locator as parameter in data driven test? For example:
//this is non-parameterized object RADIO_BUTTON locator
WebElement radiobElm = driver.findElement(RADIO_BUTTON);
radiobElm.click();
vs.
//I'd like to pass locator "RADIO_BUTTON" as string (strRadioButton) from Excel sheet, so for each test iteration my script will click on different radio-buttons. Is it possible?
WebElement radiobElm = driver.findElement(strRadioButton);
radioElm.click();
One of the many ways to accomplish this would be to use same method to find elements and read the locator from excel file.
WebElement radiobElm = driver.findElement(By.xpath("Your xpath string from exel"));
Of course you have to do all of other works to read the correct cell from excel.
Yes you can. You just have to get the data from the excel (using jexcelapi's getContents() method, for instance). Then, you can manipulate them accordingly as they come.
1- If it's an xpath, use this:
WebElement radiobElm = driver.findElement(By.xpath("Cell contents containing xpath of the webelement"));
radioElm.click();
2- If it's an id, use this:
WebElement radiobElm = driver.findElement(By.id("Cell contents containing id of the webelement"));
radioElm.click();
3- If it's an cssSelector, use this:
WebElement radiobElm = driver.findElement(By.cssSelector("Cell contents containing cssSelector of the webelement"));
radioElm.click();
Similar thing, can be applied for "className, name, linkText, partialLinkText, and tagName" also.