Reputation: 1071
I'm writing some Selenium tests in Java and will later need to find elements by DOM attributes that are not visible in the html. The code below attempts to find the search bar in google using the "class" attribute and then the DOM attribute "checked". Only the first of these works for me, the 2nd one fails with "Unable to locate element".
I assume that I'm either doing something wrong with the xpath or that I'm not understanding the DOM attributes correctly. I tried with several other attributes in the DOM but always get the same result. I also tried using cssSeletor instead of xpath, but again with the same results.
As indicated in the code I use Chrome (with Windows 7).
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
public class SeleniumTest {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "D:\\Selenium\\Drivers\\chromedriver.exe");
DesiredCapabilities caps = DesiredCapabilities.chrome();
WebDriver driver = new ChromeDriver(caps);
driver.manage().window().maximize();
driver.get("http://www.google.com");
WebElement elementByClass = driver.findElement(By.xpath("//input[@class='gsfi']"));
WebElement elementByDOM = driver.findElement(By.xpath("//input[@checked='false']"));
}
}
Edit: If I inspect the google searchbar with F12 dev tool I find the html:
<input spellcheck="false" dir="ltr" style="border: medium none; padding: 0px; margin: 0px; height: auto; width: 100%; background: transparent url("data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D") repeat scroll 0% 0%; position: absolute; z-index: 6; left: 0px; outline: medium none;" aria-autocomplete="both" role="combobox" aria-haspopup="false" class="gsfi" id="lst-ib" maxlength="2048" name="q" autocomplete="off" title="Søk" value="" aria-label="Søk" type="text">
If I inspect the DOM proprties of this element I can see the attribute "checked"=true
. See image:
Upvotes: 2
Views: 6984
Reputation: 63
Hi After some research and initial struggle with selenium I have learnt that you can execute javascript using Selenium JavaScriptExecutor class to access any of the DOM properties of a web control. So I have designed a generic function which can search for any web control on the page provided you input the unique DOM properties of that control which you are searching on the browser. As this function is traversing through the DOM hierarchy it can actually work across multiple browsers. Have a look
`
/// <summary>
/// Fetch the object reference of any control on the screen
/// Please Note : Make sure you pass unique objPropNames,objPropValues of the control,
/// if not then the first matched control is returned
/// </summary>
/// <param name="driver"></param>
/// <param name="objPropNames"></param>
/// <param name="objPropValues"></param>
/// <param name="elementTagName"></param>
/// <returns></returns>
public static IWebElement GetWebObject(IWebDriver driver,string[] objPropNames, string[] objPropValues, string elementTagName)
{
IWebElement webObj = null;
//string elementPropVlu;
//string propName, propVlu;
try
{
IList<IWebElement> lstElement = driver.FindElements(By.TagName(elementTagName));
foreach (var item in lstElement)
{
//reset the flag to true for every iteration
bool objectFound = true;
for (int i = 0; i < objPropNames.Length; i++)
{
ObjPropName = objPropNames[i];
ObjPropVlu = objPropValues[i];
//get the value of the attribute
//elementPropVlu = item.GetAttribute(ObjPropName.ToString());
var elementPropVlu = (Object)null;
try
{
elementPropVlu = ((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0]." + ObjPropName + "; ", item);
}
catch (InvalidOperationException ex)
{
}
if (elementPropVlu != null)
{
if (elementPropVlu.ToString().ToLower().Trim() != ObjPropVlu.ToString().ToLower().Trim())
{
objectFound = false;
break;
}
}
}
//if all the prop values of that object are satisfied then the match is found which
//means the element we are searching for is found
if (objectFound)
{
webObj = item;
break;
}
}
}
catch (NoSuchElementException e)
{
//throw;
//log the exception
}
return webObj;
}`
Usage :
GetWebObject(DriverContext.Driver, new string[] { "checked", "className" }, new string[] { "false", "gsfi" }, "INPUT")
Upvotes: 0
Reputation: 151401
There are a couple problems with your approach.
The XPath expression you use //input[@checked='false']
will match only input
elements that have the attribute checked
explicitly set to "false"
. It will not take into accounts those input
elements where checked
is not set an therefore has the default value of false
.
What you need to check if you want to know whether an input
is currently checked is its checked
property not the attribute. The attribute only serves to give an initial value to the property. After that, manipulating the input
won't change the attribute (unless you actually write code to do it). What will change are the properties of the input
. Your XPath checks attributes, and XPath cannot be used to select by properties.
There is a pseudo-class selector you can use for this: :checked
.
driver.findElement(By.css("input:checked"));
You can use input:not(:checked)
to find the unchecked ones.
Upvotes: 2