How can I select checkboxes using the Selenium Java WebDriver? - selenium

How can I check the checkboxes using an id or XPath expression? Is there a method similar to select by visibletext for a dropdown?
Going through the examples given for all other related questions, I could not find a proper solution that works in a concise way that by few line or method I can check a chekbox or radio button.
A sample HTML section is below:
<tbody>
<tr>
<td>
<span class="120927">
<input id="ctl00_CM_ctl01_chkOptions_0" type="checkbox" name="ctl00$CM$ctl01$chkOptions$0"/>
<label for="ctl00_CM_ctl01_chkOptions_0">housingmoves</label>
</span>
</td>
</tr>
<tr>
<td>
<span class="120928">
<input id="ctl00_CM_ctl01_chkOptions_1" type="checkbox" name="ctl00$CM$ctl01$chkOptions$1"/>
<label for="ctl00_CM_ctl01_chkOptions_1">Seaside & Country Homes</label>
</span>
</td>
</tr>
</tbody>

Selecting a checkbox is similar to clicking a button.
driver.findElement(By.id("idOfTheElement")).click();
will do.
However, you can also see whether the checkbox is already checked. The following snippet checks whether the checkbox is selected or not. If it is not selected, then it selects.
if ( !driver.findElement(By.id("idOfTheElement")).isSelected() )
{
driver.findElement(By.id("idOfTheElement")).click();
}

It appears that the Internet Explorer driver does not interact with everything in the same way the other drivers do and checkboxes is one of those cases.
The trick with checkboxes is to send the Space key instead of using a click (only needed on Internet Explorer), like so in C#:
if (driver.Capabilities.BrowserName.Equals(“internet explorer"))
driver.findElement(By.id("idOfTheElement").SendKeys(Keys.Space);
else
driver.findElement(By.id("idOfTheElement").Click();

If you want to click on all checkboxes at once, a method like this will do:
private void ClickAllCheckboxes()
{
foreach (IWebElement e in driver.FindElements(By.xpath("//input[#type='checkbox']")))
{
if(!e.Selected)
e.Click();
}
}

Solution for C#
try
{
IWebElement TargetElement = driver.FindElement(By.XPath(xPathVal));
if (!TargetElement.Selected)
{
TargetElement.SendKeys(Keys.Space);
}
}
catch (Exception e)
{
}

You can use the following code:
List<WebElement> checkbox = driver.findElements(By.name("vehicle"));
((WebElement) checkbox.get(0)).click();
My HTML code was as follows:
<.input type="checkbox" name="vehicle" value="Bike">I have a bike<br/>
<.input type="checkbox" name="vehicle" value="Car">I have a car<br/>

To get the checkbox for 'Seaside & Country Homes', use this XPath:
//label[text()='Seaside & Country Homes']/preceding-sibling::input[#type='checkbox']
To get the checkbox for 'housingmoves', use this XPath:
//label[text()='housingmoves']/preceding-sibling::input[#type='checkbox']
The principle here is to get the label with the text you want, then get the checkbox that is before the label, since that seems to be how your HTML is laid out.
To get all checkboxes, you would start a little higher up and then work down, so that is to say get the table, and then get any checkbox within a span:
//table/descendant::span/input[#type='checkbox']

I found that sometimes JavaScript doesn't allow me to click the checkbox because was working with the element by onchange event.
And that sentence helps me to allow the problem:
driver.findElement(By.xpath(".//*[#id='theID']")).sendKeys(Keys.SPACE);

This should help -
IWebElement elementToClick = driver.findElement(By.xpath(""//input[contains(#id, 'lstCategory_0')]"));
elementToClick.Click();
You can also pass an id.
If you want something like visible text you can "find element" by name if they have names.

The below code will first get all the checkboxes present on the page, and then deselect all the checked boxes.
List<WebElement> allCheckbox = driver.findElements(By
.xpath("//input[#type='checkbox']"));
for (WebElement ele : allCheckbox) {
if (ele.isSelected()) {
ele.click();
}
}

A solution using WebDriver and C# is below. The key idea is to get the ID of the checkbox from the labels' 'for' attribute, and use that to identify the checkbox.
The code will also set the checkbox state only if it needs to be changed.
public void SetCheckboxStatus(string value, bool toCheck)
{
// Get the label containing the checkbox state
IWebElement labelElement = this.Driver.FindElement(By.XPath(string.Format("//label[.='{0}']",value)));
string checkboxId = labelElement.GetAttribute("for");
IWebElement checkbox = this.Driver.FindElement(By.Id(checkboxId));
if (toCheck != checkbox.Selected)
{
checkbox.Click();
}
}

Maybe a good starting point:
isChecked = driver.findElement((By.id("idOftheElement"))).getAttribute("name");
if(!isChecked.contains("chkOptions$1"))
{
driver.FindElement(By.Id("idOfTheElement")).Click();
}

Running this approach will in fact toggle the checkbox; .isSelected() in Java/Selenium 2 apparently always returns false (at least with the Java, Selenium, and Firefox versions I tested it with).
The selection of the proper checkbox isn't where the problem lies -- rather, it is in distinguishing correctly the initial state to needlessly avoid reclicking an already-checked box.

To select a checkbox, use the "WebElement" class.
To operate on a drop-down list, use the "Select" class.

Step 1:
The object locator supposed to be used here is XPath. So derive the XPath for those two checkboxes.
String housingmoves="//label[contains(text(),'housingmoves')]/preceding-sibling::input";
String season_country_homes="//label[contains(text(),'Seaside & Country Homes')]/preceding-sibling::input";
Step 2:
Perform a click on the checkboxes
driver.findElement(By.xpath(housingmoves)).click();
driver.findElement(By.xpath(season_country_homes)).click();

For a partial match, do the following:
getDriver().findElement(By.cssSelector("<tag name>[id*='id pattern to look for']")).click();

Here is the C# version of Scott Crowe's answer. I found that both IEDriver and ChromeDriver responded to sending a Key.Space instead of clicking on the checkbox.
if (((RemoteWebDriver)driver).Capabilities.BrowserName == "firefox")
{
// Firefox
driver.FindElement(By.Id("idOfTheElement")).Click();
}
else
{
// Chrome and Internet Explorer
driver.FindElement(By.Id("idOfTheElement")).SendKeys(Keys.Space);
}

I tried with various approaches, but nothing worked. I kept getting "Cannot click element" or ElementNotVisibleException.
I was able to find the input, but I couldn't check it. Now, I'm clicking on the div that contains the checkbox and it works with following HTML (CSS based on Bootstrap).
#foreach (var item in Model)
{
<tr>
<td>
<div id="#item.Id" class="checkbox">
<label><input type="checkbox" class="selectone" value="#item.Id"></label>
</div>
</td>
<td val="#item.Id">
#item.Detail
</td>
<td>
<div>#item.Desc
</div>
</td>
<td>
#Html.ActionLink("Edit", "Create", new { EditId = item.Id })
</td>
</tr>
}
This is the code for WebDriver:
var table = driver.FindElement(By.TagName("table"));
var tds = table.FindElements(By.TagName("td"));
var itemTds = tds.Where(t => t.Text == itemtocheck);
foreach (var td in itemTds)
{
var CheckBoxTd = tds[tds.IndexOf(td) - 1];
var val = td.GetAttribute("val");
CheckBoxTd.FindElement(By.Id(val)).Click();
}
In this approach, I give the item id as id for the div and also add an attribute for td with that id. Once I find the td of the item that needs to be checked, I can find the div before that td and click it. We can also use the XPath query that supports before (here is the example http://learn-automation.com/how-to-write-dynamic-xpath-in-selenium/).

Related

Improvement With Xpath Search?

I am a student learning selenium and trying to set a checkbox(by placing a tick) that resides on the same row as a target document. Here is how the row looks:
<span><input>Checkbox</input></span> - <span>_lblDocumentCategoryDescription</span> - <span>_lblDocumentdescription</span>
Each row consists of a checkbox for that row, a category and a description. I am provided the description and need to set the corresponding checkbox at the beginning of the row.
Although I have a solution that works I am looking for a better method as my method is very slow and I can call it multiple times, compounding the slowness. The page in question has 315 fixed different documents that might possibly be added (to a merge and print feature). I usually add at least 3 rows so need to run the search
I am currently using xpath to search since my knowledge of CSS is limited and it seems like traversing up the DOM (no :parent?) is not easy unless using some javascript, which I am trying to avoid. I have read that executing JS doesn't emulate the user correctly so I guess xpath is the solution?
As I know there must be a quicker/better/more efficient solution I am hoping others might have found better?
Here is what I am currently using:
Method Call
CPTools,setStupidCheckbox("Sublease Addendum", true);
Method:
public CPTools setStupidCheckbox(String documentToPrint, Boolean onIfTrue) {
this.log.trace("Starting: setStupidCheckbox; parameter: documentToPrint " + documentToPrint);
String xpathForCheckboxes = "/ancestor::tr//input";
try {
String xpathForDocumentDescriptions = String.format("//span[contains(text(), '%s')]", documentToPrint);
tools.waitForElement(By.xpath(xpathForDocumentDescriptions), 2);
if (driver.findElement(By.xpath(xpathForDocumentDescriptions)).isDisplayed()) {
driver.findElementByXPath(xpathForDocumentDescriptions + xpathForCheckboxes).click();
}
} catch (org.openqa.selenium.NoSuchElementException | ElementNotVisibleException e) {
}
this.log.trace("Ending: setStupidCheckbox");
return this;
}
Here is the full xpath for a table row (the dynamic part of the id is the _ctl316):
<tr class="DataGridCellData">
<td class="DataGridCellDataCenterAligned">
<span class="DataLabel"><input id="ctl01_PageBody_grdDocument_ctl316_chkSelect" name="ctl01$PageBody$grdDocument$ctl316$chkSelect" onclick="javascript:uiHelper.GridCellCheck(this, 'chkAllSelect');" type="checkbox"></span>
</td><td>
<span id="ctl01_PageBody_grdDocument_ctl316_lblDocumentCategoryDescription">Approval Form</span>
</td><td align="left">
<span id="ctl01_PageBody_grdDocument_ctl316_lblDocumentdescription">Sublease Addendum</span>
</td><td align="center">
</td>
</tr>
Thanks in advance for any possible help.
Try below XPath if span text (Sublease Addendum) is unique:
//td[.= 'Sublease Addendum']

selenium webdriver validate if checkbox is checked

I need to perform validation against the table that is being displayed like this.
code sample how I'm trying to find the checkbox Element
//navigate t the second tr where the input and img tags are stored
List<WebElement> daysCheckBox = this.driver.findElements(By.xpath(".//*[#id='RULE_KEY']/div/div/div/div/div/center[1]/table[2]/tbody/tr[2]/td"));
System.out.println("Test checkbox");
for(WebElement td : daysCheckBox){
System.out.println(td.getTagName());
}
The problems I have is that this table come with 2 tags first row represents the days and the second "checkboxes" as you can see they line up with days, however checkbox have no link to each day. I have tried to solve this with reverse logic to try to identify the input tag if it is disabled. But when the box is selected it turns from input tag into img tag, also when I identify input tags I cannot pinpoint what day deselected box it corresponds to.
Does anyone have any advice or suggestion how to approach this type of validation?
Thank you.
I have put the source to make it clearer how the picture above is presented.
<tbody>
<tr bgcolor="whitesmoke">
<td><b>Sun</b></td>
<td><b>Mon</b></td>
<td><b>Tues</b></td>
<td><b>Wed</b></td>
<td><b>Thurs</b></td>
<td><b>Fri</b></td>
<td><b>Sat</b></td>
</tr>
<tr>
<td><img src="webwb/dhtmlx_iconcheckall.gif" /></td>
<td><input disabled="disabled" type="checkbox" /></td>
<td><input disabled="disabled" type="checkbox" /></td>
<td><input disabled="disabled" type="checkbox" /></td>
<td><img src="webwb/dhtmlx_iconcheckall.gif" /></td>
<td><img src="webwb/dhtmlx_iconcheckall.gif" /></td>
<td><input disabled="disabled" type="checkbox" /></td>
</tr>
</tbody>
You can create method which will convert Your table to Java Map for example:
public static Map<String,String> getTableAsMap(WebDriver driver)
{
Map<String,String> checkboxMap = new TreeMap<>();
List<WebElement> header = driver.findElements(By.xpath("((//tbody/tr)[1])/td/*"));
List<WebElement> checkboxes = driver.findElements(By.xpath("((//tbody/tr)[2])/td/*"));
for(int i = 0;i<header.size();i++){
//Only for testing purpose
System.out.printf("KEY: %s, VALUE: %s\n",header.get(i).getText(),checkboxes.get(i).getAttribute("disabled"));
checkboxMap.put(
header.get(i).getText(),
checkboxes.get(i).getAttribute("disabled")
);
}
return checkboxMap;
}
Then In your main class with driver use:
Webdriver driver = new FirefoxDriver();
Map<String,String> map = getTableAsMap(driver);
System.out.println(map.get("Fri"));
System.out.println(map.get("Sat"));
For disabled (non selected) checkbox You will receive true for selected there will be null. Both as String.
as you haven't posted the code, my answer also doesn't have a code :)
Create the WebElement for second row, i.e. xpath: //tbody/tr[2]
Now traverse all the tds inside this row and check their child element.
If the child element is input you know that checkbox is not selected else it is.
About for which day, you know the first is Sunday and Second is Monday and so on..
The Page Object Model approach may be effective to deal with this scenario. So, you can refresh your page object after some action/set of actions.
Since you mentioned that once a checkbox is checked the tag gets changed for the element, so I assume this can happen multiple times in the page based on user activity.
I can suggest that you implement a callback that reloads the and set the page objects on user action say click. With the page objects, you always have track of all the WebElements, accessibility and any change of state.

Clicking all elements with matching class

I'm new to Selinium. There is a table (inside another table) that I want to click each <td>click here</td> with a matching class value (note the text between opening and closing td will change but is irrelevant for matching purposes). The class value I'm trying to match is open. From here I learn the right way is with //*[contains(concat(" ", normalize-space(#class), " "), " open ")]
This seems to work but just for one random cell. How do I make it click all? I was planning on accomplishing this first and repeating the step, but it may be worth noting that the script should also do the same for class value available and not just open Is there away to do logical or?
TL;DR I want to click everything with <td class="open">...</td>
and
<td class="available">...</td> where ... is example text that will vary but should be ignored.
Get all elements and store them in a List, then iterate over them and click the buttons in sequence.
List<WebElement> list = driver.findElements(By.xpath("//*[contains(concat(" ", normalize-space(#class), " "), " open ")]"));
for(WebElement webelement : list) {
// webelement Click the button here
}
To get all elements, you should use driver.FindElements. Make sure it's what you used, not driver.FindElement?
Use following approach may help you -
List<WebElement> allElements = driver.findElements(By.tagName("td"));
for(WebElement element:allElements)
{
if(element.getAttribute("class").contains("open"))
{
// manipulate with <td> tag data
}
}
Please use following XPath:
//td[normalize-space(#class)="open" or normalize-space(#class)="available"]
This should match both <td class=" open ">...</td> and
<td class=" available ">...</td>

Selenium webdriver-java: how to get javascript tooltip

I want to get tooltip information enabling on JavaScript. I have tried with below code but its shown null every time.
Java Code:
Actions action = new Actions(driver);
WebElement element = driver.findElement(By.xpath("//*[#id='content']/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div[1]/table/tbody/tr[1]/td[2]/span/div/a"));
action.moveToElement(element).build().perform();
System.out.println(driver.findElement(By.xpath("//*[#id='content']/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div[1]/table/tbody/tr[1]/td[2]/span/div/a")).getAttribute("data-original-title"));
HTML Code is:
<tr class="single" name="Tasks_59c777d9-8d16-694a-7307-52caad36d751">
<td>
</td>
<td data-type="custom_task_name">
<span class="list" sfuuid="3840" data-original-title="">
<div class="ellipsis_inline" data-original-title="">
Task Testing
<br/>
Toney Harber
</div>
</span>
</td>
I have tried with span tag but this also shows null.
I am providing you 2 options try both.
Option 1
Please try below. It will return you a list. Loop through it. If there is only one span then you can get the element and then get the attribute value.
driver.findElements(By.xpath("//span[#data-original-title]"))
Option 2
Instead of
driver.findElement(By.xpath("//*[#id='content']/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div[1]/table/tbody/tr[1]/td[2]/span/div/a"))
use findElements
driver.findElements(By.xpath("//*[#id='content']/div/div/div[1]/div/div[2]/div[2]/div/div[3]/div[1]/table/tbody/tr[1]/td[2]/span/div/a"))
It will return a list of web elements. Loop thorough it you might get more than one element.

Issue selecting Radio button in Selenium Webdriver

<table id="Content_Content_Content_ctlCaseInfo_rdochldplcm" class="fltLeft">
<tr>
<td><input type="radio" id="Content_Content_Content_ctlCaseInfo_rdochldplcm_0" name="ctl00$ctl00$ctl00$Content$Content$Content$ctlCaseInfo$rdochldplcm" value="0" /><label for="Content_Content_Content_ctlCaseInfo_rdochldplcm_0">No</label></td><td><input type="radio" id="Content_Content_Content_ctlCaseInfo_rdochldplcm_1" name="ctl00$ctl00$ctl00$Content$Content$Content$ctlCaseInfo$rdochldplcm" value="1" /><label for="Content_Content_Content_ctlCaseInfo_rdochldplcm_1">Yes</label></td>
</tr>
</table>
When I try
driver.FindElement(By.Id("Content_Content_Content_ctlCaseInfo_rdochldplcm")).Click();
it clicks to "Yes"
When I try driver.FindElement(By.Id("Content_Content_Content_ctlCaseInfo_rdochldplcm_0")).Click();
OR
driver.FindElement(By.Id("Content_Content_Content_ctlCaseInfo_rdochldplcm_1")).Click();
Nothing happens and no radio button gets selected.
Please suggest ways to handle this situation ..thanks a lot!!
It would probably be better to click the Radio buttons through XPath.
In your specific case, the XPath for:
Yes - Radio Button:
"//input[contains(#id, 'rdochldplcm') and contains(#value, 1)]"
No - Radio Button:
"//input[contains(#id, 'rdochldplcm') and contains(#value, 0)]"
In this instance, if you wanted to click the 'Yes' Radio button, you can do this:
string yesRadioButtonXPath = "//input[contains(#id, 'rdochldplcm') and contains(#value, 1)]"
IWebElement yesRadioButton = driver.FindElement(By.XPath(yesRadioButtonXPath));
yesRadioButton.Click();
For the 'No' Radio button, you would use this:
string noRadioButtonXPath = "//input[contains(#id, 'rdochldplcm') and contains(#value, 0)]"
IWebElement noRadioButton = driver.FindElement(By.XPath(noRadioButtonXPath));
yesRadioButton.Click();
Since you're using a table, there may be a chance that the XPath may return more than one element. You'd need to use a different method to sort out the elements in that case, but for what you're looking for, this method should work.
this solved my problem perfeclty
I have a page with 18 radio buttons in 6 groups which represented "Yes" "No" and "No Answer"
I was trying to get them by ID but it was randomized by the app
But using a name and value tags made it work.
radios were defined basically like this:
input value="2" class=" x-form-radio x-form-field" autocomplete="off" id="randID_13578" name="emailNotifiyOptionAllow" type="radio">
and every time i opened this page id was different so using
"//input[contains(#name, 'emailNotifyOptionAllow') and contains(#value, 1)]"
solved it.
Thanx
Use this :
//First get the list of values from the radio button
List < WebElement > elements = driver.findElements(By.cssSelector("table[id='Content_Content_Content_ctlCaseInfo_rdochldplcm'] > td"));
WebElement value;
//use loop for searching the particular element
for(WebElement element : elements){
//Getting the value of the element
value = element.findElement(By.cssSelector("label")).getText();
//condition to click on the element
if(value.trim().equals("No")){ //Here value is hard coded. You can take from excel sheet also
// If condition satisfies, it will click on the element
element.findElement(By.cssSelector("input").click();
}
}
This can be used as a common function also.
try [0] and [1] instead of the underscore.
Try your code with the given below CSS :
Step 1:
By Provided HTML Piece we can derive the CSS of the Radio Button
css=#Content_Content_Content_ctlCaseInfo_rdochldplcm input
Step 2:
Click on the radio button using Web Driver Code
driver.findElement
(By.cssSelector("#Content_Content_Content_ctlCaseInfo_rdochldplcm input"))
.click();