Using selenium i'm trying to read out a dynamically generated table, i got down to the right elements (using the findElement method) but using getText() on them returns nothing.
Probably because getText() looks for quotation marks when returning "text" and can't find any between the <td> tags. Some suggestions were to use xpaths but since the tables are generated dynamically the location of the value i need also changes.
here's the table i'm trying to get 3 data points from:
<table cellpadding="0" cellspacing="0" class="fleetinfo">
<tbody><tr>
<th colspan="2">Schepen:</th>
</tr>
<tr>
<td>Groot vrachtschip:</td>
<td class="value">
40 </td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<th colspan="2">Lading:</th>
</tr>
<tr>
<td>Metaal:</td>
<td class="value">
536.062 </td>
</tr>
<tr>
<td>Kristal:</td>
<td class="value">
289.008 </td>
</tr>
<tr>
<td>Deuterium:</td>
<td class="value">
92.750 </td>
</tr>
</tbody></table>
the ones i'm interested in are the ones inside the <td class="value"> tags but as i said before, using getText() on them returns null.
Any idea on how i can acces those values?
edit: here's how i'm doing it now
private int getMetalFromFleet(WebElement fleet)
{
int ret=0;
WebElement streak = fleet.findElement(By.className("starStreak"));
List<WebElement>fleetDetails = streak.findElements(By.tagName("tr"));
for(WebElement detail : fleetDetails)
{
List<WebElement> tabel = detail.findElements(By.tagName("td"));
if(tabel.size() != 2)
continue;
if(tabel.get(0).getText().equalsIgnoreCase("metaal:"))
{
ret = Integer.parseInt(tabel.get(1).getText());
break;
}
}
return ret;
}
edit: here's the relevant bit of html
<div id="fleet9965869" class="fleetDetails detailsOpened" data-mission-type="4" data-return-flight="false" data-arrival-time="1378241688">
<span class="timer tooltip" title="03.09.2013 22:54:48" id="timer_9965869">58m 48s</span>
<span class="absTime">22:54:48 Klok</span>
<span class="mission neutral textBeefy">Plaatsen</span>
<span class="allianceName"></span>
<span class="originData">
<span class="originCoords tooltip" title="killernerd">[5:213:8]</span>
<span class="originPlanet">
<figure class="planetIcon planet tooltip js_hideTipOnMobile" title="planeet"></figure>k7 </span>
</span>
<span class="marker01"></span>
<span class="marker02"></span>
<span class="fleetDetailButton">
<a href="#bl9965869" rel="bl9965869" title="Vlootdetails" class="tooltipRel tooltipClose fleet_icon_forward">
</a>
</span>
<span class="reversal reversal_time" ref="9965869">
<a class="icon_link tooltipHTML" href="http://uni107.ogame.nl/game/index.php?page=movement&return=9965869" title="Roep terug:| 04.09.2013<br>01:54:05">
<img src="http://gf2.geo.gfsrv.net/cdna2/89624964d4b06356842188dba05b1b.gif" height="16" width="16">
</a>
</span>
<span class="starStreak">
<div style="position: relative;">
<div class="origin fixed">
<img class="tooltipHTML" height="30" width="30" src="http://gf1.geo.gfsrv.net/cdnf0/af41c52dc08208b4463f4a4608e88c.png" title="" alt="">
</div>
<div class="route fixed">
<div style="display:none;" id="bl9965869">
<div class="htmlTooltip">
<h1>Vlootdetails:</h1>
<div class="splitLine"></div>
<table cellpadding="0" cellspacing="0" class="fleetinfo">
<tbody><tr>
<th colspan="2">Schepen:</th>
</tr>
<tr>
<td>Groot vrachtschip:</td>
<td class="value">
960 </td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<th colspan="2">Lading:</th>
</tr>
<tr>
<td>Metaal:</td>
<td class="value">
8.173.484 </td>
</tr>
<tr>
<td>Kristal:</td>
<td class="value">
6.325.966 </td>
</tr>
<tr>
<td>Deuterium:</td>
<td class="value">
7.474.821 </td>
</tr>
</tbody></table>
</div> </div>
</div>
<div class="destination fixed">
<img class="tooltipHTML" height="30" width="30" src="http://gf2.geo.gfsrv.net/cdnaa/af0b356fdbecc1cfc47130e990fa66.png" title="Aankomsttijd:| 03.09.2013<br>22:54:48" alt="">
</div>
</div>
</span><!-- Starstreak -->
<span class="destinationData">
<span class="destinationPlanet">
<span>
<figure class="planetIcon planet tooltip js_hideTipOnMobile" title="planeet"></figure>Hoelbrak </span>
</span>
<span class="destinationCoords tooltip" title="killernerd">[1:2:6]</span>
</span>
<span class="nextTimer tooltip" title="04.09.2013 03:52:31" id="timerNext_9965869">5u 56m 31s</span>
<span class="nextabsTime">03:52:31 Klok</span>
<span class="nextMission friendly textBeefy">Keer terug</span>
<span class="openDetails">
<a href="javascript:void(0);" class="openCloseDetails" data-mission-id="9965869" data-end-time="1378241688">
<img src="http://gf3.geo.gfsrv.net/cdnb6/577565fadab7780b0997a76d0dca9b.gif" height="16" width="16">
</a>
</span>
</div>
the values i need are the numeric values under "Metaal", "kristal" and "deuterium".
I would recommend using xpath in this scenario rather then relying on tagnames;
private int getMetalFromFleet(WebElement fleet)
{
By identifier = By.xpath("td[contains(text(),'Metaal')]/following-sibling::td[contains(#class,'value')]");
return Integer.parseInt(fleet.findElement(identifier).getText());
}
Obviously you will want some error handling in there, but hopefully this gives the idea that those loops are not always required, and Xpath isn't always the bogeyman it is made out to be by some.
EDIT
Just in case anyone is confused, it is okay for the XPath to not have leading slashes if the selector is performed on a WebElement rather than the WebDriver object.
You would have to add two leading slashes if this selector was used on the WebDriver object.
EDIT AGAIN!
Xpath may need some tweaking but you should get the idea of the approach. I cannot see "StarStreek" in your html but it was in your code so added it to my xpath.
I found some kind of an answer after digging through a ton of programming sites.
Apparently items that have the style="display:none"; flag set like this will be seen as "hidden" by selenium.
This is, unfortunately, a feature and not a bug of some sort as selenium "tries to emulate the user" and will therefore hide information that is not explicitely visible.
"The user can't see it so neither can selenium" is their thought progress.
Here is the source.
This, unfortunately, does not solve my issue. I can however try to get around this, I'll report back my findings.
EDIT: It's amusing how different HtmlUnitDriver is from FirefoxDriver. One thing that works on HtmlUnitDriver won't work on FirefoxDriver and vice versa.
EDIT-2: Found a solution! Finally.
Using selenium's JavascriptExecutor I can directly get the innerHTML from the found element like so:
By identifier = By.xpath("*[contains(#class,'starStreak')]//td[contains(text(),'Metaal:')]/following-sibling::td[contains(#class,'value')]");
String script = "return arguments[0].innerHTML";
String outcome = (String) ((JavascriptExecutor) driver).executeScript(script, fleet.findElement(identifier));
It's still annoying as hell that you can't just use getText() though. It should at least be an option.
Got similar problem - i want to click on a row in a table which has given value. Solution (id can be changed to class name etc.):
driver.findElement(By.xpath("//table[#id='<yourTableId>']//tr//td[contains(text(),'"+<givenValue>+"')]")).click();
When I get value of td, I can get for 12 td per tr tag. More than 12 must one click on td tag then getText()
This work for me correctly.
Related
I have a code which clicks on a radio button, at first I was using Chrome. Using the code below:
driver.findElement(By.id("radioButton1"))).click();
I got the error:
"org.openqa.selenium.WebDriverException: Element is not clickable at point (411, 675). Other element would receive the click: ..."
Doing research, I changed the code to:
actions.moveToElement(driver.findElement(By.id("radioButton1"))).click().perform();
Now, I am trying to use Internet Explorer driver. But it does not perform the click.
I tried the following:
driver.findElement(By.id("radioButton1")).sendKeys(Keys.ENTER);
actions.moveToElement(driver.findElement(By.id("radioButton1"))).click().perform();
((JavascriptExecutor) driver).executeScript("arguments[0].click()", driver.findElement(By.id("radioButton1")));
But none works. The first one just focuses on the button, so I added another sendKeys, but it doesn't work. The 2nd and 3rd, nothing happens.
Edit:
Adding HTML snippet.
<input name="btn1" class="w-rdo-native" id="radioButton1" type="radio" value="value1" bh="RDOINP" isrefresh="false">
<label class="w-rdo w-rdo-dsize" bh="RDO"></label>
And when I click on the radio button, the label gets an additional property upon click.
<label class="w-rdo w-rdo-dsize" bh="RDO" AWMouseDown="true"></label>
Additional edit:
The set of buttons look like this:
and as stated before, one button + label block has the following HTML structure:
<tr>
<td>
<div class="w-rdo-container">
<input name="radioButtons" class="w-rdo-native" id="button1" type="radio" value="button1" bh="RDOINP" isrefresh="false">
<label class="w-rdo w-rdo-dsize" bh="RDO">
</label>
</div>
</td>
<td class="sectionHead">Option 2
</td>
</tr>
Upon clicking a button, the corresponding label gets an additional attribute:
<label class="w-rdo w-rdo-dsize" bh="RDO" AWMouseDown="true"></label>
It seems AWMouseDown seems to be the trigger to 'officially' click the button.
Edit :
Full HTML snippet of table. (Please note that this table has been cleansed so apologies for some mistake if I committed one.)
<table border="0" cellpadding="0" cellspacing="0" class="a-cptp-tbl">
<tbody>
<tr>
<td>
<div class="w-rdo-container">
<input checked class="w-rdo-native" id="btn1" name="radioBtn" type="radio" value="btn1"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 1</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>
<div class="w-rdo-container">
<input class="w-rdo-native" id="btn2" name="radioBtn" type="radio" value="btn2"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 2</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>
<div class="w-rdo-container">
<input class="w-rdo-native" id="btn3" name="radioBtn" type="radio" value="btn3"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 3</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>
<div class="w-rdo-container">
<input class="w-rdo-native" id="btn4" name="radioBtn" type="radio" value="btn4"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 4</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>
<div class="w-rdo-container">
<input class="w-rdo-native" id="btn5" name="radioBtn" type="radio" value="btn5"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 5</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>
<div class="w-rdo-container">
<input class="w-rdo-native" id="btn6" name="radioBtn" type="radio" value="btn6"><label class="w-rdo w-rdo-dsize"></label>
</div>
</td>
<td class="sectionHead">Option 6</td>
</tr>
<tr>
<td></td>
</tr>
</tbody>
</table>
Try using JavaScript like below:
WebElement radioBtn1 = driver.findElement(By.id("radioButton1"));
((JavascriptExecutor) driver).executeScript("arguments[0].checked = true;", radioBtn1);
If you are using QMetry Automation Framework, you should create custom radio button component like where you can override click method with such custom implementation.
Use ExplicitWait to wait for element until clickable and then have to click on that element
WebElement element = driver.findElement(By.id("radioButton1"));
WebDriverWait wait = new WebDriverWait(driver, 120);
wait.until(ExpectedConditions.elementToBeClickable(element));
element.click();
EDITED
If it is causing problem in IE browser. The cause is preventing to find element in IE browser is ActiveX Controls
So just you need to follow these steps -
Go to Internet options > Advanced > security and do check below mentioned checks -
after check > apply and then don't forgot to restart your PC
Now simply run your script and try to click on that element using id
driver.findElement(By.id("button1")).click();
Hope this will work. Let us know if still face the same issue.
Can you try identifying the radio buttons using a list and then clicking on an element in the list using its index with get()?
List<WebElement> radioGrp = driver.findElements(By.name("xxxxxxxx"));
radioGrp.get(0).click();
Not sure what is causing the problem.It works for me thought:
public static IWebDriver driver;
[Test]
public void TestMethod1()
{
driver = new PhantomJSDriver();
driver.Navigate().GoToUrl("file:///C:/Users/utripra/Desktop/test.html");
driver.FindElement(By.Id("radioButton1")).Click();
It seems that the radio button is combination of the <input> and <label> tags, i.e. the <div> with class="w-rdo-container" or its <td> parent. I think so because the rapper <td> and the <td> where the label Option 2 is are siblings.
class="w-rdo-container" doesn't seem to be unique, so you can use xpath to go up the html tree from id="button1"
driver.findElement(By.xpath("//div[input[#id='button1']]")).click(); // to click the div
// or
driver.findElement(By.xpath("//td[div[input[#id='button1']]]")).click(); // to click the td
Try following for clicking on Option 2 radio button:
driver.findElement(By.xpath("//td[normalize-space(text())='Option 2']/preceding::input[1]")).click();
Write a method that will accept the position of the radio button and click on the button by using cssSelector as follows:
driver.findElement(By.cssSelector("table.a-cptp-tbl > tbody > tr:nth-child(" + checkBoxPosition + ") > td > div > input")).click();
Full method:
public void selectOption(int positionOfCheckBox){
By locator = By.cssSelector("table.a-cptp-tbl > tbody > tr:nth-child(" + positionOfCheckBox + ") > td > div > input");
//wait for your element to be visible
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
//click element after it is visible/clickable
driver.findElement(locator).click();
}
Just add Thread.sleep(5000); above your script for radio button.
For example like this
Thread.sleep(5000);
driver.findElement(By.id("uniform-id_gender2")).click();
It works for me.
:)
Currently working on the automation of salesforce application.
I need a quick help to check the below code, i am unable to identify the element using java container. here is the HTML source for the page.
<div class="pbBody">
<span id="j_id0:j_id1:j_id5:matrixGrid">
<div id="j_id0:j_id1:j_id5:j_id7">
<div class="pbSubsection">
<table class="detailList" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<tr>
<th class="labelCol vfLabelColTextWrap last " scope="row">
<td class="dataCol last ">EUR</td>
<th class="labelCol vfLabelColTextWrap last " scope="row">
<td class="dataCol last ">
<span id="j_id0:j_id1:j_id5:j_id7:j_id11:theDrPriceMatrix">Germany</span>
</td>
</tr>
</tbody>
</table>
JAVA Container is written here to identify element in tag
WebElement w5=driver.findElement(By.cssSelector("table.detailList"));
System.out.println(w5);
WebElement w6=w5.findElement(By.xpath("/html/body/form/span/div/div/div/div/div[1]/span/div/div/table/tbody/tr[2]"));
WebElement w7=w6.findElement(By.cssSelector("td.dataCol"));
List<WebElement> l3=w7.findElements(By.tagName("span"));
for (int i = 0; i <l3.size();i++)
{
System.out.println(l3.get(i).getText());
}
l3.get(0).getText();
actually the issue is I am not able to write anything for in the container
I am trying to select the email, password, and signin elements from here.
The element has a unique ID and I'm able to copy the Xpath from inspecting it.
I have tried these queries and unable to figure out why Selenium cannot find it.
WebElement emailfield = driver.findElement(By.id("lid"))
WebElement emailfield = driver.findElement(By.xpath("//*[#id=\'lid\']"));
WebElement emailfield = driver.findElement(By.xpath("//*[#id=lid]"));
The drive is able to open and launch chrome to do this. However, I am not lucky.
Please let me know in what way these are not valid. As I understand it, the id should be completely unique but neither the By.id and By.xpath methods are not finding the element.
Here is my code.
String email = "myemail";
String password = "the_password";
WebElement emailfield = driver.findElement(By.id("lid"));
emailfield.sendKeys(email );
WebElement passwordfield = driver.findElement(By.xpath("//*[#id=pwd]"));
passwordfield.sendKeys(password );
WebElement login = driver.findElement(By.id("submit_but"));
login.click();
Here is HTML table.
<table width="260" align="center" class="mob_width" cellspacing="2" cellpadding="1">
<tbody><tr>
<td colspan="2">
<h3 class="signintxt">Sign In</h3>
</td>
</tr>
<tr>
<td align="center" colspan="2"><span id="msgpanel"></span></td>
</tr>
<tr>
<td class="label">Email / Phone:</td>
<td align="left"><input name="lid" class="input usrbx" id="lid" onkeypress="clearmsg()" type="email" value=""></td>
</tr>
<tr>
<td class="label">Password:</td>
<td align="left"><input name="pwd" class="input passbx" id="pwd" onkeypress="clearmsg()" type="password"></td>
</tr>
<tr>
<td class="label"></td>
<td align="left"><div class="forgotpasslink"><span onclick="goToForgotPassword();">Forgot Password?</span></div>
</td></tr>
<tr id="hiptr" style="display: none;">
<td class="label"> </td><td align="left"> </td>
</tr>
<tr>
<td class="emptytd"></td>
<td height="30" class="mobile-height">
<div class="sectxt">
<label>
<input name="rem" id="rem" type="checkbox" value="10">
<span class="securetxt">Keep me signed in</span>
</label>
</div>
</td>
</tr>
<tr>
<td class="emptytd"></td>
<td align="left">
<button name="submit" class="submit_mobile" id="submit_but" type="submit">Sign In</button>
</td>
</tr>
</tbody></table>
Here is an Explicit wait that compiles, and wait 10 seconds and gives same error.
//explicit
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement aboutMe;
aboutMe= wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//form[#id='login']//*[#id='lid']")));
aboutMe.click();
The fields are inside <iframe>. You need to switch to it first
driver.switchTo.frame("zohoiam"); // switch by iframe ID
WebElement emailfield = driver.findElement(By.id("lid"));
// some more code
driver.switchTo().defaultContent(); // switch out of the iframe
For more switch options look here.
You have made syntactical error while writing the xpath,
//*[#id=\'lid\']
has wrong syntax [You can verify this using firebug & firepath].
Try below xpath it should work,
.//*[#id='lid']
However you can add the parent Form node to make it more robust,
.//form[#id='login']//*[#id='lid']
Finally, you need to make sure that you wait till the page is loaded completely before going for element identification.
For more on explicit wait, refer Selenium webdriver explicit wait
Below is the html code... I want to know which xpath can I use to select such a check box.
In actual HTML code I have multiple td for checkboxes, here I have shown only one.
I already tried
driver.findElement(By.id("cntMain_GridView1_chIndividual_0")).click();
but it gives an error saying no such element found on web page.
<table id="cntMain_GridView1" class="table iconTwo" cellspacing="0" cellpadding="3" style="width:100%;border-collapse:collapse;">
<tbody>
<tr>
<td class="no-sorting" valign="top" align="left" style="width:10px;">
<p class="defaultP" tabindex="35">
<span style="display:inline-block;width:5%;">
<div class="ez-checkbox">
<div class="ez-checkbox">
<input id="cntMain_GridView1_chIndividual_0" class="ez-hide" type="checkbox" onclick="javascript:RbtnOnOff(this.id);" name="ctl00$cntMain$GridView1$ctl02$chIndividual" tabindex="-1"/>
</div>
</div>
</span>
</p>
</td>
</tr>
</tbody>
</table>
Try changing the display style property of the element and then clicking on the element. Use JavascriptExecutor to make the element visible. Try the following code:
JavascriptExecutor js = (JavascriptExecutor) driver;
String domain_name = (String) js.executeScript("return document.getElementById(" +
"'cntMain_GridView1_chIndividual_0').style.visibility = 'visible'");
driver.findElement(By.id("cntMain_GridView1_chIndividual_0")).click();
I have two list on my request on jsp. First one is productGroupName, and the second is products.
Now, I show these like below.
<html:form action="/priceOrder"> <table width="100%" id="tableStyle" style="font: message-box;padding: 20px;">
<logic:iterate id="productGroups" name="productGroup">
<tr>
<td>
<h3 style="background-color: #720D00; color: white;"><bean:write
name="productGroups" property="prodGroupName" /></h3>
<table width="100%" id="tableStyle" style="font: message-box; color: white; padding: 20px; background: #F15A00;">
<tr>
<td width="200px"><strong>Product Name</strong></td>
<td width="100px"><strong>How Many</strong></td>
<td><strong>Info</strong></td>
</tr>
<logic:iterate id="product" name="products">
<tr>
<c:if test="${(productGroups.prodGroupID) == (product.prodGroupID)}">
<td>
<html:checkbox property="productChecked" ><bean:write name="product" property="prodName"/></html:checkbox> <br />
</td>
<td><html:text property="quantity" styleId="check" size="5"/></td>
<td><bean:write name="product" property="prodDesc" /></td>
</c:if>
</tr>
</logic:iterate>
</table>
</td>
</tr>
</logic:iterate>
<tr align="center" style="background-color: #F15A00;"><td height="50px">
<html:submit styleId="buton" property="method"><bean:message key="button.order" /></html:submit>
</td></tr>
<tr><td></td></tr>
</table></html:form>
As you see firstly I iterate productGroupNames, showing if productID is equal to productGroupID under productGroupName. But I have a problem on getting check box and quantity info. I need which product is checked and how many that is wanted.
Instead of doing a form submit directly, submit it through a JS function. In your JS function, since you're iterating your list and giving the checkbox and text field the same name, you'll get an array with the same name.
That is you'll get an array of the IDs. You can get the index of the selected checkbox, get the quantity, get the corresponding list element and populate separate hidden form variables with the value. Then submit it.
An alternative approach would be to have a hidden variable associated with each checkbox which provides some mapping between the list and the checkbox.
I don't do Struts, but their documentation at least says that you need the <html:multibox> for this.