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'}
})