capybara acceptance test - how to select the right element from inspecting the UI - ruby

In this crud test I create a log entry with #notes and will try to update the log by replacing #notes with #updated_notes.
#notes = Faker::Crypto.md5
#updated_notes = Faker::Crypto.sha256
This block of code to create the log entry works. I used within and the id's of divs in the source code with inspect.
it 'User can update manpower log entry' do
# create a new entry
within '#manpower_log_div' do
find('#manpower_log_notes').send_keys(#notes)
click_button "+ Add"
expect(page.has_css?('td', #notes)).to be true
end
Here I try to click the already existing notes on the page, which lets me edit them.
# click the already existing notes to be able to edit them
within '#manpower_log_div' do
find('#inline_edit').click
end
The error received is
Capybara::ElementNotFound:
Unable to find css "#inline_edit"
Inspecting the element gives us this, but notice the id of the object is too specific: data-object_id="11747753". What element can I place in find that I can use every time I run this test?
<span textarea_cols="50" class="inline_textarea_edit inline_editable" data-object_field="notes" data-object_id="11747753" data-object_class="ManpowerLog" data-custom_callback="" id="ManpowerLog-11747753-notes" data-value_required="false">a5c3e556f108fd29b00150ca736c82d6</span>

You can find the element by any valid CSS selector that would match it. In your example you could use class or data attribute - or a combination of both.
find('span.inline_textarea_edit[data-object_field="notes"]').click()

In your code find('#inline_edit') is looking for an element with id inline_edit. As Thomas Walpole mentioned you can find your button using css selector for example by class:
find('.inline_textarea_edit')
or
find('.inline_editable')
or
find('.inline_textarea_edit.inline_editable')
Make sure that class is uniq for that element. If not, you'll need to use something else then class or something else together with class, you need to look for uniq attribute of that element.
Also make sure that your element is within element with ID manpower_log_div as you are using within '#manpower_log_div'
You can find more info about css selectors here: http://www.w3schools.com/cssref/css_selectors.asp

Related

Site_Prism not finding POM elements when page.find used

So I have setup a Capybara, Cucumber project with SitePrism for POM and for the most part it works. When I use:
Then('Find object name') do
expect(#page).to have_object_name
end
it works just fine but when I come to use:
Then('Assign object names text to a variable') do
expect(#page).to have_object_name
valueA = #page.find('object_name').text
end
this doesnt work and throws an error
Unable to find css "object_name" (Capybara::ElementNotFound)
However, if I use:
Then('Assign object names text to a variable') do
expect(#page).to have_object_name
valueA = #page.find(:xpath, 'object_name_XPath').text
end
this works out just fine as well, but this sort of defeats the point of POM as it would greatly increase maintenance.
I assume I must be missing something to get the page.find locate the object_name from my page but I have danced around it and searched high and low but can't seem to figure the problem out.
Help? :)
#page.find takes a CSS selector (by default - it's actually just the Capybara find method), not the name of a SitePrism element.
If #page is a SitePrism::Page or SitePrism::Section object and you have defined elements on it, then you just access that element as a method on #page - See https://github.com/natritmeyer/site_prism#accessing-the-individual-element
#page.object_name

Ruby cucumber automation suite - parameter received as null while iterating

I inherited a test automation suite and while modifying it I am trying to write a function to test similar links which are present in the same web page but in different divs and the tag ids are dynamic.
I have a function defined below which accepts an HTML element and sends an action to the element
def element_do(html_element, html_element_type, html_element_value, action)
#browser.send(html_element.to_sym,html_element_type.to_sym ,html_element_value).send(action)
end
I have a method defined as somemethod and I am trying to call the method in a particular div using the some_element#{i} as below
def multiple_accounts
#num_accts.each do |i|
p "validating for account #{i}"
#page.element_do(:div,:id,"some_element#{i}",somemethod)
end
The issue I am facing is that on second iteration the action parameter is passed as null instead of the somemethod. I am new to ruby automation and I am not sure what exactly is happening. Any help is appreciated
Additional details - based on the questions
1) #num_accts is an array which is got by scanning the text of the webpage and contains account numbers (eg: [56544, 87990])
2) This forms a part of the id for the divs as in "acct#56544". So I am passing the array elements from num_accts to "acct#{i}" referred as 'some_element'
3) 'Somemethod' is a method defined to click on a particular link in the div and verifies a text to confirm that the link redirects to the correct page. The some method works fine when there is only one div.
It is not evident from the question, but my suspicion is that you try to pass the name of the method (which returns null), but instead you call the method. I think your call should be:
#page.element_do(:div,:id,"some_element#{i}",'somemethod')

if page has selector - Capybara

I'm trying to implement a simple piece of logic that says if element exists on page do something`
The issue I am facing is that if the element doesn't exist then the find method provided returns an exception and will fail my test.
(Capybara::ElementNotFound)
so for example I want to do something like:
if page.find(".element")
do something
end
If the element doesn't exist then the test should just carry on as normal.
Is there a way to do this?
Consider using something like this:
if page.has_css?('selector')
do something
end
This method is described here

Getting deprecation warnings when calling methods on elements - Could use some advice

I am getting deprecation warnings pretty frequently when calling methods on page object elements. This signals to me that I may not be using the gem as intended yet. I could use some help, could anyone recommend a better way to handle something like this?
I am working with a page containing a list of divs that each hold a checkbox element. In other words, something like this:
<div class="item-checkbox"><input type="checkbox"></div>
<div class="item-checkbox"><input type="checkbox"></div>
<div class="item-checkbox"><input type="checkbox"></div>
I would like to access a checkbox by index, and then check it when needed. Here is what I currently have:
def select_checkbox(index)
fail "Nothing in list" unless checkboxes.length > 0
checkbox = self.checkboxes[index].checkbox_element
if checkbox.exists?
checkbox.set
else
fail "could not select a checkbox at index #{index} - check that it exists"
end
end
protected
def checkboxes
div_elements(:class=> 'item-checkbox')
end
This works, however I get a deprecation warning on line 5, checkbox.set. Changing it to checkbox.click clears it up. Nevertheless, I am not convinced that I am doing this the "page-object gem" way. Using watir-webdriver, divs gives me an array to work with, and I can accomplish the same thing in a similar way. Has anyone done anything like this using the gem?
What you have above looks fine except the set method does not exist on the CheckBox element. Instead, there are check, uncheck, and checked? methods. I think you can safely change your above method to this:
def select_checkbox(index)
fail "Nothing in list" unless checkboxes
checkbox = self.checkboxes[index].checkbox_element
if checkbox.exists?
checkbox.check
else
fail "could not select a checkbox at index #{index} - check that it exists"
end
end
protected
def checkboxes
div_elements(:class=> 'item-checkbox')
end
Another way to possibly do this is to declare the divs in the class like this:
class MyPage
include PageObject
divs(:checkbox, :class => 'item-checkbox')
def select_checkbox(index)
fail "Nothing in list" unless checkboxes
checkbox_elements[index].checkbox_element.check
end
end
In this case you are still checking to see if there are any checkbox divs on the page. In the second line of the method you will fail if the checkbox does not exist so it takes care of the condition you guarded against.
-Cheezy
You need to use checkbox.check, not checkbox.set.
Here is a similar SO thread for reference:
How to avoid page-object deprecated for checkbox

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

Resources