Get cucumber datatable in hooks file using Ruby/Watir - ruby

First time here so I'll try to be most readable possible. I have a test in a feature file which uses a datatable for sorting some data as seen below:
Current cucumber test example
Currently I am using scenario.test_steps.map(&:name) to get all the steps (this is necessary because of an integration to an application lifecycle software manager) in an array and this is what I get:
Cucumber steps got in the hooks file
My question is: is it possible to get the datatable information in the Before do |scenario| hook over the hooks file?
Thanks in advance to anyone who helps!

When iterating through scenario.test_steps, each test step has an associated Cucumber::Core::Ast::Step. This contains the step specific information such as the step name, data table, etc. The associated Ast::Step will be the last element of the test step's source:
test_step.source
#=> [
#=> #<Cucumber::Core::Ast::Feature "Feature: Something" (features/something.feature:1)>,
#=> #<Cucumber::Core::Ast::Scenario "Scenario: Only a test" (features/something.feature:3)>,
#=> #<Cucumber::Core::Ast::Step "Given : the fields" (features/something.feature:4)>
#=> ]
To access the Ast::Step multi-line argument, check the multiline_arg. If a data table has been specified, an Ast::DataTable will be returned. Otherwise, an Ast::EmptyMultilineArgument will be returned. You can check if the returned value is a data table by calling data_table?.
As an example, the below would iterate through each test step and output the data table if defined:
Before do |scenario|
scenario.test_steps.each do |test_step|
multiline_arg = test_step.source.last.multiline_arg
puts multiline_arg.raw if multiline_arg.data_table?
end
end

Related

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

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

How to use a table in Cucumber with Ruby to verify data on web form

I am using Cucumber with Ruby and Watir webdriver.
What I am trying to do is verify that data that is pre-populated on a web form matches the data in a table in the features file in Cucumber. I need help in writing the Ruby code in the step definitions file. Here is what I have so far:
Cucumber feature:
Then I will be able to view my information pre-populated from IAM as follows:
|First Name/Given Name |Chimwemwe |
|Last Name/Surname |Rossi |
|Country |USA |
|Address |fdafda |
|City |fdafd |
|State |Louisana |
|Postal Code |99999 |
Then (/^I will be able to view my information pre-populated from IAM.$/) do |table|
information = table.rows_hash
information.each do |entry|
contact_info = entry [0]
if #browser.text_field(:name=>'firstName').verify_contains(contact_info[0])==true
puts "Passed"
else
puts "Failed"
end
end
I am only doing the first row for now until I get it to work. I would like it to eventually iterate through the table.
when I try to run the script all I get is this error: #table is a Cucumber::Core::Ast::DataTable.
I am fairly new to Ruby/Cucumber and this is the most complicated script I have written so far. Any help on how to do this would be really helpful. I know I need an array, but i have been looking at so much of this online, I feel like my brain is going to explode. Thanks.
Unless you have an easy way to map the Cucumber table to the Watir fields, iteration might not be useful. The simplest approach is to directly check that each field under test matches the table.
I am not sure which assertion library you are using, but as an example, the following uses the RSpec Expectations:
Then (/^I will be able to view my information pre-populated from IAM.$/) do |table|
information = table.rows_hash
expect(#browser.text_field(:name=>'firstName').value).to eq(information['First Name/Given Name'])
expect(#browser.text_field(:name=>'lastName').value).to eq(information['Last Name/Surname'])
# etc. for each field
end
Note that the test will fail at the first incorrect field. If you want to assert all of the fields at once, you can retrieve them into a Hash and compare it to the table:
Then (/^I will be able to view my information pre-populated from IAM.$/) do |table|
form_fields = {
'First Name/Given Name' => #browser.text_field(:name=>'firstName').value,
'Last Name/Surname' => #browser.text_field(:name=>'lastName').value
}
expect(form_fields).to eq(table.rows_hash)
end

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

Have Cucumber Step Verify Variable Set By A Page Object In Another Step

I am using Cheezy's PageObject to setup some cucumber tests. I have everything pretty much setup like Jeff Morgan's book "Cucumber & Cheese".
Right now I have a page object "PublishPage" setup that has a method that sets a variable #tag. For example I have in the file publish_page.rb
Class PublishPage
def tag
#some steps left out
#tag = "123"
end
def verify_tag
#some steps left out
#tag.should include "2"
end
end
In the Cucumber steps, for one of the steps i have on_page(PublishPage).tag, and then in another step i have on_page(PublishPage).verify_tag. In my env.rb file I have require 'rspec-expectations'.
The problem is that when I run this code I get an error that says undefined method 'include' for #<PublishPage:xxxxxx>. But if I move the code inside the verify_tag method into the steps everything works except it does not have access to #tag...
This should be as simple as adding
include RSpec::Matchers
to your page object.
The other alternative would be to expose #tag through some method and then in your Cucumber step say something like
on_page(PublishPage).the_displayed_tag.should include("2")
Every time you invoke on_page(PublishPage), it will instantiate a new page object. You are most likely getting the "cannot convert nil to string" error because you are referencing an instance variable from a new object, hence it's value being nil. You should no longer get that error if you instantiate your page object only once, between calling page.tag and page.verify_tag.
Doing things this way will use one instance of your page object, allowing you to persist between step definitions.
When /I publish a tag/ do
#on_page(PublishPage).tag
#publish_page = PublishPage.new #browser
#publish_page.tag
end
Then /I should have my tag/ do
#publish_page.verify_tag
end
Hope this helps!

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