Watir, Page-objects: how to get all elements that have the same identifier - webdriver

I have the following code code on my page I wanna check:
...
<p class="tags-link">
test1
test2
test3
</p>
....
<p class="tags-link">
test4
test5
test6
</p>
....
I use Watir-webdriver and page-object. And I need to get all links related to blocks with "tags-link" class.
I have the following code:
element(:tags, :p, :css => "tags-link a")
tags_element returns the 1st link only.
The following code will give me just 3 links related to the 1st block:
element(:tags, :p, :css => "tags-link")
tags_element.element.links.each do |elm|
puts elm
end
But I need to get all tags blocks
Now I have the following code that works, but I wanna be "page-object" oriented :
#browser.elements(:css =>".tags-link a").each do |tag|
puts tag
end
Could you please help me...to get all links on the page related to "tags-link" using page-objects
Thanks,
Anna

You can define a collection of links in your page object using links:
class MyPage
include PageObject
links(:tag_link, :css =>".tags-link a")
end
This will create a collection_name_elements method that returns an array of matching page-object elements. You can iterate over it to perform an action on each element. For example, to output the text of each link:
page.tag_link_elements.each do |link|
puts link.text
end
#=> test1
#=> test2
#=> test3
#=> test4
#=> test5
#=> test6

This is all you need to do:
ary_of_tests = #browser.ps(:class, 'tag-links').map do |t|
t.as.map do |x|
x.text
end
end
=> [["test1", "test2", "test3"], ["test4", "test5", "test6"]]
If you do not like dynamic arrays you can always use the flatten method to make it one dimensional or to_s method to make it into a string. Defining a new class and specifying scenarios seems like overkill to me, but to each his own.
Note: ps(:class, 'tag-links) is a collection of all p elements with attribute class and value tag-links in the DOM of a given page.

Related

Scrapy chain selector with different parents

I want to chain two selectors together that have different parents. The selector I'm using currently:
..css('td:nth-child(8) > span.cap.mtv > ::text')
Which yields:
<Selector xpath="descendant-or-self::td[count(preceding-sibling::*) = 7]/span[#class and contains(concat(' ', normalize-space(#class), ' '), ' cap ') and (#class and contains(concat(' ', normalize-space(#class), ' '), ' mtv '))]/*/text()" data='$725,000'>
The issue I have is that I also want the following:
..xpath('td[8]/div/text()')
Which yields:
<Selector xpath='td[8]/div/text()' data='UFA'>
Ultimately I want to use an item loader and extract to get:
$725,000
UFA
...
I want to achieve something similar to the following..
...xpath('td[8]').css('span.cap.mtv > ::text').xpath('/div/text()')
I have previously just sort of re-scraped an element w/ another set of selectors if the program had previously found nothing but would much rather have this sort of 'either/or' flexibility. Or would I be better of looking at another selector all together for this situation?
Any help is much appreciated!
If you're using item loaders, you can simply add multiple selectors for a single field as shown in scrapy docs.
Something like this should work, after creating a loader:
loader.add_css('field', 'td:nth-child(8) > span.cap.mtv > ::text')
loader.add_xpath('field', 'td[8]/div/text()')
Your input/output processors would then be responsible for how this information is combined.

Rails conditional CSS in view helper

I have a simple rails app and I'm trying to write a view helper that does the following.
Compares two values. If the current_month amount is greater than the forecast amount then make the text green. If the current_month amount is less than the forecast amount then make the text red.
I wrote out this simple helper to append text to the output of the the rails method, but I'm unsure of how to inject CSS/styling into this.
def target_hit(forecast, current)
(if current.amount > forecast.amount
number_to_currency(current.amount.to_s) + " Yay"
elsif current.amount < forecast.amount
number_to_currency(current.amount.to_s) + " No dice"
end).html_safe
end
I'm pretty proficient on the backend but when it comes to front-end stuff I'm stumbling a lot. Any help would be greatly appreciated.
example view code
<p class='total'>Current: <%= target_hit(#forecast, #current) %></p>
The rails helper content_tag http://apidock.com/rails/ActionView/Helpers/TagHelper/content_tag, is useful and means you don't have to use html_safe. I try to move all the logic from the views to helpers to make the view easy to read e.g.
def target_hit(current_amt, forecast_amt)
content_tag(:p, "#{number_to_currency(current_amt.to_s)} target_content(current_amt, forecast_amt)", class: "total #{target_class(current_amt, forecast_amt)}")
end
def target_content(current_amt, forecast_amt)
forecast_reached?(current_amt, forecast_amt) ? "Yay" : "No dice"
end
def target_class(current_amt, forecast_amt)
forecast_reached?(current_amt, forecast_amt) ? "green" : "red"
end
def forecast_reached?(current_amt, forecast_amt)
current_amt >= forecast_amt
end
in the view, you just call the helper method
<%= target_hit(#current.amount, #forecast.amount) %>

Apply conditional class in a rails view inside map{} using haml

I am trying to apply a class conditionally to the names associated with a reminder. If there are three persons associated with a reminder - Jay, Jonah and Jamison... and Jonah is the one who acknowledged the reminder, then I want his name to have the class "acknowledge", though I want to display all three names.
%tbody
-reminder.each do |r|
%tr
%td
=r.persons.each.map{|n| n.name{:class=> ("acknowledge" if r.completed_by.id == n.id)} }.join(',')
I tried to apply the class inside the map{} as shown above but get an error saying
syntax error, unexpected =>, expecting '}'
Any help is much appreciated.
%tbody
- reminder.each do |r|
%tr
%td
- r.persons.each do |person|
%span{class: "acknowledge" if person.completed_by.id == n.id}= person.name

Xquery group by on 2 tags

Below is the XML part of my data.
<A>
<a><Type>Fruit</Type><Name>Banana</Name></a>
<a><Type>Fruit</Type><Name>Orange</Name></a>
<a><Type>Fruit</Type><Name>Apple</Name></a>
<a><Type>Fruit</Type><Name>Lemon</Name></a>
<a><Type>Cars</Type><Name>Toyota</Name></a>
<a><Type>Cars</Type><Name>Lamborghini</Name></a>
<a><Type>Cars</Type><Name>Renault</Name></a>
</A>
Out put as -
<a>Fruits-Banana,Orange,Apple,Lemon</a>
<a>Cars-Toyota,Lamborghini,Renault</a>
I tried to get the required output by all in vain. I tried 'group by` clause too, but getting errors.
any help?
let $x:=
<A>
<a><Type>Fruit</Type><Name>Banana</Name></a>
<a><Type>Fruit</Type><Name>Orange</Name></a>
<a><Type>Fruit</Type><Name>Apple</Name></a>
<a><Type>Fruit</Type><Name>Lemon</Name></a>
<a><Type>Cars</Type><Name>Toyota</Name></a>
<a><Type>Cars</Type><Name>Lamborghini</Name></a>
<a><Type>Cars</Type><Name>Renault</Name></a>
</A>
for $z in distinct-values($x//a/Type)
let $c := $x//a[Type=$z]/Name
return
<a>{concat($z, "-", string-join($c, ","))}</a>
First for is taking the distinct values of the tag Type, then for each distinct value of this, the respective values of all the Name tags are derived.
Then using the concat function I have concatenated the Type text with the string generated by string-join, used to add/append the Name and , (comma).
HTH :)

Pyjs / Pyjamas Frame: How to use a button to change the url in a frame

I have a web page that contains two buttons and a frame. Within the frame, a web page is displayed. I am trying to make it so button A shoes url '/AAA' in the frame while button B shoes url '/BBB' in the frame. How the heck can I do that?
Here is what I have:
class ImageButton(SimplePanel):
def __init__(self, image_location):
'''(None, str) -> None'''
SimplePanel.__init__(self)
img = Image(image_location, StyleName='rangler')
img.addClickListener(getattr(self, "onImageClick"))
self.add(img)
def onImageClick(self, sender=None):
pass
#This is where I need help!?
class QAFrame(SimplePanel):
def __init__(self, current_url):
SimplePanel.__init__(self)
frame = Frame(current_url,
Width="200%",
Height="650px")
self.add(frame)
def caption():
style_sheet = HTML("""<link rel='stylesheet' href='about_us.css'>""")
srah_pic = ImageButton("Steve.jpg")
fl_pic = ImageButton("Fraser.jpg")
horizontal = HorizontalPanel()
vertical = VerticalPanel()
vertical.add(srah_pic)
vertical.add(fl_pic)
horizontal.add(vertical)
QAFrame('Fraser_qa.htm')
QAFrame('Steve_qa.htm')
horizontal.add(QAFrame('Steve_qa.htm'))
RootPanel().add(horizontal)
Basically,
You need to .addClickListener to your button and, as a parameter, you want to pass in the handler that will perform your desired task on button click.
The one thing that really confused me was, I could not pass an argument through to my handler. But, the object "sender" is automatically passed in with the handler. You can try to fish through the senders attributes to find information that you need.
class ImageButton(SimplePanel):
def __init__(self, image_location, css_style):
'''(None, str, str) -> None'''
SimplePanel.__init__(self)
self.image_location = image_location
img = Image(self.image_location, StyleName= css_style)
img.addClickListener(Cool) # Cool is the name of my handler function
self.add(img)
def Cool(sender): # You can do whatever you want in your handler function.
# I am changing the url of a frame
# It is a little-medium "Hacky"
if sender.getUrl()[-9:] == 'Steve.jpg':
iframe.setUrl('Fraser_qa.htm')
else:
iframe.setUrl('Steve_qa.htm')
I would extend my ImageButton class to support passing in the URL to the webpage you want to show. In the __init__ function, you can store that URL in an instance property.
You should make the clickhandler into an instance method, which can access the instance variable which holds the URL to the desired page.
I lack the definitive Python knowledge to supply code examples. Hope you still understand the concept.

Resources