Finding dynamic text using selenium - java

I have a webpage that dynamically places a text in a span. It is something like:
<table id=table_1>
<td>
<span> $available/$total <span><label id=label_1>Servers available</label>
</td>
</table>
The only thing i know is that either "x/y Servers available" or "No Servers Available" would be displayed on the webpage. Please let me know how can I get this x and y.
<html>
<body>
<div class="refresh_div" >
<table id="Server_status_table" >
<!-- -----------For Server Status box header ---------------->
<tr>
<%
int num=Integer.parseInt(request.getAttribute("availWorkerCount").toString());
int tot=Integer.parseInt(request.getAttribute("totalWorkerCount").toString());
int avg = 0;
if(tot!=0 && num>0){
avg=num*100/tot;
}
pageContext.setAttribute("total", tot);
%>
<c:choose>
<c:when test="${ total eq 0 }">
<!-- -----------For showing how many servers are available now---------------->
<td>
<label id="Avaibility_l" style="font-size: 120%;">Availability</label>
</td>
<td>
<span>No server available</span>
</td>
</c:when>
<c:otherwise>
<!-- -----------For showing how many servers are available now---------------->
<td>
<label id="Avaibility_l" style="font-size: 120%;">Availability</label>
<br/> &nbsp
</td>
<td >
<!-- -----------For showing the availability bar---------------->
<div id="progress" class="progress">
<div id="bar" class="bar" style="width:<%=avg %>%;"></div>
</div>
<!-- -----------For showing the availability progress detail message---------------->
<span>
${availWorkerCount} / ${totalWorkerCount}<label id="Progress_message_l"> occupied</label>
</span>
</td>
</c:otherwise>
</c:choose>
</tr>
<tr>
<!-- -----------For showing the approximate Queue Wait time ---------------->
<td>
<label id="Queue_wait_time_l" style="font-size: 120%;">Queue waiting time</label>
</td>
<!-- -----------For showing the approximate wait time detail message---------------->
<td >
<label id="Wait_time _message_1stpart_l" >Approximately</label>
${queueWaitingTime}
</td>
</tr>
</table>
</div>
</body>
</html>
I need ${availWorkerCount} , ${totalWorkerCount} and ${queueWaitingTime}

I have an idea. Please follow the below steps might work for you, this answer is from the HTML prospective. I not sure what you mean by
I need ${availWorkerCount} , ${totalWorkerCount} and ${queueWaitingTime}
Full example code after the steps. Just to mention, I have not ran this code.
1.Search the Element label by text
label[contains(.,'Servers available')]
you can add id check with it also like
label[contains(#id,'label_1') and contains(.,'Servers available')]
2.get the label and then get the parallel element span. Span should have the value
CODE :
List<WebElement> elements = driver.findElements(By.xpath("label[contains(#id,'label_1') and contains(.,'Servers available')]");
for(// now loop over the elements)
{
WebElement elem = elements.get(0);
List<WebElement> spanelems = elem.findElements(By.xpath("../span"));
spanelems.get(0).getText() // this should give you the data under the span
}

With WebDriver you're picking text off from the page after it has finished loading. Thus getting this kind of "dynamic" text won't be a problem. Your example is only dynamic on the server side, in the client side the text from these variables would be static content and just as easy to grab from the page as any other text.
I suggest you put an id attribute to the <span> you're looking for, then it's super simple to get its contents with Selenium.
For example:
<span id="myStuff">foobar</span>
And fetch it with:
String contentsOfMySpan = driver.findElement(By.id("myStuff")).getText();
* EDIT *
Since you can't change original code, here's the hard way to do it:
By qwt = By.xpath("//label[#id = 'Wait_time _message_1stpart_l']/parent::td/text()[2]");
By wc = By.xpath("//label[#id = 'Progress_message_l']/parent::span/text()[1]");
String queueWaitingTime = driver.findElement(qwt).getText();
String[] workerCounts = driver.findElement(wc).getText().split(" / ");
String availWorkerCount = workerCounts[0];
String totalWorkerCount = workerCounts[1];

Related

SpringBoot. Thymeleaf. How to make table's column clickable to send request to Controller?

I've created table with 8 columns:
<table border="1" cellspacing="0" cellpadding="0">
<tr height="30">
<div th:each="horiz1, state : ${#numbers.sequence(1, 8)}">
<td width="30" th:value=${state.count} th:attr="action=#{/}" >
</td>
</div>
</tr>
</table>
In fact each column (tag "td") should serve as a button and after clicking send me to controller (#PostMapping or #GetMapping), where I will try to read th:value. How to make it?
Instead of th:attr="action=#{/}" I've tried to use th:href="#{/}" - does not work.
I've tried to insert between tags "td" the Form Button, but could not make it invisible and with size on complete size of column.
UPD. Full html code
<body>
<table border="1" cellspacing="0" cellpadding="0">
<div th:each="vert : ${#numbers.sequence(1, 4)}">
<tr height="30">
<div th:each="horiz1, state : ${#numbers.sequence(1, 8)}">
<td width="30" th:value=${state.count} th:attr="action=#{/}" th:style="${state.odd}? 'background: #f4cd8d' : 'background: #745853'">
</td>
</div>
</tr>
<tr height="30">
<div th:each="horiz2, state : ${#numbers.sequence(1, 8)}">
<td width="30" th:style="${state.even}? 'background: #f4cd8d' : 'background: #745853' "> </td>
</div>
</tr>
</div>
</table>
</body>
I'm creating chess board. After clicking at any cell, it should go to Controller, make some calculations and highlite cell, where a horse can move.
Simplify the Thymeleaf
Parts of this may not be directly relevant to your core question, but there is a lot you can do to simplify the Thymeleaf which generates the chess table.
By doing this, you can get rid of all the <div> elements you are currently using, and also make it easier to handle click events, later on:
<table id="chessboard" border="1" cellspacing="0" cellpadding="0">
<tr height="30"
th:each="row, rStat : ${#numbers.sequence(1, 8)}">
<td th:each="col, cStat : ${#numbers.sequence(1, 8)}"
width="30"
th:data-row=${rStat.count}
th:data-col=${cStat.count}
th:style="${(rStat.odd and cStat.odd) or (rStat.even and cStat.even)}
? 'background: #f4cd8d' : 'background: #745853'">
</td>
</tr>
</table>
The main differences here are:
I place the Thymeleaf th:each iterators in the <tr> and <td> tags.
I only have one piece of logic to handle coloring each square.
I create two data- attributes in each <td> to uniquely identify each square.
Just to note:
You could argue that there is not much benefit from using Thymeleaf here, since basically everything is hard-coded in the Thymeleaf template. Normally, you would expect Thymeleaf to receive values from the controller - but for drawing the chess board, no such server-provided data is needed.
It does allow for a more compact template, I suppose.
Clicking each Square
The resulting HTML generated by the above Thymeleaf has no click events. It's easier to add these events immediately following table HTML, in a <script>...</script> tag - for example:
// get an array containing the <td> elements
var squares = document.getElementsByTagName('td');
// loop through that array, adding an event to each element:
for (i = 0; i < squares.length; i++) {
squares[i].addEventListener('click', function (e) {
console.log('clicked on row ' + this.getAttribute('data-row')
+ ' col ' + this.getAttribute('data-col'));
});
}
In my case, the click events just cause a line of informational text to be printed to the browser's console - for example:
In your case, you want to send this data (the row and column numbers) to your controller. That is a much bigger question.
If you are not familiar with how to do this, you can research various questions - for example: How to send js variable to Spring controller? - and probably many more similar questions.
If you get stuck, you can ask a new, more targeted, follow-up question.

How to access a webtable element using xpath if the webtable element is inside a td tag

I am not able to access the webtable elements inside the table2 , please see the page source below :
<table id="table1">
<tr class="head">
<td class="left" colspan="2">
<!--PAGE LINKS-->
</td>
</tr>
<tr>
<td class="left_link">
<h1>
<a name="nav_home" href="index.html" id="home_link" class="home">HOME</a><br>
<a name="nav_adopt" href="adoption.html" id="adoption_link">ADOPTION</a><br>
<a name="nav_about" href="about.html" id="about_link">ABOUT</a><br>
<a name="nav_contact" href="contact.html" id="contact_link">CONTACT</a><br>
</h1>
</td>
<td class="content">
<h1>
CONTACT US
</h1>
<hr>
<p>
Use the form below to contact us if you have any questions, queries or even any requests.
We are always happy to hear from you all.
</p>
<h1 class="subhead">Contact Form</h1>
<form name="message_form">
<table id="table2" class="inner_table">
<tr>
<td>Enter Name</td>
<td><input type="text" name="name_field"></td>
</tr>
<tr>
<td></td>
<td>
<input type="radio" id="rinfo" name="rbutton" value="information">Information
<input type="radio" id="rdona" name="rbutton" value="Donation">Donation
<input type="radio" id="radop" name="rbutton" value="Donation">Adoption
</td>
</tr>
For example i am not able to access the name inside the table2.
I tried accessing using below but failed .
driver.findElements(By.xpath("//*[#class='table1']/tbody/tr[2]/td[2]/form/table[#class='inner_table']/tr[1]/td[1))
Try this below xpath
//table[#id='table2']/..//following::input[#name='name_field']
Explanation of xpath:- Use id attribute of <table> tag and move ahead with <input> tag using following keyword.
This above xpath will locate the Enter Name field text box.
Note:- Instead of using absolute xpath, Use relative xpath.
It is not recommended to use xpath on selenium, since elements might tend to change and you have to refactor your selector if you add another element.
To answer your question, you can use the id for table2 and select the desired element.
It should be a CSS selector as simple as input[name='name_field'] or if that isn't specific enough, use #table2 input[name='name_field'].
Try xpath like below:
to access input filed with name 'name_field' use below xpath
driver.findElement(By.xpath("//table[#id='table2' and #class= 'inner_table']//input[#type='text' and #name='name_field']")
Hope it will help.
In web tables, you can use xPath to reach parent of an element and then finding the preceding-sibling or the following-sibling of td tags
This tutorial will help you:
http://www.seleniumtests.com/2011/10/using-xpath-to-reach-parent-of-element.html

How to show the variable values at the top of the table in jsp?

I am passing an object from servlet to jsp and then I am iterating that object in the jsp and showing the results in a table as shown below. And while iterating the table, I calculate some counts and store it in a variable.
These are my count variable -
kCount
rCount
totalCount
And then I am showing the actual values of these count variables in fieldset as shown below and it works fine.
<div>
<!-- if I try to show the fieldset here, then I see all the values coming as zero. -->
<TABLE>
<TR>
<TH>VALUE1</TH>
<TH>VALUE2</TH>
<TH>VALUE3</TH>
<TH>VALUE4</TH>
</TR>
<c:set var="kCount" value="0" scope="page"/>
<c:set var="rCount" value="0" scope="page"/>
<c:set var="totalCount" value="${CV.getValue().size()}" scope="page"/>
<c:forEach var="i" begin="0" end="${CV.getValue().size() - 1}">
<TR>
<TD>
${CV.getValue().get(i)}
</TD>
<TD>
${CV.getHasR().get(i)}
<c:if test="${CV.getHasR().get(i) == 'True'}">
<c:set var="rCount" value="${rCount + 1}" scope="page"/>
</c:if>
</TD>
<TD>
${CV.getType().get(i)}
<c:if test="${CV.getType().get(i) == 'K'}">
<c:set var="kCount" value="${k + 1}" scope="page"/>
</c:if>
</TD>
</TR>
</c:forEach>
</TABLE>
<!-- I don't want to show the fieldset here, it should be shown at the top of the table -->
<fieldset>
<legend><b>Window</b></legend>
<table>
<tr>
<th>VALUE2</th>
<th>VALUE3</th>
</tr>
<tr>
<td>Total rows:</td>
<td>${totalCount}</td>
</tr>
<tr>
<td>R Count:${rCount}</td>
<td>K count:${kCount}</td>
</tr>
</table>
</fieldset>
</div>
Now If I try to copy this fieldset and try to show at the top of the table instead of showing at the bottom of the table, then I see all the values as zero. My main goal is to show the values of each variables in the fieldset but it should be shown at the top of the table, not at the bottom.
Any thoughts how this can be one if possible at all?
There are at least three options here (I am sure there are many more):
Calculate your totals in the servlet and pass them to the JSP for display
In the JSP, loop through your data first to calculate the totals and display them, then loop again to display the data
In the JSP, loop through and display your data while calculating your totals, then use jQuery or similar to write the totals back into the correct location using javascript.

How to iterate an object in JSP to get the percentage?

I am working on servlet and jsp project. I am passing an object from servlet to JSP. And currently I am iterating that object and showing them in a table -
Below is my code in jsp -
<TABLE id="tableSMS" BORDER="1" CELLPADDING="3" CELLSPACING="1" style="text-align: center;">
<TR style="color:#ffffff;background-color:#787878;">
<TH>Hash Name</TH>
<TH>Database Name</TH>
<TH>Version</TH>
</TR>
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TR>
<TD>
${reportCount.getHash().get(i)}
</TD>
<TD>
${reportCount.getDatabaseName().get(i)}
</TD>
<TD>
${reportCount.getVersion().get(i)}
</TD>
</TR>
</c:forEach>
And above code is working fine and I am able to show the data properly. Now what I need to do is -
${reportCount.getDatabaseName().get(i)} will return database name as oracle or mysql only. Now I need to calculate what is the percentage of oracle database. I will get the total number of records from ${reportCount.getHash().size(). So if total number of records is 10 and oracle database is present 5 times, then the percentage should be 50%.
Now I am not sure how would I calculate the above percentage using that object? And after calculating that percentage, I need to show the result in a new table which is shown below -
<table>
<tr>
<th style="background-color: #E8E8E6;"><b>Oracle Database</b></th>
</tr>
<tr>
<!-- I would like to show the percentage in this row -->
<td>%</td>
</tr>
</table>
I am thinking I should iterate the reportCount object again in the above new table and extract the percentage here but not sure how would I do that? Can anyone provide an example?
UPDATE:-
Here is my bean code -
public class Response {
private List<String> hash = new LinkedList<String>();
private List<String> databaseName = new LinkedList<String>();
private List<String> version = new LinkedList<String>();
// getters and setters here
}
There are three things as following:
Add the functions taglib:
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
Add reportsCounts variable to requestScope instead of session if not required on any other page & use as following:
<c:set var="oracleDBCount" value="0" scope="page" />
<c:forEach var="reportCount"
items="${requestScope.reportCounts.databaseName}" varStatus="loop">
<TR>
<TD>${requestScope.reportCounts.hash[loop.index]}</TD>
<TD>${reportCount}
<c:if test="${reportCount == 'ORACLE'}">
<c:set var="oracleDBCount" value="${oracleDBCount + 1}" scope="page"/>
</c:if>
</TD>
<TD>${requestScope.reportCounts.version[loop.index]}</TD>
</TR>
</c:forEach>
Now display percentage as:
${(oracleDBCount / fn:length(requestScope.reportCounts))*100}%
Based on my experience, doing number-crunching on a JSP page can make it unreadable very quickly. Also you may encounter additional requirements in the future such as:
Text matching (Are you guaranteed that the value is always "oracle"? Or can it become "ORACLE" or "Oracle"?
What if there are zero reports? Then you will need an if-condition to prevent division by zero.
If your client says "We have more report servers like MS, Postgres...can you show the percentage of those?"
Is it possible to do the computation inside the servlet while you are making the reportCount object?
Then you can pass the value inside a session attribute
request.getSession(true).setAttribute("oracleReports", "50%")
and then in the JSP output something like
<c:out value="${sessionScope.oracleReports}"/>
Use JavaScript for doing the operation, Here is the code
Read the comments to understand the code.
Add an id to the so that i can read the inner content using
javascript. Appended id with the index so that each raw gets different
id's
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TD id="databaseName<c:out value='${i}' />">
${reportCount.getDatabaseName().get(i)}
</TD>
Add Id to the so that i can set values to the raw using
JavaScript
<tr>
<td id="oraclePercentage">%</td>
<td id="mySQLPercentage">%</td>
</tr>
call the javascript function to set the values to the raw, as we don't
have any button to trigger we open a raw and add the JavaScript call
from the JSP so that the script is triggered every time the page loads
the raw.
<TR><TD><Script>setPercentage('${reportCount.getHash().size() - 1}');</script><TD><TR>
what to do is defined here
<Script>
function setPercentage(var index){
for(var i=0; i<index;i++){
var documentType=document.getElementById("databaseName"+i).innerHTML;
var oracleCount=0;
var mySQLCount=0;
if(vardocumentType=='Oracle')
oracleCount+=(Number)1;
else if(vardocumentType=='MySQL')
mySQLCount+=(Number)1;
document.getElementById("oraclePercentage").innerHTML=(oracleCount/index)*100;
document.getElementById("mySQLPercentage").innerHTML=(mySQLCount/index)*100;
}
</script>

How to edit fields of a table?

I have a table to show a long list of items, I am wondering how I can edit the fields and submit the form to update them?
<form name="edit" method="POST" action="edit">
<table border="4">
<tbody>
<c:forEach items="${basket.items}" var="item">
<tr>
<td>
<input name="item.id" value="${item.id}"/>
</td>
<td>
<input label="Price" value="${item.product.price}"/>
<br/>
</td>
</tr>
</c:forEach>
</tbody>
</table>
this is a new one
<input id="edit" type="submit" name="edit" value="Edit"/>
</form>
You are using Struts2, with JSTL and EL instead of Struts Tags and OGNL... is there a particular reason that forces you to drop most of the framework mechanics ?
That said, your inputs aren't valid (no type specified) and the "this is a new one" sentence in the HTML seems to indicate the willing to insert a new row, instead of editing the existing entres. Your description and your code seem to ask two different things... to insert a new one, just make a call to another method of the action (or another action) called "add" instead of "edit", sending one single element and adding it to the collection. No need to use AJAX here...
If instead, the question is really:
how I can edit the fields and submit the form to update them ?
this is the way:
<s:form method="POST" action="edit">
<table border="4">
<tbody>
<s:iterator value="basket.items" var="item" status="ctr">
<tr>
<td>
<s:textfield name="item[%{#ctr.index}].id" />
</td>
<td>
<s:textfield name="item[%{#ctr.index}].product.price" />
</td>
</tr>
</s:iterator>
</tbody>
</table>
<s:submit value="Edit"/>
</form>
I would suggest you make an AJAX call using jquery to update the new one. And then in the success handler you can append the new line to the existing table. Before doing that you need to give your table proper ids so that its easier to use JQUERY.
var newLine = document.createElement("tr");
var cellName = document.createElement("td");
$(cellName).text("itemId");
$(newLine).append(cellName);
// similarly create other td's
$("#modelTable").append(newLine);// replace modelTable by the id of your table

Categories