Pagination using PageObject Watir Webdriver [duplicate] - selenium-webdriver

Using page-object and watir-webdriver how can I click a link in a table, based on the row text as below:
The table contains 3 rows which have names in the first column, and a corresponding Details link in columns to the right:
DASHBOARD .... Details
EXAMPLE .... Details
and so on.
<div class="basicGridHeader">
<table class="basicGridTable">ALL THE DETAILS:
....soon
</table>
</div>
<div class="basicGridWrapper">
<table class="basicGridTable">
<tbody id="bicFac9" class="ide043">
<tr id="id056">
<td class="bicRowFac10">
<span>
<label class="bicDeco5">
<b>DASHBOARD:</b> ---> Based on this text
</label>
</span>
</td>
<td class="bicRowFac11">
....some element
</td>
<td class="bicRowFac12">
<span>
<a class="bicFacDet5">Details</a> ---> I should able click this link
</span>
</td>
</tr>
</tbody>
</table>
</div>

You could locate a cell that contains the specified text, go to the parent row and then find the details link in that row.
Assuming that there might be other detail links you would want to click, I would define a view_details method that accepts the text of the row you want to locate:
class MyPage
include PageObject
table(:grid){ div_element(:class => 'basicGridWrapper')
.table_element(:class => 'basicGridTable') }
def view_details(label)
grid_element.cell_element(:text => /#{label}/)
.parent
.link_element(:text => 'Details')
.click
end
end
You can then click the link with:
page.view_details('DASHBOARD')

Table elements include the Enumerable module, and I find it very useful in cases like these. http://ruby-doc.org/core-2.0.0/Enumerable.html. You could use the find method to locate and return the row that matches the criteria you are looking for. For example:
class MyPage
include PageObject
table(:grid_table, :class => 'basicGridTable')
def click_link_by_row_text(text_value)
matched_row = locate_row_by_text(text_value)
matched_row.link_element.click
#if you want to make sure you click on the link under the 3rd column you can also do this...
#matched_row[2].link_element.click
end
def locate_row_by_text(text_value)
#find the row that matches the text you are looking for
matched_row = grid_table_element.find { |row| row.text.include? text_value }
fail "Could not locate the row with value #{text_value}" if matched_row.nil?
matched_row
end
end
Here, locate_row_by_text will look for the row that includes the text you are looking for, and will throw an exception if it doesnt find it. Then, once you find the row, you can drill down to the link, and click on it as shown in the click_link_by_row_text method.

Just for posterity, I would like to give an updated answer. It is now possible to traverse through a table using table_element[row_index][column_index].
A little bit more verbose:
row_index could also be the text in a row to be matched - in your case - table_element['DASHBOARD']
Then find the corresponding cell/td element using either the index(zero based) or the header of that column
table_element['DASHBOARD'][2] - Selecting the third element in the
selected row.
Since you do not have a header row (<th> element) you can filter the cell element using the link's class attribute. Something like this
table_element['DASHBOARD'].link_element(:class => 'bicRowFac10').click
So the code would look something like this:
class MyPage
include PageObject
def click_link_by_row_text(text_value)
table_element[text_value].link_element(:class => 'bicRowFac10').click
end
end
Let me know if you need more explanation. Happy to help :)

Related

visualforce emailtemplate issue referencing a list in an Apex class

I suffer an error trying to implement a visualforce emailtemplate. The dev console gives me the following problem on the VF component: Unknown property 'String.Name' (line 0). I can't figure out how to resolve this. Consequently the email template doesnt work & gives me the error: <c:ProductOrderItemList can only contain components with an access level of global.
I aim to send an email from a Product Order (parent). In the email I want to include child records (product order items).
Apex class:
public class ProductOrderTemplate
{
public Id ProductorderID{get;set;}
public List<Product_Order_Item__c> getProductorderItems()
{
List<Product_Order_Item__c> toi;
toi = [SELECT Product_Type__r.Name, Quantity__c FROM Product_Order_Item__c WHERE Product_Order__c =: ProductorderID];
return toi;
}
}
The visualforce component:
<apex:component controller="ProductOrderTemplate" access="global">
<apex:attribute name="ProductOrdId" type="Id" description="Id of the Product order" assignTo="{!ProductorderID}"/>
<table border = "2" cellspacing = "5">
<tr>
<td>Name</td>
<td>Quantity</td>
</tr>
<apex:repeat value="{!ProductorderID}" var="toi">
<tr>
<td>{!toi.Name}</td>
<td>{!toi.Quantity}</td>
</tr>
</apex:repeat>
</table>
</apex:component>
And the email:
<messaging:emailTemplate subject=“Product Order” recipientType="User" relatedToType=“Productorder”>
<messaging:htmlEmailBody >
Hi,<br/>
Below is the list of ... for your Product order {!relatedTo.Name}.<br/><br/>
<c:ProductOrderItemList ProductOrderId="{!relatedTo.Id}" /><br/><br/>
<b>Regards,</b><br/>
{!recipient.FirstName}
</messaging:htmlEmailBody>
</messaging:emailTemplate>
Any help much appreciated! Quite stuck on this. I'm new to visualforce and apex.
​​​​​​​
You might need just a VF email template without component and apex class. Go to Product_Order_Item__c object, find Product_Order__c field definition. Write down the "Child Relationship Name".
Let's say it'll be "Line_Items". You need to add "__r" to the end (why?) and then you can do something like that:
<messaging:emailTemplate subject="Product Order" recipientType="User" relatedToType="Productorder">
<messaging:htmlEmailBody >
<p>here are your line items</p>
<table>
<apex:repeat value="{!relatedTo.Line_Items__r}" var="item">
<tr>
<td>{!item.Name}</td>
<td>{!item.Quantity}</td>
</tr>
</apex:repeat>
</table>
</messaging:htmlEmailBody>
</messaging:emailTemplate>
If you still think you want Apex and component (maybe you want to filter some records out, maybe you want to have them sorted or have a reusable piece of markup to use in multiple emails)...
... the error you're getting is because ProductorderID is a single String (well, Id) variable. But you've used it in a repeat that expects a list/array. A reference to <apex:repeat value="{!ProductorderItems}" var="toi"> should call your getProductorderItems() and work better.

Create def Check if a URL is Vaild if it is not found go to a different URL to edit that field but check the current URL then pull the correct info

Trying To create def Check if a URL is Valid if it is not found go to a different URL pressed a button to edit that field but check the current URL then pull the correct info from config and send to the text field
below is what I am looking at
<tbody><tr>
<th width="150">License Key *</th>
<td width="1">:</td>
<td><input type="text" name="LicenseKey" value="" size="80" maxlength="64"></td>
</tr>
</tbody>
>
def licenses(value):
try:
gotoURL(builder+value)
if driver.find_element_by_xpath('//*[#id="main-message"]/h1/span'):
gotoURL(base_url+value)
if driver.find_element_by_xpath('//*[#id="main-message"]/h1/span'):
gotoURL(server1+value)
if driver.find_element_by_xpath('//*[#id="main-message"]/h1/span'):
gotoURL(server2+value)
except NoSuchElementException:
pressButton(license_edit)
if driver.current_url(builder):
sendKeys(license_key,server_license)
if driver.current_url(base_url):
sendKeys(license_key,serverlicense)
if driver.current_url(zach_server):
sendKeys(license_key,server_license1)
if driver.current_url(michael_server):
sendKeys(license_key,server_license2)
this is the errors I am getting TypeError
I am guessing that you are getting the typeError because
driver.find_element_by_xpath()
returns a WebElement that for whatever reason can’t be converted to a boolean for your if statements. Try switching to
driver.find_elements_by_xpath()
This method will still work even if only one element is found, it just returns an array containing that element. This is important because python is able to see an array of length 1+ (if one or more elements are found) and convert it to a Boolean as true.

Chaining an element using css containing text and accessing an associated field

I need to access the input field in the below html. The way the page is setup I need to chain using the 'Address Line 1' text and then sending text to the input field. The input field id changes and so doesn't the layout of the fields depending on user preference. I am struggling. If you need some more information feel free to ask I did not want to overload with too much information.
<td class="labelCol requiredInput">
<label for="00N36000000xina"><span class="assistiveText">*</span>Address Line 1</label>
</td>
<td class="dataCol col02">
<div class="requiredInput">
<div class="requiredBlock"></div>
<input id="00N36000000xina" maxlength="255" name="00N36000000xina" size="20" tabindex="4" type="text">
</div>
</td>
I have accessed like this:
element(by.css('div.pbSubsection:nth-child(3) > table:nth-child(1) > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(2) > input'))
However depending on where the user puts the fields it can move around. So what I was hoping was to be able to access the label\ and use that to pinpoint its input field.
I don't know protractor but I cobbled together some code that hopefully will work or be close and I'll give you the thought process and some info and hopefully you can use it to fix my code, if needed, and solve the problem.
Start by finding an element by XPath, "//label[text()='Address Line 1']". This searches for a LABEL tag that contains "Address Line 1". Once you find that element, get the label attribute. From your HTML, this label is the id for the INPUT element you want. Now use the id to find the element and do with it what you want.
id = element(by.xpath("//label[text()='Address Line 1']")).getAttribute("label")
input = element(by.id(id))
input.sendkeys("some text")
Haven't tested this myself, but you could try something like this:
// $ is shorthand for element(by.css())
$('div.assistiveText').getAttribute('for').then(function (val) {
// locate the <input> by the value of the attribute on <label>
element(by.id(val)).sendKeys('abc'); // replace sendKeys with your intended function
});
Or if that first locator on the label isn't specific enough, swap out $('div.assistiveText') for element(by.cssContainingText('Address Line 1'))
I tried it for other attributes (I don't have a for attribute anywhere in my app) and it seemed to work for me.
Try this:
List<WebElement> elementList = driver.findElements(By.cssSelector("tbody > tr"));
for (WebElement element : elementList) {
if(element.findElement(By.cssSelector("td.labelCol > label")).getText().equalsIgnoreCase("Address Line 1")) {
element.findElement(By.cssSelector("input[type='text']")).sendKeys("textToInput");
}
}

How to display xml2json data

I am using xml2json to translate a xml file from medline. I am stuck on using ng-repeat to display the information I need. I need to display the title,url and see-reference. When i have one health-topic in the xml file The title and url display fine. When I add more health-topics it does not work. any help is appreciated, thanks
plunkr
<table>
<tr ng-repeat="topic in topics">
<td>{{topic._title}}</td>
<td>{{topic._url}}</td>
<td>{{topic.see-reference}}</td>
</tr>
</table>
<pre>{{topics | json}}</pre>
The structure of your XML is like this:
<health-topics total="1909" date-generated="01/03/2015 02:30:35">
<health-topic title="Abdominal Pain">
</health-topic>
<health-topic title="Abdominal Pain">
</health-topic>
<health-topic title="Abdominal Pain">
</health-topic>
xml2json creates an object for every element. The properties of the object are the element's attributes (starting with an underscore) and the child elements. In your case:
//health-topics
{
_total: "1909",
_date-generated: "01/03/2015 02:30:35",
health-topic: [
{
_title: Abdominal Pain"
...
health-topic is an array containing the topics. If you have a single topic wrapped with health-topics it would be:
//health-topics
{
_total: "1909",
_date-generated: "01/03/2015 02:30:35",
health-topic: {
_title: Abdominal Pain"
...
health-topic is now an object. But maybe a single topic wouldn't even be wrapped with a health-topics element. That's something only you know.
All in all the data structure is different depending on the number of topics. You would need to check and adapt to that. The code working for multiple topics would be
$scope.topics = $scope.dom['health-topics']['health-topic']

AngularJS: Show if X > Y and add class

I am building my first app. It is an ordering system where a customer can add items to the cart. Everything is working well. However, my client would like a way to alert the customer if they try to add a quantity to the cart that is greater than the current stock.
My client doesn't want to show stock levels, unless the customer adds something greater than the stock available.
I have a table with stock items in each row. I'd like to do three things, if the stock level is greater that available stock, I'd like to change:
• Class on the table row
• Add class disabled to the submit
• Show a div that has the available stock in.
To make matters a little more interesting, customers have to order by packs and not individual items.
Basically, I am trying to get the following code to work:
This is the general markup:
<tr ng-repeat="series_detail in productDetail | filter:filter">
<td>{{series_detail.sku}}</td>
<td>{{series_detail.size}}</td>
<td>{{series_detail.price</td>
<td>{{series_detail.pack}}</td>
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
<td><span class="itemtotal">{{series_detail.price * qty | number:2}}</span></td>
<td class="form-inline" style="text-align:right;">
<input type="submit" class="add_to_cart_submit btn btn-danger btn-small" value="Add">
</td>
</tr>
I want to then show this div
<div ng-show="'{{totalitems}}' > '{{series_detail.stock}}'">Yo, no stock dude</div>
I have tried adding a model, 'totalitems' to a row and then using ngShow to pop it up. However, it seems that 'totalitems' is evaluating to nothing. I've experimented with a few other options, but nothing has worked (ngIF etc.).
Regarding the changing of class, I am guessing, that once I get this sorted, I can transfer the expression to ngClass? I have played with this, and again, nothing has worked so far.
Provided this line goes inside the ng-repeat:
<div ng-show="qty * series_detail.pack > series_detail.stock">Yo, no stock dude</div>
For the class indication, lets say on tr, you could use the same expression as:
<tr ng-class="{outOfStock: (qty * series_detail.pack > series_detail.stock)}" ng-repeat="series_detail in productDetail | filter:filter">
outOfStock is class in your CSS.
BTW,
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
does not set totalitems to whatever {{qty * series_detail.pack | number}} evaluates to.
If you really need totalItems in your model a possible option is to have a method on the series_detail instance
objRef.totalItems = function(qty) {
return qty * this.pack;
}
and use it as:
<div ng-show="series_detail.totalItems(qty) > series_detail.stock">Yo, no stock dude</div>
<td>{{series_detail.totalItems(qty) | number}}</td>
I am not to sure to understand everything but something like this should works ?
<div ng-show="isStockAddedGreaterThanAvailable()">{{series_detail.stock}} Yo, no stock dude </div>
And in your controller
$scope.isStockAddedGreaterThanAvailable = function(){
....
}

Resources