Accessing nested divs using page object model - page-object-gem

I am having trouble accessing the nested divs.
here is my scenario. I need to access the total in inner div. Can some one please shed some light here.
<div id="RequestSend">
<div class="title">
Requests Sent
</div>
<div class="total">
10
</div>
</div>
<div id="RequestReceived">
<div class="title">
Requests Received
</div>
<div class="total">
20
</div>
</div>
I tried the following, but did not succeed.
Approach 1:
prof.rb
=======
div(:total_count, {:class => 'total'})
div(:request_send, {:id => 'RequestSend'})
prof_spec.rb
=============
page.request_send_element.total_count.should eq 10
Output:
NoMethodError: undefined method `total_count' for #<Selenium::WebDriver::Element:0x....>
Approach 2:
prof.rb
=======
divs(:total_count, {:class => 'total'})
prof_spec.rb
============
total_count[0] # for first
total_count[1] # for second
Please note I am a new user to page object.

Solution 1 - Blocks
The most straightfoward approach would be to use blocks when defining your accessors. This allows you to specify paths to an element - ie allowing you to scope the search to specific elements.
The easiest one is to just chain a bunch of div_element1 methods together:
div(:request_send_total){
div_element(:id => 'RequestSend').div_element(:class => 'total')
}
div(:request_received_total){
div_element(:id => 'RequestReceived').div_element(:class => 'total')
}
Alternatively, if you might need to look for different things in the RequestSend/RequestReceived divs, I would create an accessor specifically for each of those divs. Then the accessor for the total, would call the parent element:
div(:request_send, :id =>'RequestSend')
div(:request_send_total){
request_send_element.div_element(:class => 'total')
}
div(:request_received, :id =>'RequestReceived')
div(:request_received_total){
request_received_element.div_element(:class => 'total')
}
In both cases, your page API would be:
page.request_send_total
#=> 10
page.request_received_total
#=> 20
Solution 2 - Widgets
A more complicated implementation, but nicer page API, would be to use widgets. Basically this is like creating an element type with its own specific methods.
You could create a request widget like:
class Request < PageObject::Elements::Div
def total
div_element(:class => 'total').text
end
end
PageObject.register_widget :request, Request, :div
Your page object, would then use the registered request accessor:
request('request_send', :id => 'RequestSend')
request('request_received', :id => 'RequestReceived')
Finally, you would get the total values as:
page.request_send_element.total
#=> 10
page.request_received_element.total
#=> 20

Related

Sequel Left Join

My aim is to build a relationship between rooms, people and work shift. So my sequel string looks like this :
x = DB[:raum].join_table(:left, DB[:platz], :rid => :id)
.join_table(:left, DB[:patient_behandlungs_link], :platz_id => :id)
.join_table(:left, DB[:patienten], :id => :patienten_id)
.join_table(:left, DB[:behandlungsverfahren], :id => :t2__behandlungsverfahren_id)
.join_table(:left, DB[:dialysezeit], :id => :t2__dialysezeit_id)
.join_table(:left, DB[:nadeln], :id => :t2__dialysenadel_id)
.join_table(:left, DB[:dialysatorzugang], :id => :t2__dialysatorzugang_id)
.where("raumnummer = ?", raumid.to_i)
It's working like this but in the resulting table there is also a field for the shift id. In this state it does not differentiate in which workshift the person is working. if i do a foreach and push the values out I get my empty nil fields with no one inside, which I want to, and I get the people which are in room raumid from all workshifts.
If I make a .filter(:schicht_id => 1) for example, then I loose my nil values. I need them to assign new people to the empty slots, so I tried (:schicht_id => 1).or(:schicht_id => nil) and similar things but I don't get my result, I want
I think i blamed sequel for something that is not related to sequel.
In the image my select box starts showing options from the second value
This behavior made me think, something was wrong with my joins and group by instructions.... i now have to figure out why the select box shows me from values form 2-9 and not from 1-9. In the HTML Site Source code all 9 Options are given.
This is strange for me.
sorry for blaming sequel.

page element definition for cloned rows

I am using the page-object-gem and trying find the best way to define my page elements when a set of text_field have an infinite number of occurrences.
The HTML on page load is similar to the following:
<div><input id="dx_1_code" value=""/> <input id="dx_1_dos" onblur="clone($(this),false)" value=""/></div>
If the user tabs out of the last input then a new row is cloned with id values that increment with HTML like follows:
<div><input id="dx_2_code" value=""/> <input id="dx_2_dos" onblur="clone($(this),false)" value=""/></div>
<div><input id="dx_3_code" value=""/> <input id="dx_3_dos" onblur="clone($(this),false)" value=""/></div>
My first try was to define my class as follows:
class SamplePage
include PageObject
include DataMagic
text_field(:dx_1, :id => "dx_1_code")
text_field(:dx_2, :id => "dx_2_code")
text_field(:dos_1, :id => "dx_1_dos")
text_field(:dos_2, :id => "dx_2_dos")
end
However I quickly ended up with a lot of redundant entries.
Is there a better way to handle an unknown number or entries like this in terms of element setups and use of the populate_page_with method?
The elements are indexed, which makes them a good candidate for the indexed properties feature. The indexed_property lets you define locators where a number is substituted in when accessing the element. The page object would look like:
class MyPage
include PageObject
indexed_property(:dx, [
[:text_field, :code, {id: 'dx_%s_code'}],
[:text_field, :dos, {id: 'dx_%s_dos'}],
])
end
The first two rows would then be inputted using:
page = MyPage.new(browser)
page.dx[1].code = 'a'
page.dx[1].dos = 'b'
page.dx[2].code = 'c'
page.dx[2].dos = 'd'
Unfortunately there is no built-in way for the populate_page_with method to work with indexed properties. As with anything, you could hack in something. The populate_page_with method looks for an "element" method as well as a setter method. By adding your own to the page object, the method could be used.
class MyPage
include PageObject
indexed_property(:dx, [
[:text_field, :code, {id: 'dx_%s_code'}],
[:text_field, :dos, {id: 'dx_%s_dos'}],
])
# Method for inputting the various dx code/dos values based on a Hash
def dx=(values)
values.each_pair do |index, fields|
fields.each_pair do |field, value|
dx[index].send("#{field}=", value)
end
end
end
# This is so that populate_page_with can check that the element is enabled/visible
def dx_element
dx[1].code_element
end
end
This would give you the ability to use populate_page_with by sending a Hash where the keys are the index and the values are the fields/values for that index. The same inputting of the page that we did before can now be written as:
page = MyPage.new(browser)
page.populate_page_with(dx: {
1 => {code: 'a', dos: 'b'},
2 => {code: 'c', dos: 'd'}
})

How to pass a value to the index during runtime for the indexed_property?

I have multiple sets of select_list and check boxes with the same properties. While I can differentiate them using index => 0, index => 1 and so on, is there a way to achieve this using an indexed_property?
When I tried:
indexed_property(:my_index_prop,
[[:select_list, :my_select, {:name => 'my_select',:index => '%d'}],
[:checkbox, :my_check, {:name => 'my_check',:index => '%d'}]]
)
It resulted in the error 'expected fixnum got string "0"'.
If indexed_property cannot be used, is there a way to pass the index during runtime and identify an element? For example:
for cnt in 0 .. 6
# identify element using index
end
The problem is that the Page-Object is sending the :index value as a String when Watir-WebDriver requires the :index value to be a number.
Solution 1 - Use Element Collections
Given that you are only using the indexed property to specify the :index locator, you could define element collections instead.
Assuming that your page is something like:
<html>
<body>
<select name="my_select" id="0"></select>
<input name="my_check" id="a" type="checkbox">
<select name="my_select" id="1"></select>
<input name="my_check" id="b" type="checkbox">
<select name="my_select" id="2"></select>
<input name="my_check" id="c" type="checkbox">
</body>
</html>
You could define the page object as:
class MyPage
include PageObject
select_lists(:my_index_prop_select_list, :name => 'my_select')
checkboxes(:my_index_prop_checkbox, :name => 'my_check')
end
The two element collections are arrays, meaning you can specify the index by using the [] method:
page = MyPage.new(browser)
p page.my_index_prop_select_list_elements[1].attribute('id')
#=> "1"
p page.my_index_prop_checkbox_elements[1].attribute('id')
#=> "b"
The problem with this solution is that you do not get the benefit of the different accessor methods.
Solution 2 - Use XPath
Another option would be to use the :xpath locator with the indexed_property:
class MyPage
include PageObject
indexed_property(:my_index_prop, [
[:select_list, :my_select, {:xpath => '//select[#name="my_select"][%s + 1]'}],
[:checkbox, :my_check, {:xpath => '//input[#type="checkbox"][#name="my_check"][%s + 1]'}]
])
end
The benefit of this is that you get the usual accessor methods created:
page = MyPage.new(browser)
p page.my_index_prop[1].my_select_element.attribute('id')
#=> "1"
p page.my_index_prop[1].my_check_element.attribute('id')
#=> "b"
page.my_index_prop[1].check_my_check
p page.my_index_prop[1].my_check_checked?
#=> true
The disadvantage here is that you have to write XPaths, which is not a big deal when it is simple.
Solution 3 - Modify Page-Object
Lastly, you could modify the Page-Object gem to turn the :index into a number before passing it to Watir. This can be done by adding the monkey-patch:
class PageObject::IndexedProperties::RowOfElements
def initialize (browser, index, identifier_list)
initialize_browser(browser)
identifier_list.each do |identifier|
type = identifier[0]
name = identifier[1]
how_and_what = identifier[2].clone # Cannot modify the original...
how_and_what.each do |key, value|
if key == :index
how_and_what[key] = (value % index).to_i
else
how_and_what[key] = value % index
end
end
self.class.send type, name, how_and_what unless self.class.instance_methods.include? name
end
end
end
This would allow the page object to be defined as expected:
class MyPage
include PageObject
indexed_property(:my_index_prop, [
[:select_list, :my_select, {:name => 'my_select', :index => '%d'}],
[:checkbox, :my_check, {:name => 'my_check', :index => '%d'}]
])
end
Which is used the same as the prior solution:
page = MyPage.new(browser)
p page.my_index_prop[1].my_select_element.attribute('id')
#=> "1"
p page.my_index_prop[1].my_check_element.attribute('id')
#=> "b"
page.my_index_prop[1].check_my_check
p page.my_index_prop[1].my_check_checked?
#=> true
The disadvantage of course is that you have to patch the Page-Object gem. Though you could request the change be made to the project.

Neo4j::Rails::Model to_json - node id is missing

I have a Jruby on Rails application with Neo4j.rb and a model, let's say Auth, defined like this:
class Auth < Neo4j::Rails::Model
property :uid, :type => String, :index => :exact
property :provider, :type => String, :index => :exact
property :email, :type => String, :index => :exact
end
And this code:
a = Auth.find :uid => 324, :provider => 'twitter'
# a now represents a node
a.to_json
# outputs: {"auth":{"uid": "324", "provider": "twitter", "email": "email#example.com"}}
Notice that the ID of the node is missing from the JSON representation. I have a RESTful API within my application and I need the id to perform DELETE and UPDATE actions.
I tried this to see if it works:
a.to_json :only => [:id]
But it returns an empty JSON {}.
Is there any way I can get the ID of the node in the JSON representation without rewriting the whole to_json method?
Update The same problems applies also to the to_xml method.
Thank you!
I am answering my own question. I still think that there is a better way to do this, but, for now, I am using the following hack:
In /config/initializers/neo4j_json_hack.rb I put the following code:
class Neo4j::Rails::Model
def as_json(options={})
repr = super options
repr.merge! '_nodeId' => self.id if self.persisted?
end
end
And now every JSON representations of my persisted Neo4j::Rails::Model objects have a _nodeId parameter.
The ID is typically not included because it shouldn't be exposed outside the Neo4j database. Neo4j doesn't guarantee that the ID will be identical from instance to instance, and it wouldn't surprise me if the ID changed in a distributed, enterprise installation of Neo4j.
You should create your own ID (GUID?), save it as a property on the node, index it, and use that to reference your nodes. Don't expose the Neo4j ID to your users or application, and definitely don't rely on it beyond a single request (e.g. don't save a reference to it in another database or use it to test for equality).

What's the right way to define an anchor tag in rails?

It's obvious from the documentation (and google) how to generate a link with a segment e.g. podcast/5#comments. You just pass a value for :anchor to link_to.
My concern is about the much simpler task of generating the <a name="comments">Comments</a> tag i.e. the destination of the first link.
I've tried the following, and although they seemed to work, the markup was not what I expected:
link_to "Comments", :name => "comments"
link_to "Comments", :anchor => "comments"
I think I'm missing something obvious. Thanks.
You are getting confused by Ruby's syntactic sugar (which Rails uses profusely). Let me explain this briefly before answering your question.
When a ruby function takes a single parameter that is a hash:
def foo(options)
#options is a hash with parameters inside
end
You can 'forget' to put the parenthesis/brackets, and call it like this:
foo :param => value, :param2 => value
Ruby will fill out the blanks and understand that what you are trying to accomplish is this:
foo({:param => value, :param2 => value})
Now, to your question: link_to takes two optional hashes - one is called options and the other html_options. You can imagine it defined like this (this is an approximation, it is much more complex)
def link_to(name, options, html_options)
...
end
Now, if you invoke it this way:
link_to 'Comments', :name => 'Comments'
Ruby will get a little confused. It will try to "fill out the blanks" for you, but incorrectly:
link_to('Comments', {:name => 'Comments'}, {}) # incorrect
It will think that name => 'Comments' part belongs to options, not to html_options!
You have to help ruby by filling up the blanks yourself. Put all the parenthesis in place and it will behave as expected:
link_to('Comments', {}, {:name => 'Comments'}) # correct
You can actually remove the last set of brackets if you want:
link_to("Comments", {}, :name => "comments") # also correct
In order to use html_options, you must leave the first set of brackets, though. For example, you will need to do this for a link with confirmation message and name:
link_to("Comments", {:confirm => 'Sure?'}, :name => "comments")
Other rails helpers have a similar construction (i.e. form_for, collection_select) so you should learn this technique. In doubt, just add all the parenthesis.
If you want to go through rails, I suggest content_tag (docs).
Example:
content_tag(:a, 'Comments', :name => 'comments')
<%= link_to('new button', action: 'login' , class: "text-center") %>
created an anchor tag for login.html i.g
new button
and for
new button
use
<%= link_to('new button', controller: 'admin',
action: 'login' , class: "text-center") %>