In Selenium using Ruby, how would I select this updated element's text using xpath? - ruby

I'd like to select the text inside 'updatedOn_1756', which would typically return something like "10:12 PM". How would I do this? I thought it would be something like element = driver.find_element(:id, "updatedOnID"), but that doesn't work. I'm using Firefox, incidentally.
EDIT: I believe the page is dynamically updated. Though there is no text inside the source shown here, there is a time displayed on the page (it doesn't show in the page source when I click 'view source').
<tr id='row_for_1756' >
<td class="IDClass">1756</td>
<td>Jameson</td>
<td><a id='DrinkName_1756' class="linkToClient" title="Launch Live Viewer" href='/client/Client.application?myid=1756'>Stevens 18</a> -
<a title="BETA Client" href='/client/Client.application?bell=1756' style="color: green; font-weight: bold;">(BETA VERSION)</a> - <a id='DrinkName_Old_1756' class="linkToClient" title="Version before" href='/client/blank/Client.application?myid=1756' style="color: Red;">(old version)</a></td>
<td>9980</td>
<td><span id='updatedOn_1756' class="updatedOnID"></span></td>
<td><span id='histUpdatedOn_1756' class="updatedOnID"></span></td>
</tr>

The reason it doesn't work is because you're asking for an id with the value updatedOnID, which doesn't exist. There is a class with that value, but since you're looking for the id, you'll need the entire ID value, including the number:
driver.find_element(:id, "updatedOn_1756")

Related

Thymeleaf: Form submit on click of table row

I have a table with orders and order ids. I would like to click on a row to view the order details in another page. My code:
<form id="orderDetalsForm" th:action="#{/restaurant/orderdetails}"
method="POST" th:object="${order}">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">Order Id</th>
<th scope="col">Order Details</th>
<th scope="col">Date</th>
<th scope="col">Amount</th>
</tr>
</thead>
<tbody>
<tr id="orderRow" th:each="order : ${orders}"
style="cursor: pointer"
th:onclick="'getOrderItems(\''+${order.orderId}+ '\');'">
<td scope="row" th:text="${order.orderId}"></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<tr>
<td colspan="3">Total</td>
<td th:text="${grandTotal}"></td>
</tr>
</tbody>
</table>
</form>
I tried an ajax form submit:
<script>
function getOrderItems(orderId) {
var url = "/restaurant/orderdetails";
$.ajax({
url : url,
type : "post",
data : {
"orderId" : orderId
},
success : function(data) {
console.log(data);
},
error : function() {
console.log("There was an error");
}
});
}
</script>
In my controller I have this:
#PostMapping(value="/restaurant/orderdetails")
public ModelAndView orderDetails(#RequestParam String orderId){
List<Product> orderDetails = userService.getOrderDetails(orderId);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("orderDetails", orderDetails);
modelAndView.setViewName("restaurant/orderdetails");
return modelAndView;
}
While the ajax works, the page is not getting redirected to my orderdetails page.
You can't use AJAX to redirect to a page. AJAX is for getting data from the server that is then processed/displayed using JavaScript. You however basically want clicking on the row to behave like clicking a link or (since you are using a POST mapping) submitting a form.
First off, using POST makes this a bit more complicated. You should consider using a GET mapping, not only because it makes this problem easier, but also because a POST mapping isn't really appropriate here. POST is used to send data to the server, which you are not doing.
Another thing you should consider it that using a (pure) JavaScript solution to link the table row hinders accessibility. For example, users that can't/don't use a mouse (such as disabled people or search engines) won't be able to see or even use such a link. To solve this it is a good idea to add a proper link to the row. Then that link can used by "clicking" on it with the JavaScript of the click handler.
<tr th:each="order : ${orders}" onclick="orderRowClick(this)">
<td scope="row"><a th:href="#{/restaurant/orderdetails(orderId=${order.orderId})}" th:text="${order.orderId}"></a></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<script>
// Look for a link in the row and click on it
function orderRowClick(row) {
row.querySelector("a").click();
}
</script>
Several more points:
IDs must be unique in HTML. By putting id="orderRow" on such a repeated row will result in invalid HTML.
You shouldn't be using on... attributes to assign event handlers. I'm just using it here or otherwise this answer will go too far.
Remove the <form> from around the table. It doesn't do anything.
If you do want to/have to use a POST mapping, then replace the link in the table row with a form with a hidden field containing the order ID and a submit button and in the JavaScript look for the form instead of the link and submit it: row.querySelector("form").submit();.
BTW there are several (possibly better) ways to do what you are trying. For example:
Forget the JavaScript and just put a link into every cell. With the right CSS the row/cells can be changed so that it looks like you are clicking on the row.
It seems like you are using Bootstrap, which has the "stretched link" feature. Unfortunately it's a bit tricky to get to work with table rows, but it's worth looking at.
What I've understand so far is that you want to redirect user to a new page when the user clicks on the button on the table, for that there're different approaches -
Issue with your approach -
Since you're using ajax it wont be redirecting user to a new page ( because thats exactly how a AJAX works, for more info on AJAX us this link - https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX ), unless you explicitly tells your ajax-code to redirect the user on a new page.
For that you can simply put your page redirection code to a on your ajax success, something like this -
<script>
//your code
$.ajax({
// your code
success : function(data) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
},
error : function() {
console.log("There was an error");
}
});
}
</script>
PS - This is not efficient programming practice since you're technically making an extra call to your server un-necessarily.
Approach 2nd
Simply make your html table buttin a-href link , like this -
<html>
// your code
<a th:href="#{'/restaurant/orderdetails/orderId=' + ${order.orderId}}">Order details button </a>
//your rest of the code
</html>
Approach-3rd , You can alternatively use java-script function for page redirection as well, simply modify you ajax function , something like this -
function getOrderItems(orderId) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
}

Trying to provide hyperlink in HTML based on ng-if condition...not working

I want to provide a link on a text based condtion utilizing ng-if.
If functions return true I want to provide the link, otherwise display just the value with no link.
<th style="text-align:left">
<span ng-if="(mandalLink())">
<a ng-href="/#!/l2-mandal/{{department}}/{{d}}" title="Click to see data at Mandal Level">{{d}}</a>
</span>
<span ng-if="(!mandalLink())"> {{d}} </span>
</th>
I have used ng-if at other places and its working but in this case it's not. What am I doing wrong here?
In your .html-file try:
<th style="text-align:left">
<span ng-if="showLink">
<a ng-href="/#!/l2-mandal/{{department}}/{{d}}" title="Click to see data at Mandal Level">{{d}}</a>
</span>
<span ng-if="!showLink"> {{d}} </span>
</th>
In your .ts-file (on ngOnInit or where you get/assign a value to 'department'..)
showLink;
getDepartmentOrWhatEver(){
... // your logic getting 'department' assigned
if (department == "") {
this.showLink= false;
}
else {
this.showLink= true;
}
}
From the docs on ng-if:
The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
ngIf differs from ngShow and ngHide in that ngIf completely removes and recreates the element in the DOM rather than changing its visibility via the display css property. A common case when this difference is significant is when using css selectors that rely on an element's position within the DOM, such as the :first-child or :last-child pseudo-classes.
FYI: The brackets are not needed around the function, just <span ng-if="mandalLink()"> is fine..

Click on a link in a table based on the other text in the row in selenium IDE 2

I am new to selenium and have very little coding experience. That being said, I am trying to set up a suite of regression tests for my software. I run into a problem when making a test to add and save a new contact and information, then immediately delete the contact (just to make sure any new additions to the software don't break that functionality). My contacts are saved into a table with the name in the first column, details in the second, edit link in the third, delete link in the fourth, and assign contact link in the fifth. Everything works fine right after I set up the test, but the IDE assigns what delete link to click with an xpath so if i add another contact before my test contact, the wrong one gets deleted. How do I target the delete link in my test contact row so it will search for the text "test contact" and click the delete link in the same row everytime even if i have changed the order of the contacts in the table or added many new contacts? Below is a sample of one row in the table. I need to select delete based on the name in that row.
<table class="tbl">
<thead>
<tbody>
<tr>
<td>
<a class="entityLink" target="_attached" href="../download/Average+Inspection.xlam?documentID=55840"> Average Inspection.xlam </a>
</td>
<td></td>
<td>43.76 Kb</td>
<td>SP: Randi kay Anderson</td>
<td>5/16/14 1:13 PM</td>
<td> No </td>
<td>
<ul class="actlinks llink">
<li>
<a class="al-assign" target="_top" href="/app/admin/massAssignFiles.do?m=massAssignSLFileAttachment&returnPage=BACK_ADMIN_SEARCH_UPLOADEDFILE&documentID=55840"> Assign </a>
</li>
<li>
<a class="al-delete" onclick="return myConfirm();" href="/app/admin/manageFiles.do?m=deleteFile&documentID=55840">Delete</a>
</li>
<li>
<a class="al-edit" href="/app/admin/manageFiles.do?m=editFile&fileid=55840">Edit</a>
</li>
<li>
<a class="al-edit" target="_top" href="sharingPermissions.do?m=editFileSharingPermissions&returnPage=BACK_ADMIN_SEARCH_UPLOADEDFILE&fileID=55840">Edit Sharing Permissions</a>
</li>
</ul>
</td>
</tr>
What I feel, there should be some uniqueness among the entries of table.So you should use that unique property to locate and perform action on your required element.
By looking into above table, I assume that ?documentID=55840 is that unique property for each table and you can use this to locate the required element. The only thing you have to add in your code is , after adding a new entry your code should be able to obtain the documentId of newly added entry.
You can do it in following steps:
Add a new entry
Obtain the document Id of newly added entry
Using the document Id locate the delete element
// Given text should be dynamic to make it generic
String hrefOfElememnt = driver.findElement(By.xpath("//a[contains(text(),'Average Inspection.xlam')]")).getAttribute("href");
String[] hrefArray= hrefOfElememnt .split("?");
String[] documentIdArray = hrefArray[1].split("=");
String documentId = documentIdArray [1];
// To find delete button
WebElement deleteLink = driver.findElement(By.xpath("//a[#class='al-delete' and contains(#href,'"+ documentId +"')]"));
deleteLink.click();
use this
command- click
target- xpath=//*[text()="text you want to click"]
I used it, this will solve your problem

Scrolling div by ID

I have an HTML page with this structure.
<div class="scrollBoxYe">
<table class="grid">
<tr><td class="wd0"><div id="20110701" class="lcday"><div class="lcleft">Fri 01</div><div class="lcmid">The Sacred Heart of Jesus, solemnity - St. Gal, Bishop (c. 489-553), Bl. Antonio Rosmini, Priest, Founder of the Institute of Charity (1797-1855)</div><div class="lcright">Jul</div></div></td>
</tr>
<tr><td class="we0"><div id="20110702" class="lcday"><div class="lcleft">Sat 02</div><div class="lcmid">Immaculate Heart of Mary - Memorial - St. Bernardino Realino, Priest (1530-1616)</div><div class="lcright">Jul</div></div></td>
</tr>
<tr><td class="we0"><div id="20110703" class="lcday"><div class="lcleft">Sun 03</div><div class="lcmid">St. Thomas, Apostle -Feast</div><div class="lcright">Jul</div></div></td>
</tr>
</table>
</div>
<script type="text/javascript">
ScrollCalendar();
</script>
ScrollCalendar function should scroll to a div ID like 20110701, 20110702, 20110703.
function ScrollCalendar() {
var d = new Date();
calrow = d.formatDate("Ymd");
document.write (calrow);
var offscroll = window.parent.document.getElementById(calrow).offsetTop;
document.write (offscroll);
window.parent.document.getElementById("scrollBoxYe").scrollTop = offscroll;
}
In the function above the div ID which is retrieved with the variable calrow is determined correctly. However, the code doesn't come up with the right offset (offscroll) to scroll the div (scrollBoxYe). These are my questions:
If calrow is right (does show 20110701). Will getelementby ID interpret calrow as a string ID to retrieve the element? Should I make calrow into a string first? What's the right function to do that?
Is it wrong to search for the element with window.parent.document if all the page information is in one document? Should the code say instead document.getElementbyID("scrollBoxYe").scrollTop?
Is there a better way to scroll scrollBoxYe with the variable calrow?
Thanks.
There is a better way to scroll: element.scrollIntoView()
http://msdn.microsoft.com/en-us/library/ms536730(v=vs.85).aspx
It's not part of the standard but according to this it is supported by all browsers.

html() does not retrieve the whole content

I am getting the following response
<div id="weblogs">
<tr>
<td nowrap class="bl">1</td>
</tr>
<tr>
<td nowrap class="bl">2</td>
</tr>
</div>
Now I am trying to attach the rows like the following:
function _ajax(postData)
{
loadUrl = "getweblogs.asp";
$.ajax( {
url : loadUrl, // your ajax file
type : 'post',
data : postData,
success : function( resp ) {
alert($("#weblogs" , resp).html());
$('#weblogs > tbody:last').append($("#weblogs" , resp).html());
}
});
return false;
}
The replace is working fine. My problem is, that the htmls elements from the response are removed. I'm getting only 1 and 2. instead of
<tr>
<td nowrap class="bl">1</td>
</tr>
<tr>
<td nowrap class="bl">2</td>
</tr>
I don't know what am I doing wrong. Could someone give me any clue?
Thank you!
Greetings
Magda
What you're trying to do is not so clear. Is there already an element with id="weblogs" in the page? If so, why does your response have an element with the same id (not a good idea), and if not, why are you trying to append an element's contents to itself like that (also, not a good idea)?
Why not just change the server-side to send the html required, without a wrapping div tag (which makes it invalid html anyway, another bad idea), and then use it as-is?
Another problem is that you're trying to select .html() of something that will always be an empty jquery object: $(selector, string) will never match anything. You'll need to make the string a jquery object if you want to search its substructure: string = $(string).
And I think you're misunderstanding the use of $(selector, $obj). The selector must be in the $obj's sub-structure:
$('#foo', $('<div id="foo"><span/></div>')); // returns empty jquery object
So looking for #weblogs in the substructure of an element with id weblogs will also never find anything.
Your question isn't entirely clear, but I'll try and answer: are you working with Internet Explorer? If so, consider this paragraph from the docs:
For example, Internet Explorer sometimes leaves off the quotes around attribute values if they contain only alphanumeric characters.
API docs: html()

Resources