Selenium can't find element by id and xpath - java

I read already all the other questions about this topic, there are a lot. I tried some but I do not find error in the code.
I tried adding a timer too to wait for the page to load.
Below the html code and the java:
HTML:
<form id="myform" method="get" action="">
<input type="hidden" name="something1" id="something1.1" />
<input type="hidden" name="something2" value="" />
<table>
<tr>
<td><label>Name: </label></td>
<td><select name="name">
<option selected="selected" value="1000">FirstNameOnly</option>
</select></td>
</tr>
<tr>
<td><label>Direction: </label></td>
<td><select name="Direction">
<option selected="selected" value="">Choose One</option>
<option value="UP">UP</option>
</select></td>
</tr>
<tr>
<td colspan="2"><label>Time: </label></td>
</tr>
<tr>
<td><label>From: </label></td>
<td><input type="text" value="" name="from" id="id6"/>
</tr>
<tr>
<td><label>To: </label></td>
<td><input type="text" value="" name="to" id="id7"/>
</tr>
<tr>
<td><label>File type: </label></td>
<td><span id="id8">
<input name="fileType" type="radio" checked="checked" value="0" id="id8-0"/><label for="id8-0">Excel</label>
<input name="fileType" type="radio" value="1" id="id8-1"/><label for="id8-1">CSV</label>
</span></td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" name="p::submit" id="id9" value="Preview">
<input type="submit" name="download" id="ida" value="Download">
</td>
</tr>
</table>
</form>
JAVA:
public void HeadlessChromeStartDownload(){
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
ChromeOptions options = new ChromeOptions();
if (ValidateOS.isWindows()){
options.setBinary("C:\\Users\\Juri\\AppData\\Local\\Google\\Chrome SxS\\Application\\chrome.exe");
System.out.println("Windows system");
} else if (ValidateOS.isUnix()){
options.setBinary("/path/to/chrome/not/yet/added");
}
options.addArguments("--headless --disable-gpu");
ChromeDriver driver = new ChromeDriver(options);
driver.get("http://localhost/that-test-page.html");
//WebElement timer = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.id("id8-1")));
WebElement select1 = driver.findElementByName("FirstNameOnly");
Select field1 = new Select(select1);
field1.selectByIndex(1);
WebElement select2 = driver.findElementByName("Direction");
Select field2 = new Select(select2);
field2.selectByIndex(1);
driver.findElementByName("from").sendKeys("21/06/2017");
driver.findElementByName("to").sendKeys("22/06/2017");
/*File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(scrFile, new File("C:\\screen1.jpg"));
System.out.println("Screen saved");
} catch (IOException e) { System.out.println("Screen NOT saved"); }
*/
//driver.findElement(By.id("id8-1")).click();
driver.findElement(By.xpath("//form[1]/input[6]")).click();
//driver.findElementById("ida").click();
driver.quit();
}
It really does not matter if I use:
driver.findElement(By.id("id8-1")).click();
or
driver.findElementById("id8-1").click();
or
driver.findElement(By.xpath("//form[1]/input[6]")).click();
I can't get Selenium to click on that radio button.
And the same goes for the rest of the code, in fact I used findElementByName which obviously is not the best choice.
Thanks to anyone who knows what is wrong with this code!! (: (:
UPDATE1:
So, I can not explain what happened yesterday. The website I am trying to test was using id8-1 for that radio button. Today it is id3-1, and both the solution with: driver.findElement(By.cssSelector("input[value='1']")).click(); or mine: driver.findElement(By.id("id3-1")).click(); worked.
I'm astonished. It was clearly 8 yesterday.
Still, I do not know if using the cssSelector solution is the best, because I want to work with the IDs.
I upvoted all the answers because all are useful but I wish to use IDs so I'm using my code.. In case of updates by your side I will choose it the one (: (:
Thanks to all!!!

When driving IE with Selenium, I encountered a problem where driver.find_element_by_id("elem_id") can't find it but running javascript document.getElementById("elem_id") in IE's developer console can. In my case, I was extracting a value. So I worked it around by doing driver.execute_script('return document.getElementById("elem_id").outerText')

Try with the following:
driver.findElement(By.xpath("//input[#name='fileType' AND #id='id8-1']")).click();

Does selenium throws an error? When trying to click an element that no longer existis into DOM, you will see an error like 'Element is no longer attached
to the DOM'.
Better than to using wait, is to write a method that verifies if the element is available. Try the following one:
private void waitUntilElementExistsAndIsVisible(final By by) {
new FluentWait<WebDriver>(driver).withTimeout(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.pollingEvery(DEFAULT_SLEEP_TIME_IN_SECONDS, TimeUnit.SECONDS).ignoring(NoSuchElementException.class)
.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wd) {
return wd.findElement(by).isDisplayed();
}
});
}
Use it before executing some action with an element:
waitUntilElementExistsAndIsVisible(By.id("id8-1"));
driver.findElement(By.id("id8-1")).click();
Another workaround is to use the Action methods. Try to move the mouse to the enclosing tag (<span id="id8">), and then, click the desired element:
Actions builder = new Actions(driver);
builder.moveToElement(driver.findElement(By.id("id8"))).perform();
waitUntilElementExistsAndIsVisible(By.id("id8-1"));
driver.findElement(By.id("id8-1")).click();

You can achieve this without using xpath also
driver.findElement(By.cssSelector("input[value='1 0r 0']")).click();
You can select either 0 or 1 which you want to select

Related

I am populating my dropdown from DB but after selecting I am getting null value in my method present in my java code when submit button is clicked

I am populating my dropdown from DB but after selecting I am getting null value in my method present in my java code when submit button is clicked.
Though, if I am hard coding values in my dropdown, whole functionality is working perfectly. Please, tell me what I am doing wrong?
Java Code for passing List value obtained from DB which I am passing to my JSP:
EventService eventService = new EventServiceImpl();
List<Event> theEvents = eventService.showEventListMethod();
// add the event list to the model
theModel.addAttribute("event", theEvents);
return "eventPostponeCancelCompletePage";
My JSP form where I am selecting value from dropdown:
<form action = "eventCancelCompleteMethod" modelAttribute="event" method = "post">
<table id="table" align="center">
<tr>
<td width="50%">Event Name: </td>
<td width="50%">
<select name="eventName">
<c:forEach var="tempEvent" items="${event}">
<option value="tempEvent.eventName">${tempEvent.eventName}</option>
</c:forEach>
</select>
<!-- <select name="eventName">
<option value="Birthday Party for May">Birthday party for May</option>
</select> -->
</td>
</tr>
<tr>
<td align="center" width="34%" >
<!-- <input type = "submit" value = "Postpone"/> -->
<input class="btn btn-default custom" type = "button" value = "Postpone Event" onclick="openPage('showPostponeEventPage')"/>
</td>
<td align="center" width="33%">
<input class="btn btn-default custom" type = "submit" value = "Cancel/Complete Event"/>
</td>
</tr>
</table>
</form>
Java method which will be called once submit button is clicked:
#PostMapping("/eventCancelCompleteMethod")
public String eventCancelCompleteMethod(#ModelAttribute("event") Event theEvent)
{
EventService eventService = new EventServiceImpl();
System.out.println("Event Name: "+theEvent.eventName);
//theEvent.setEventName("New testing event July");
theEvent.setEventState("inactive");
System.out.println("New Event Data: "+theEvent);
System.out.println("Successfully Cancelled/Completed the event");
String action = eventService.eventCancelCompleteMethod(theEvent.eventName, theEvent.eventState);
System.out.println("Action: " + action);
if(action.equalsIgnoreCase("success"))
{
System.out.println("Successfully added contributor data!!");
return "redirect:/showEventPostponeCancelComplete";
}
else
{
System.out.println("Failed to add!!");
return "redirect:/showEventPostponeCancelComplete";
}
}
I think you should use form:select as below:
<form:select path="BEAN.YourBeanAttrName" style='width: 110px;' id="">
<form:options items="${FORM.actionList}" itemValue="key" itemLabel="value"/>
</form:select>

identifying button element on a webpage selenium

I am trying to locate a pesky button on my webpage. most of the other elements I can locate but this one is giving me a headache.
The html is:
<table class="d_FG" role="presentation">
<tbody>
<tr>
<tr id="z_t">
<td class="fct_w" colspan="2">
<div>
<input name="newAttachments_fsid" value="0" type="hidden">
<table id="z_u" class="dcs" role="presentation">
<tbody>
<tr style="border: none;">
<td colspan="3" style="padding-right:0">
<a id="z_v" class="vui-button d2l-button d2l_1_192_930" role="button" tabindex="0" aria-disabled="false">Add a File</a>
<a id="z_w" class="vui-button d2l-button d2l_1_193_372" role="button" tabindex="0" aria-disabled="false">Record Audio</a>
</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
I am trying to locate the element:
<a id="z_v" class="vui-button d2l-button d2l_1_192_930" role="button" tabindex="0" aria-disabled="false">Add a File</a>
I have tried various methods such as:
public void add_attachment(){
driver.switchTo().defaultContent();
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
driver.findElement(By.id("z_v"))).click();
}
But just cant manage it. Always get the message it is not visible or another element would be clicked.
I tried using a javascript that scrolls down to the element but that didn't work. Any ideas to help me with would be greatly appreciated
Can you try some other workarounds like using Actions or javascriptExecutor as below,
WebElement btn = driver.findElement(By.id("z_v")));
Actions action = new Actions(driver);
action.click(btn).build.perform();
or
JavascriptExecutor js = (JavascriptExecutor)driver;
Js.executeScript("arguments[0].click()",btn);

#FindBy annotation for radio buttons

I have to select one of the several values of type radio button using #FindBy.
Here is my html code that I need to automate.
I tried giving #FindBy(how=How.CSS,using= "[type='radio']" and value)
But I have to pass in the value dynamically. ie. Chose BlueSkies or Pangea airlines.What is the best way to write it.Will #FindBy return a list of WebElements and can I work on it like that. Please help.
<input type="radio" name="outFlight" value="Blue Skies Airlines$361$271$7:10"/>
</td>
<td class="data_left" align="LEFT" bgcolor="CCCCCC">
<font size="-1" face="ARIAL">
<b>Blue Skies Airlines 361</b>
</font>
</td>
<td class="data_center_mono" align="CENTER" valign="TOP" bgcolor="CCCCCC">
<font size="-1" face="ARIAL">7:10</font>
<br/>
</td>
<td class="data_center" align="CENTER" bgcolor="CCCCCC" nowrap="">
<font size="-1" face="ARIAL">non-stop</font>
</td>
</tr>
<tr>
<td class="data_verb_xcols" valign="top" bgcolor="#FFFFFF" colspan="4">
</tr>
<tr>
<td class="frame_action_xrows" rowspan="2" align="CENTER" bgcolor="#FFCC00" valign="CENTER">
<input type="radio" name="outFlight" value="Pangea Airlines$362$274$9:17"/>
</td>
<td class="data_left" align="LEFT" bgcolor="CCCCCC">
<font size="-1" face="ARIAL">
<b>Pangaea Airlines 362</b>
</font>
</td>
The value in #FindBy can't be dynamic. You can split it to two
#FindBy(how = How.CSS, using = "[value*='Blue Skies Airlines']")
private WebElement blueSkyesRadioButton;
#FindBy(how = How.CSS, using = "[value*='Pangea Airlines']")
private WebElement pangeaAirlinesRadioButton;
Or to insert them both to list and work with indexes
#FindBy(how = How.CSS, using = "[type='radio']")
private List<WebElement> radioButtons;
#FindBy(how = How.CSS, using = "[type='radio']")
private List<WebElement> radioButtons;
Some more explanation supporting the solution give by #Guy, you can write an method to select radio dynamically. For an example
public void selectRadio(String airlineName){
for(WebElement radio : radioButtons){
if(radio.getAttribute("value").contains(airlineName)
radio.click();
}
}
You can use iterator if you wish. You just need to call this method by page object passing the airlineName as an argument.

how to pass checkbox value(checked/unchecked) to controller as href parameter in jsp

I am a beginner in jsp.I want to get data from database and show checked on a checkbox depending on db value i.e. 0 or 1.This is working for me.But I also want o that when I check or uncheck the checkbox it will reset value and pass it to controller as a href parameter.
here is my jsp:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page session="false" %>
<html>
<head>
<title>Investor Account</title>
</head>
<body>
<script type="text/JavaScript">
function updateCheck(){
if(document.getElementById('chk').checked){
document.getElementById('chk').value = 1;
location.href=""
alert(document.getElementById('chk').value);
}
else{
document.getElementById('chk').value = 0;
alert(document.getElementById('chk').value);
}
}
</script>
<div align="center">
<h1>Investor Account List</h1>
<table border="1">
<th>ID</th>
<th>Investor Code</th>
<th>Investor Name</th>
<th>SMS Subscriber</th>
<th>Action</th>
<c:forEach var="investorAcc" items="${listInvestorAcc}" varStatus="st">
<tr>
<td>${st.index + 1}</td>
<td>${investorAcc.investor_code}</td>
<td>${investorAcc.investor_name}</td>
<td> <input type="checkbox" id="chk" name="chkSms" value= <c:if test="${investorAcc.sms_sub==1}">1</c:if> onclick="updateCheck();"
<c:if test="${investorAcc.sms_sub==1}">checked="checked"</c:if>/>
<td>
1</c:if>"> Update
</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
To update checkbox value, the easiest way is to use form in loop. Try
<c:forEach var="investorAcc" items="${listInvestorAcc}" varStatus="st">
<form action="updateInvestorAcc">
<input type="hidden" name="id" value="${investorAcc.id}"/>
<tr>
<td>${st.index + 1}</td>
<td>${investorAcc.investor_code}</td>
<td>${investorAcc.investor_name}</td>
<td>
<c:choose>
<c:when test="${investorAcc.sms_sub==1}">
<input type="checkbox" id="chk" name="chkSms"
value="${investorAcc.sms_sub}" checked="checked"/>
</c:when>
<c:otherwise>
<input type="checkbox" id="chk" name="chkSms"
value="${investorAcc.sms_sub}"/>
</c:otherwise>
</c:choose><td> <!-- end of checkbox -->
<td><input type="submit" value="Update"></td>
</tr>
</form>
</c:forEach>
Edit:
You need a Servlet to get updated value
#WebServlet("/updateInvestorAcc")
public class UpdateInvestorAcc extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String idStr=request.getParameter("id");
int id= Integer.parseInt(idStr);// If you need to parse to int
String[] chkSms=request.getParameterValues("chkSms");
boolean isChkSms =false;
if(chkSms !=null && chkSms.length > 0){//If checkbox is checked than assign it with true or 1
isChkSms=true;
}
// Now update the DB with id and checkbox value.
}
you can simplify the middle bit in the other posters suggestion with a basic IF test. Because it's only going to be 1 or 0 (choose is overkill IMO). Technically because it's 1/0 you don't even need to ==1 comparitor, just reference it raw in the test="" block as test="${investorAcc.sms_sub}". The JSTL is smart enough to handle all angles (including NULL). 1=true, 0=false, NULL=false.
<c:forEach var="investorAcc" items="${listInvestorAcc}" varStatus="st">
<form action="updateInvestorAcc">
<input type="hidden" name="id" value="${investorAcc.id}"/>
<tr>
<td>${st.index + 1}</td>
<td>${investorAcc.investor_code}</td>
<td>${investorAcc.investor_name}</td>
<td>
<input type="checkbox" id="chk" name="chkSms"
value="${investorAcc.sms_sub}" <c:if test="${investorAcc.sms_sub==1}">checked="checked"</c:if>/>
<td> <!-- end of checkbox -->
<td><input type="submit" value="Update"></td>
</tr>
</form>
</c:forEach>
For your second bit about the 'unchecked' box passing invalid values. That's a super annoying thing with HTML. Unchecked boxes get 'dropped to null' when a form is submitted. A lot of people are supplementing with a 2nd hidden input to get this done without NULL errors (note, it MUST be second). Different "ID", but same "NAME" so the Servlet will see it and capture the 'unchecked' value from it instead of the NULLed original checkbox:
ex:
<td>
<input type="checkbox" id="chk" name="chkSms"
value="${investorAcc.sms_sub}" <c:if test="${investorAcc.sms_sub==1}">checked="checked"</c:if>/>
<input type="hidden" id="chk_0" name="chkSms"
value="0"/>
<td> <!-- end of checkbox -->

Struts2 Populate Lists

I am having issues populating a List of User defined object attributes in Struts2.
Here is my example (getters / setters ommitted):
public class Foo { private String attr1; private String attr2;
}
public class Bar { private List foos; }
public class StrutsAction extends ActionSupport { private Bar bar; }
I have code in JSP as follows (extract):
<tr><td><input type="text" name="bar.foos.attr1"/></td><td><input type="text" name="bar.foos.attr2"</td></tr>
<tr><td><input type="text" name="bar.foos.attr1"/></td><td><input type="text" name="bar.foos.attr2"</td></tr>
I need each table row to create 1 foo item in the List with each attribute, however my code creats a new foo object for each attribute when passed through and I end up with 4 foos rather than 2!
I understand I can solve the problem with hard coding the Index into the html as follows:
<tr><td><input type="text" name="bar.foos[0].attr1"/></td><td><input type="text" name="bar.foos[0].attr2"</td></tr>
<tr><td><input type="text" name="bar.foos[1].attr1"/></td><td><input type="text" name="bar.foos[1].attr2"</td></tr>
I was wondering if it can be done without hard coding the Indexes?
I think you can use the Struts 2 iterator tag:
<s:iterator var="foo" value="bar.foos">
<tr><td><s:property value="attr1"/> .....
</s:iterator>
If it does not work, we can think in other solution.
You can find more information here: http://struts.apache.org/2.3.1/docs/iterator.html
[]s
You said you have variable number of rows. Let's name it numOfRows... Try to rewrite your example like so:
<table>
<s:iterator status="stat" value="(numOfRows).{ #this }" >
<tr>
<td><input type="text" name="bar.foos[%{#stat.index}].attr1"/></td>
<td><input type="text" name="bar.foos[%{#stat.index}].attr2"/></td>
</tr>
</s:iterator>
</table>
You can find docs about Iterator tag there... Look at the bottom of the page.
If you don't have numOfRows at render phase, then I am afraid the only way to generate textfields is javascript on client side....
[EDIT]
Regarding indexes... You don't have to bother if you have indexes something like this:
<table>
<tr>
<td><input type="text" name="bar.foos[0].attr1"/></td>
<td><input type="text" name="bar.foos[0].attr2"/></td>
</tr>
<tr>
<td><input type="text" name="bar.foos[3].attr1"/></td>
<td><input type="text" name="bar.foos[3].attr2"/></td>
</tr>
<tr>
<td><input type="text" name="bar.foos[5].attr1"/></td>
<td><input type="text" name="bar.foos[5].attr2"/></td>
</tr>
</table>
Struts will do the conversion just right... You just have to be aware, that objects who's indexes are missing will be null... So you should filter them out in the action.

Categories