Displaying all the results with selector gadget & nokogiri? - ruby

I am using selector gadget for the first time and am having trouble, when I run the code below, why do I only get the first result to display in the Terminal?
Also, is there any easier way to get the text after the ICD-10 code in the example page, because as of now selector gadget only gets the links, and not the plain text?
require 'rubygems'
require 'nokogiri'
require 'open-uri'
url = "http://en.wikipedia.org/wiki/ICD-10_Chapter_XVII:_Congenital_malformations,_deformations_and_chromosomal_abnormalities"
doc = Nokogiri::HTML(open(url))
puts doc.at_css("li li:nth-child(1) li a , li li ul:nth-child(5) :nth-child(1), .new, li:nth-child(3) li a, li li li:nth-child(10) li:nth-child(9) li:nth-child(4) :nth-child(1) li:nth-child(5) :nth-child(1) :nth-child(1) li:nth-child(2) :nth-child(1), li a:nth-child(4), li li li:nth-child(1), #mw-content-text li a:nth-child(5), li :nth-child(4) ul:nth-child(4) :nth-child(1), #mw-content-text li a:nth-child(3)").text

This gets all the text following a bullet with a Q code:
puts doc.search('//li[contains(a[#class="external text"]/#href, "icd10")]').map(&:text)
The XPath matches a list item (li) which contains an external link with icd10 in the URL, then extracts the text from it.
It's a bit of a broad brushstroke: it gets all the text, which means further manipulation will be necessary if you don't want the code, or subitems that don't have a code. But in any case it's a start.

See here:
http://nokogiri.org/Nokogiri/XML/Node.html#method-i-at_css
Search this node for the first occurrence of CSS rules. Equivalent to css(rules).first See Node#css for more information.
So, if you want to view all of the texts, might I suggest you do this:
selectors = ["li li:nth-child(1) li a", "li li ul:nth-child(5) :nth-child(1)", ".new", "li:nth-child(3) li a", "li li li:nth-child(10) li:nth-child(9) li:nth-child(4) :nth-child(1) li:nth-child(5) :nth-child(1) :nth-child(1) li:nth-child(2) :nth-child(1)", "li a:nth-child(4)", "li li li:nth-child(1)", "#mw-content-text li a:nth-child(5)", "li :nth-child(4) ul:nth-child(4) :nth-child(1)", "#mw-content-text li a:nth-child(3)"]
selectors.each do |s|
puts doc.at_css(s).text
end

Related

Element not interactable in dropdown. How to get an element?

Help please to get a correct solution of my task.
I have this dropdown (it looks like dropdown) with code:
<div class="jcf-select-drop jcf-select-jcf-hidden jcf-unselectable" style="position: absolute; top: 1331px; width: 376.125px; left: 285.75px;">
<div class="jcf-select-drop-content">
<span class="jcf-list jcf-scroll-active">
<span class="jcf-list-content" style="max-height: 369px; overflow: auto;">
<ul>
<li>
<span class="jcf-option" data-index="0">Afghanistan</span>
</li>
<li>
<span class="jcf-option" data-index="218">USA</span>
</li>
And simple test:
let countryTest = $$("span.jcf-select.jcf-unselectable").first();
let USA = $("body > div.jcf-select-drop.jcf-select-jcf-hidden.jcf- unselectable > div > span > span > ul > li:nth-child(217) > span");
countryTest.click();
USA.click();
I need to select USA, but have an error "Failed: element not interactable". I can get Afghanistan, but not USA.. I tried
browser.actions().mouseMove(USA).click().perform();
but it isn't help.
Can I somehow click on USA-element using data-index? Or what is correct way to choose the element?
And how is there a way to make shorter the element(by.css), because it's too long..
I am assuming that the dropdown contains a full list of countries. As such, USA will not be high on the list (number 218 it looks like). Because your dropdown will only display a limited amount of countries at once, USA is hidden. Most dropdowns allow text to be entered to search for a country. This also limits the matches to all be displayed on the screen. You can then click on USA (although its index may have changed)
Example
let countryTest = $$("span.jcf-select.jcf-unselectable").first();
let USA = $("body > div.jcf-select-drop.jcf-select-jcf-hidden.jcf-unselectable > div > span > span > ul > li:nth-child(217) > span");
//keep in mind USA selector will likely have changed after you do your search
countryTest.click();
countryTest.sendKeys('USA'); //likely will be a different element that you have to send keys to
USA.click();
Try the below one
const countryTest = element(by.cssContainingText('spna.jcf-list-content>ul>li>span', 'USA'));
So countryTest.click() selects USA from the dropDown.
hope it helps you.
Assuming you already solved clicking a parent element that displays the dropdown, have you tried the following?:
If you have just those 2 options:
var USA = element.all(by.css('.jcf-list-content ul li span')).last();
countryTest.click();
USA.click();
If the dropdown has more options (USA being 218?):
var USA = element.all(by.css('.jcf-list-content ul li span')).get(218);
countryTest.click();
USA.click();
You can try with the 'span' at the end, or removing it. I'm not sure which one will work.
Ultimately, try something like this:
var USA = element(by.cssContainingText('li', 'USA'));
countryTest.click();
USA.click();
Hope it helps.

document.querySelectorAll("span + a") didn't work?

I have a HTML like this.
<span class="vm-video-side-notification-text-item">
Includes copyrighted content
</span>
I use
var x = document.querySelectorAll("span + a");
alert(x.length);
the alert is "0"... I don't know why.
I see the w3school says
element+element
div + p
Selects all <p> elements that are placed immediately after <div> elements
so I try span + a. Can anyone correct my mistake?
You're conflating elements with tags.
While the start tag of the a is directly after the start tag of the span indeed, the a element is inside the span element.
So, in order for your example to work, you can either
change the query selector to "span > a" for "any a directly inside a span"
var x = document.querySelectorAll("span > a");
alert(x.length);
or change the html to have the a element after the span element
<span class="vm-video-side-notification-text-item">
</span>
Includes copyrighted content
(... but not both!)

li elements not created in foreach statement

Is there a maximum number li elements in an OL or UL ?
I have a static UL and in a foreach I'm trying to add elements to the list. If I add more than 9 elements only first LI is created. I checked my list and I have all the elements in it and the foreach statement is executed to the last element.
If I replace LI with UL Li (instead of creating one list element I'm creating a new list of 1 element) then everything works fine.

how to scroll a web application in watir

How do I scroll a web application in Watir ?
I have tried#browser.send_keys :space
This just brings the whole page down. But I have a scroll within the application, I need to scroll the vertical scroll bar down & up in my automation testing, Please help me !
Thanks!
<div dojoattachpoint="containerNode" class="containerNode tabContentPane typeNavigationSingleChild" style="overflow: auto; left: 5px; top: 10px; width: 1549px; height: 535px;">
<div pageid="lifecycle_theme_home_page_dashboard_pageId" id="lifecycle_theme_home_page_dashboard_pageId" style="height: 535px; padding: 0px; width: 1549px;" widgetid="lifecycle_theme_home_page_dashboard_pageId" title="" role="group" class="dijitContentPane wcs-nullLayout">
Solution 1) Scroll to Last Element
I think Vinay's approach should work. However, in the current form, it assumes that the element already exists on the page. I am guessing the element you want is only visible once you scroll far enough. So what you can do is scroll to the last element in the div.
Watir-Webdriver
In Watir-Webdriver:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
div_with_scroll.elements.last.wd.location_once_scrolled_into_view
Watir-Classic
In Watir-Classic, it is different since it does not use selenium-webdriver:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
div_with_scroll.elements.last.document.scrollIntoView
Solution 2) Use ScrollTop Property
As an alternative, if the above does not work, you can set the scrollTop property to move the div element's scrollbar. This worked for an application that I was working on that had content that was only loaded once you scrolled to the bottom.
Watir-Webdriver
To jump the scrollbar to the bottom, which in theory should trigger the below content to load, set the scrollTop property to the scrollHeight:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_bottom_script = 'arguments[0].scrollTop = arguments[0].scrollHeight'
div_with_scroll.browser.execute_script(scroll_bottom_script, div_with_scroll)
To jump back to the top, set the scrollTop to zero.
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_top_script = 'arguments[0].scrollTop = 0'
div_with_scroll.browser.execute_script(scroll_top_script, div_with_scroll)
You can also use any value in between depending on where you need to go to.
Watir-Classic
In Watir-Classic, you can set the scrollHeight more directly:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
#Go to bottom
div_with_scroll.document.scrollTop = div_with_scroll.document.scrollHeight
#Go to top
div_with_scroll.document.scrollTop = 0
if the element is at the bottom of the page, it will load more content:
browser.element.wd.location_once_scrolled_into_view
Using Watir-Classic, the second method Justin Ko provided works great for iterating through a scrollable section to find something specific. Here's an example of that:
div_with_scroll = browser.div(:class => 'containerNode tabContentPane typeNavigationSingleChild')
scroll_value = 50 # change this number to match how much you want to scroll each iteration
max_loop = div_with_scroll.document.scrollHeight / scroll_value
if div_with_scroll.document.scrollHeight % scroll_value > 0 # accounts for any remainder height
max_loop = max_loop + 1
end
for i in 0..max_loop do
div_with_scroll.document.scrollTop = i * scroll_value # moves the scrollbar
if div_with_scroll.text.include? 'Search Text'
puts 'Search Text found in iteration: ' + i.to_s()
break # exits the loop when found
end
end
There may be a more efficient way to do what I'm doing here, but you get the idea.
Use Javascript (eg. bottom of page):
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);\n")
use a correct javascript executor to achieve this result - below i have written some code to show you the 'in my opinion' best and most reliable way to achieve this:
BOTTOM OF PAGE:
((IJavaScriptExecutor)webapplication).ExecuteScript("window.scrollTo(0, document.body.scrollHeight - 5)");
TOP OF PAGE:
((IJavaScriptExecutor)webapplication).ExecuteScript("window.scrollTo(0, document.body.scrollHeight 0)");
you can also set different values to scroll to different heights - for example the scroll to bottom code i have set to 5px from the bottom of the page. good luck, hope this is of somewhat use to you.

How do I use an add on to create a rule to find and replace text in a Site?

I have both stylish and grease monkey installed in Firefox 5. I want to know if either of them or another add on has the capability of finding text and replacing it with something else, or better yet locating a div by its id and replacing the span within with another string of text.
From OP comment:
I have a website with a div (id=siteLinkList), with a ul and multiple lis inside the div.
Each li has an a with text that needs to be replaced. I want the script to search for the div and then find and replace text inside that div.
Here is what I have so far:
var els = document.getElementsByTagName("*");
for(var i = 0, l = els.length; i < l; i++)
{
var el = els[i];
el.innerHTML = el.innerHTML.replace(/EGN1935: 5091, Summer B 2011/gi, 'Success');
el.innerHTML = el.innerHTML.replace(/EGN1935: 5088, Summer B 2011/gi, 'Chemistry');
}
The script works but I fear that it delays the loading time.
Yes, Greasemonkey can do this. (Even Stylish can do this in a limited way with CSS content.)
There must be zillions of scripts that do this at userscripts.org.
See also, related SO questions like:
Greasemonkey script in Firefox 4, want to change one line of code on webpage
Use Greasemonkey to remove table
Find and replace in a webpage using javascript.
You need to post details of what the page is/should-be, before and after.
More specific answer based on update(s) from OP:
Speed up your code by focusing on the kinds of elements you want, AMAP, instead of a fetching every element.
Code like so, should work. :
var TargLinks = document.querySelectorAll ('div#siteLinkList ul li a');
for (var J = TargLinks.length - 1; J >= 0; --J)
{
/*--- Does "EGN1935: 5088, Summer B 2011" only appear in the text of
the link or in the href?
The first block will be more efficient if it works, otherwise use
the 2nd block.
*/
var el = TargLinks[J];
el.textContent = el.textContent.replace (/EGN1935: 5091, Summer B 2011/gi, 'Success');
el.textContent = el.textContent.replace (/EGN1935: 5088, Summer B 2011/gi, 'Chemistry');
/* Only use this block if the first block did not work.
el.innerHTML = el.innerHTML.replace(/EGN1935: 5091, Summer B 2011/gi, 'Success');
el.innerHTML = el.innerHTML.replace(/EGN1935: 5088, Summer B 2011/gi, 'Chemistry');
*/
}
You can do this with Firebug - http://getfirebug.com/. Once you install it, activate it by clicking the bug looking icon on the page you want to edit. A view of the HTML document tree will appear, and you can click arrows to drill further down. Alternatively, you can use the pointer icon inside Firebug to select any HTML element on the page (such as a div with a specific ID).
Once you have the element selected, you can select the text that it contains and edit it as you like.
You can edit a ton of other things with this plugin, but it's important to know that once you reload the page your edits will go away.

Resources