Can a Cucumber feature pass a constant to a step definition? - ruby

I have a library of XPATHs for a site whose XPATHs regularly change. I've written it because instead of going through every feature file and changing the XPATH it sends, I can simply change the value of the variables I have within my .rb library.
Is it possible to pass these constants to step definitions through the .feature file?
Example .feature feature file:
Scenario: I want to test a button
When I go to url "blah"
And I click on the XPATH: XPATH_CONSTANT_VARIABLE
Example .rb step definition:
When /^I click on the XPATH: {I DON'T KNOW WHAT TO PUT HERE}$/ do |path|
#driver.find_element(:xpath, path).click
end
Example XPATH .rb library:
XPATH_CONSTANT_VARIABLE = "//*[#id="blahblah"]/div[1]/div/div[2]/div/div[1]/div/div[5]/div/div/div/div[2]"

Your scenarios are very imperative. I advice you to make them more declarative and don't use (or refer) to XPathes in scenarios. Read:
You're Cuking It Wrong
Imperative vs Declarative Scenarios in User Stories
If you really want to leave your scenarios as they are, you can use:
When /^I click on the XPATH: \w+$/ do |constant|
xpath = Kernel.const_get constant
#driver.find_element(:xpath, xpath).click
end
But putting all constants to global space as you did seems ugly to me. It may be better to put them to YAML file.

Related

Cucumber, how to write this line

I did some selenium-webdriver ruby code. It works, but now I want to use cucumber to take advantage of the html report that looks good with green and red colors. When I started to use some code in the file called custom_steps.rb, it did not work.
Can you please tell me how to write this line in this file:
require 'selenium-cucumber'
# Do Not Remove This File
# Add your custom steps here
# $driver is instance of webdriver use this instance to write your custom code
divs = $driver.find_elements(:xpath,"//div[#class='col-xs-12 check-box-container']/a/div");
How is the code from custom_steps.rb called in .feature file?
It is not called by that file, your step definition interprets meaning from the .feature file.
In your step definition file you need to write regular expressions to match the lines in the .feature file.
Here is an example of the syntax in action from dispora, a large rails app with many cucumber tests https://github.com/diaspora/diaspora/blob/21980681b156bc163c616cf0344bcdf3f3a195db/features/step_definitions/search_steps.rb.
Also see https://github.com/cucumber/cucumber-ruby

Importing CSV as test data in Cucumber?

We are trying to incorporate CSV into Cucumber to get the benefit of CSV files, but when researching online I see no official documentation on this feature but only "Import scenario outline 'examples' from CSV?".
I am not sure if this comes to any conclusions yet. Is it currently any built-in way to use CSV in Cucumber?
If currently there is no built-in way to import CSV, and I have to write the own parsing method, I think my question will be, in the step definition, how do I hook up the variables with the definition in scenario? For example:
Scenario: do something
Given I eat number as <number> cucumbers
and the cucumber is produced at date as <date>
When the cucumber is expired
Then I should have diarrhea
data.csv
number,date
1,2012-01-01
1,2012-11-03
in the steps.rb, if I do:
CSV.foreach("path/to/data.csv") do |row|
...
How to I map row.number`row.date` to the number\date in the feature file?
In order to use the Examples functionality in cucumber I think you'd have to do some significant metaprogramming that would probably reduce the maintainability and readability of your features. I'd probably accomplish this by wrapping you current steps in another step definition like so:
Scenario: do something
Given I load some data
Then expired cucumbers should give me diarrhea
and the define the step definitions
Then 'I load some data' do
#data = []
CSV.foreach("path/to/data.csv", headers: true) do |row|
#data << row
end
end
Then 'expired cucumbers should give me diarrhea' do
#data.each do |row|
step %Q|I eat number as #{row[:number]} cucumbers|
step %Q|the cucumber is produced at date as #{row[:date]}|
step %Q|the cucumber is expired|
setp %Q|I should have diarrhea|
end
end
The only problem with this is that if one scenario fails, it may take an extra debugging step to figure out which one is failing. Since these steps are run, more or less, under the hood. You could do this pretty easily by printing the row to STDOUT from the step definition:
Then 'expired cucumbers should give me diarrhea' do
#data.each do |row|
puts "row", row.inspect
step %Q|I eat number as #{row[:number]} cucumbers|
step %Q|the cucumber is produced at date as #{row[:date]}|
step %Q|the cucumber is expired|
setp %Q|I should have diarrhea|
end
end
That should give you some indication of which row is giving you trouble.
Erata: I understand your desire to be able to maintain a data sheet separate from the features so that someone like a Project Manager can come up with edge cases and then have those run against the behavior of the code. But I'd almost be more willing to allow them to edit the feature on github and allow CI to run those examples they added to the example table rather than do this approach. In either case its probably something good for regression, but probably really painful to develop code against. This type of testing is sort of the aim of http://fitnesse.org/ and that might be a project of inspiration for you.

Generalizing Cucumber/Capybara Tests

I wrote a feature to test the default configuration of my web app using Cucumber and Capybara. Part of the feature looked like this:
And the page has a photo labeled "Device"
And the page has a checkbox labeled "Device"
And I check "Device"
And I submit the form
Then the resulting page has no photo labeled "Device"
It worked great. I want users who have installed and configured the web app on their own servers to be able to run the test to help confirm that their configuration is correct. And "Device" is a string in the default config file that the user can change. It's an element in an array and they can add to or remove from the array when configuring their instance of the app.
Is this a sensible use of the tools or am I abusing Cucumber and/or Capybara? If it's sensible, how would I do it? If it's a bad idea, what tools might I use for this instead, if anything?
Here's how I got it to work. I'm just not sure this is the best way to do it.
For this to work, the feature would have to look more like this:
And the page has at least 3 photos, let us call the last one "third_photo"
In the corresponding step definition, I use an XPath to pull out the corresponding label string for the first photo and assign it to a Hash object stored in a class variable.
And /^I the page has at least (\d*) photos, let us call the last one "([^\"]*)"$/ do |n, name|
if ! defined?(#note)
#note = Hash.new;
end
#note[name] = find(:xpath, '//ol[#id="menu"]/li[' +n+ ']/a').text;
end
Subsequent step definitions can now access the value, whatever it was.
So, another feature might be:
Then I uncheck "third_item"
And the corresponding step definition might be:
Then /I uncheck "([^\"]*)"/ do |item|
uncheck(#note[item])
end
But I don't feel good about it. If nothing else, I imagine there might be a name collision with another instance variable defined outside the step definitions.
It feels like I'm either Doing It Wrong or else I'm Using The Wrong Tool. What is the right way to do this?
Don't know what you are fishing after, but it feels like your tests and implementation are quite tightly coupled. Maybe that's the feeling you are having, that it seems like you are describing your app in tests.
I don't have a good answer to your questions, merely because I don't "understand" it. I would however urge you to try to decouple your tests from your implementation and see if there's any abstraction there waiting to be found.
There's a blog post about using instance variables in step definitions at http://www.cloudspace.com/blog/2010/06/23/using-instance-variables-with-cucumber-steps/.
Commenters talk about the coupling this entails and at least one possible way around it.
In particular, davetron5000 says:
What we do is to not use instance variables at all, but instead
provide a has that shared state can go in. This hash is cleared after
each test run. Not ideal, but it's a bit cleaner than random instance
variables all over the place (and also ensures a reasonably clean
state before each test)

Is there a simpler way to write the following cucumber test?

I'm usisng cucmber to test a php app and it's working quite well actually.
I have a cucmber feature that uses the following step to check for the presence of a link in a page:
Then /^I should see a link that contains "(.+)"$/ do |link|
assert !!(response_body =~
/<a ([\w\.]*="[\w\.]*" )*href="(http:\/\/)?([\w\.\/]*)?(#{link})/m), response_body
end
Now, this works but it's butt ugly and complicated.
Originally I tried using the xpath thing:
response_body.should have_xpath("//a[#href=\"#{link}\"]")
But then if I check for a link to 'blah.com' then it won't match 'http://blah.com" - which kind of defeats the whole purpose of the test. Hence the reason I switched to regex.
So is there a simpler way to write the test which doesn't rely on complicated regular expressions?
Cheers.
EDIT:
After lots of hair-pulling... I did find a less messy way to find images on my page:
response_body.should include(image)
Where the image string is set to something like 'myimage.png' - of course, this will break if the actual text 'myimage.png' is on the page and not the image.
There must be a better way. I was considering Hpricot to see if I can parse the html and pull out the attribute I want to test, then test that with a regex but that all seems so... bloated.
Something like this should work:
response_body.should have_css("a[href*='#{link}']")
See this for details:
http://www.w3.org/TR/css3-selectors/#attribute-substrings
EDIT:
Looks like the equivalent method for webrat is have_selector, so:
response_body.should have_selector("a[href*='#{link}']")
Then /^I should see the image "(.+)"$/ do |image|
response_body.should have_selector("img[src*='#{image}']")
end
Then /^I should see a link that contains "(.+)"$/ do |link|
response_body.should have_selector("a[href*='#{link}']")
end
Thanks AlistairH - your advice worked! :)
I still don't undestand why it's searching html with a css selector syntax but maybe that was just a design choice they guy who wrote it took because it looked easier than regex...? I don't know.

Cucumber: Automatic step file creation?

When i run cucumber it displays the
possible steps that i should define, an example from the RSpec book:
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.001s
You can implement step definitions for undefined steps with these snippets:
Given /^I am not yet playing$/ do
pending
end
When /^I start a new game$/ do
pending
end
Then /^the game should say “Welcome to CodeBreaker”$/ do
pending
end
Then /^the game should say “Enter guess:”$/ do
pending
end
Is there a way that it will automaticly create the step definitions file, so i don't have to
rewrite or copy paste by hand but i can just to customize them to be more generic?
Cucumber doesn't offer this feature. Probably because you would have to tell it where to put the step definitions file, and what to name it.
Like Kevin said, Cucumber would have to know the name of the file to put it in, and there are no good defaults to go with, other than using the same file name as the feature file. And that is something I consider an antipattern: http://wiki.github.com/aslakhellesoy/cucumber/feature-coupled-steps-antipattern
Intellij Idea or RubyIDE does exactly what you are asking for:
Detects missing step definitions
Creates missing step definitions in a new file (you choose the name of the file) or in one of the existing step definition files
Highlights matched step parameters
see http://i48.tinypic.com/10r63o4.gif for a step by step picture
Enjoy
There is a possibility this kind of feature could be useful, but as Kevin says, it doesn't exist at present. But it could also get quite messy, quite quickly.
Maybe you already do this, but there's nothing stopping you cut and pasting the output direct into your text editor, or even piping the output direct to your text editor if you're so inclined. Then at least you're getting pretty much most of the way there, bar creating the file and naming.
try this https://github.com/unxusr/kiwi it auto generate your feature file and make the step definitions file for you and you just fill in the steps with code.
In later version will write the code of the steps and run the test all of that automagically
You can use a work around way to generate steps file
all you have to do is to run the Cucumber on a feature doesn't have defined steps by identify a specific feature as the following command:
1) using path
bundle exec cucumber {PATH}
note path would start with features/....
for example
features/users/login.feature
1) using tags
bundle exec cucumber --tags=#{TAG}
note tag should be above your scenario in the steps file
for example
#TAG
Scenario:
And you will have the suggested steps in the console with pending status

Resources