Find text in unordered list and click on link within that list item - ruby

In a ruby script that uses watir, I'm trying to find text within an list item within an unordered list, then click on the link within that list item. In the sample below, I want to find "Apple" and have it click on the link that takes you to http://samplegrocerystore.com/tehnc34.
<div class="col-login">
<img class="logo" src="/images/hello.png" />
<h1 style="margin-top:15px;">Select Account</h1>
You have multiple accounts -- please select the one you would like to log in with.
<ul>
<li><h3>The Grocery Store</h3><h4>Chapter: Apple (#01)</h4>
<br/><strong>Login to this account</strong>
</li><li>
<h3>The Grocery Store</h3><h4>Chapter: Banana (#02)</h4>
<br/><strong>Login to this account</strong>
</li>
</ul>
</div>

I guess you are saying that you don't know the link href ahead of time?
Assuming you have opened the page in question using a Watir::Browser variable called browser:
Working off the unique text in the list item (Apple),
browser.li(:text, /Apple/).link(:text, 'Login to this account').click
should click the desired link.
Or if you do know the link href ahead of time, it is easier to use that:
browser.link(:href, 'http://samplegrocerystore.com/tehnc34').click
Either one should work, though if your web page is fairly complicated using a regex to find the word Apple might be slowish.

Based on your HTML, you can use the find method on a lists collection to locate the element with the specified text and then click on the link within the list element:
li = lists.find { |el| el.text.include? "Apple"}
li.a.click

try the following in irb:
browser.h4(:text => /Apple/).links.count
browser.h4(:text => /Apple/).parent.links.count
browser.h4(:text => /Apple/).parent.parent.links.count
until you find your answer with just 1 link, then that's your immediate link following the 'Apple' text. Then just call it like below:
browser.h4(:text => /Apple/).parent.link.click

Related

How to get number of list element (ul tag) of HTML using Get matching XPath count?

I'm kind of new to XPATH-query. I use RF and selenium2library and the XPath Helper-plugin in chrome to test a certain website page. I'm new to HTML/CSS/JavaScript as well.
The web page consists of two ULs (lists) for left and right sides of the page and each one has a few LIs which have few divisions comprised of widgets (JPEG images etc).
I need to count this list rows (number of LIs in each UL). I have already done the samething in a drop down menu to count its elements with no problem (perhaps because it was considered
a web element). But right now I use the same "Get Matching Xpath Count" which returns almost the whole page HTML source instead of a number and it then fails.
All my program is based on getting the number of LIs in a UL (of drop down menu, page, table,...). so I wonder what to do now. Here is an example of the HTML code of the page:
<ul class="rqcol" id="col8a580456553ae">
<li class="rqportlet" id="por8a58045655">
<div id="hdrpor8a580" class="rqhdr" onmouseover="RQ.util.showTools(this)" onmouseout="RQ.util.hideTools(this)"> </div> </li>
<li class="rqportlet" id="por8a580456" >
<div id="hdrpor8a581" class="rqhdr" onmouseover="RQ.util.showTools(this)" onmouseout="RQ.util.hideTools(this)"> </div></li>
</ul>
and my code was:
Get Matching Xpath Count | //ul[#id="ccol8a580456553ae"]/li
which does give me some texts plus HTML code.i also tried:
Get Length | //ul[#id="ccol8a580456553ae"]
which doesn't give me 2 but a big number.
An XPath 2.0 expression to count the 'li' for the specific '' would be:
//ul[#id="col8a580456553ae"]/count(li)
Try this new chrome extension
https://chrome.google.com/webstore/detail/relative-xpath-helper/eanaofphbanknlngejejepmfomkjaiic
You've made a typo in the id value - an extra "c" char in the beginning; otherwise the xpath is correct:
${count}= Get Matching Xpath Count //ul[#id="col8a580456553ae"]/li
By the way, the keyword Get Matching Xpath Count is deprecated in the latest version of the SeleniumLibrary, in favour of Get Element Count

Ignore element inside only certain divs

I have a basic web scraper written which pulls short sections of text from a webpage and puts them into a list. My problem is that there are dynamic ads that appear on the page and mess up the lists.
The page I'm scraping is a Yelp restaurant listing page.
I pull out the biz-name (business name) and add it to the list and it works fine but when the ads appear the scraper pulls the biz-name also.
This is the structure but I can't figure out how to ignore the 'AD element' and just scrape the normal business names. I've cut it down a lot and removed the 'unimportant' elements.
This is with an AD:
<li class="yloca-search-result">
...
...
<a class="biz-name"...><span>San Lorenzo’s</span></a>
</li>
This is a normal listing:
<li class="regular-search-result">
...
...
<a class="biz-name"...><span>BigGrill</span></a>
</li>
I've been trying to make Nokogiri ignore the business name inside the <li class="yloca-search-result"> and only select the others inside the regular-search-result class.
I can't figure it out. Can someone point me in the right direction at least? Is it possible?
I figured it out. Wasn't difficult but I just couldn't see the answer.
ad = doc3.at_css("li.yloca-search-result")
ad.remove

XPath is broken when changes are made

This is the current situation: There are several files and folders in a specific location.
Once you hover over a file or a folder, an icon appears then you can click on that icon and a menu will appear. From that menu a user can select any action(rename, move,etc). The problem is that the XPath which is provided by FirePath is broken whenever a new file/folder is created/added in the location.
This is the initial line of code which works fine until the XPath is broken:
webDriver.findElement(By.xpath("//*[#id='main_files_view']/ol/li[6]/ul/li[4]")).click();
Whenever a new item is added in the location, the index with value "6" can change to "7" (new position of the file) and the XPath generated is now slightly different:
webDriver.findElement(By.xpath("//*[#id='main_files_view']/ol/li[7]/ul/li[4]")).click();
How can I change that XPath and makes it robust so that no matter the number of items added/removed, the XPath will not break?
Below is the section of the HTML which is related to the XPath provided by FirePath.
When the XPath is provided, the last class is also highlighted.
<li class="storage_item document file_object even ui-draggable" data-thumb-translation="Translated" data-possible-actions="Rename Delete Share Move View" data-file-size="0 bytes" data-item-type="file" data-display-name="solids_A" data-name="solids_A.raas" data-id="bd48453c752043d98afb237b86ee88a3">
<a class="file_name" href="#/Item/Details?id=bd48453c752043d98afb237b86ee88a3&itemtype=File&tab=Default">
<img class="file_list_icon" width="16" height="16" src="https://api-staging.autodesk.com/content/gateway/2013.1.307595.626/z/Content/images/fileIcons/small/raas.png"/>
<div class="name_container">
<ul class="tools">
<li class="preview_trigger"/>
<li class="comment_balloon none has_tooltip" data-tooltip-contents="#comment_balloon_tooltip" data-comments="0">
<li class="categorize action has_tooltip" data-tooltip="Categories"/>
<li class="document_tools has_tooltip" data-tooltip="Actions"/>
</ul>
</li>
I am using Selenium 2.0, on Eclipse IDE.
If the data-name is unique, then you have
//*[#id='main_files_view']/ol/li[#data-name='solids_A.raas']/ul/li[contains(#class, 'document_tools')]
Css Selector is even better than XPath in this case:
#main_files_view li[data-name='solids_A.raas'] .document_tools
Try this:
By.XPath("//*[#id='main_files_view']/ol/li/ul/li[4]")
You do not have to define every index in an xpath and often if it's just one that change, removing that index will work.
In general you should avoid xpaths in your tests. Css selectors are faster (especially in IE) and more readable. If data-name is unique then this should work:
webDriver.findElement(By.cssSelector("#main_files_view li[data-name='solids_A.raas'] li.document_tools"));
If you really need an xpath the one provided by user1177636 will also do the job.

Click a button with XPath containing partial id and title in Selenium IDE

Using Selenium IDE, I'm trying to click a button within a table on a webpage using XPath with a partial id and a title from the element. The XPath I'm using is:
xpath=//*[contains(#id, 'ctl00_btnAircraftMapCell')]//*[contains(#title, 'Select Seat')]
and thats the entire html code for an example of the buttons im trying to click:
<li id="ctl00_MainContent_repAircraftMap_ctl20_repAircraftMapRow‌​_ctl00_liAircraftMap‌​Cell" class="">
<a id="ctl00_MainContent_repAircraftMap_ctl20_repAircraftMapRow‌​_ctl00_btnAircraftMa‌​pCell" href="javascript:void(0)" seatnumber="20A" mapbindattribute="1124" title="Select Seat 20A" onclick="SeatClick(1124);"></a>
</li>
Am I constructing this incorrectly? It's not working!
Now that you have provided your HTML sample, we're able to see that your XPath is slightly wrong. While it's valid XPath, it's logically wrong.
You've got:
//*[contains(#id, 'ctl00_btnAircraftMapCell')]//*[contains(#title, 'Select Seat')]
Which translates into:
Get me all the elements that have an ID that contains ctl00_btnAircraftMapCell. Out of these elements, get any child elements that have a title that contains Select Seat.
What you actually want is:
//a[contains(#id, 'ctl00_btnAircraftMapCell') and contains(#title, 'Select Seat')]
Which translates into:
Get me all the anchor elements that have both: an id that contains ctl00_btnAircraftMapCell and a title that contains Select Seat.

Get specific element in webdriver containing text

What are some good ways to retrieve a specific element in WebDriver/Selenium2 based only on the text inside the element?
<div class="page">
<ul id="list">
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
<li>Grape</li>
</ul>
</div>
Essentially, I'd like to write something like this to retrieve the specific element:
#driver.find_element(:id, "list").find_element(:text, "Orange")
This is very similar to how I would use a selector when finding text inside a link (i.e. :link_text or :partial_link_text), but I would like to find elements by text inside normal, non-link elements.
Any suggestions? How do you deal with this issue? (In case you were wondering, I am using Ruby.)
You could do that with xPath. Something like this for your example:
#driver.find_element(:id, "list").find_element(:xpath, './/*[contains(., "Orange")]')
A couple years late, but I was just going to ask this question and answer it so other could find it...
I used a css selector to get all the li elements and then filtered the array based on the text:
#driver.find_elements(css: '#list > li').select {|el| el.text == 'Orange'}.first
You could then .click or .send_keys :return to select the option.

Resources