Using Factory Girl step definitions in Cucumber features (Rails 3) - ruby-on-rails-3

I'm trying to use Cucumber and Factory Girl. The following lines:
Given I am not logged in
And the following user exists:
| login | email | password | confirmation |
| user50 | user50#mydomain.com | secret50 | secret 50 |
....
raises the following error:
Undefined step: "the following user exists:" (Cucumber::Undefined exception)
/home/user/RubymineProjects/project/features/sign_in.feature:9:in `And the following user exists:
You can implement step definitions for undefined steps with these snippets:
And /^the following user exists:$/ do |table|
# table is a Cucumber::Ast::Table
pending # express the regexp above with the code you wish you had
end
'
I've installed factory_girl_rails (even RubyMine's code completion feature works with Factory Girl step ... )
#Gemfile
group :test do
gem "cucumber-rails", ">= 0.3.2"
gem "factory_girl_rails"
end
#features/support/env.rb
require 'factory_girl'
require 'factory_girl/step_definitions'
Any ideas? Thanks
Update: Thanks to #sj26 and #twmills I realized that I forgot to create a :user factory with Factory Girl. Once I created it, everything worked well.

For those people, who trying to use FactoryGirl helpers now:
From FactoryGirl 3.5.0 these step helpers are deprecated and removed in 4.0.0: http://robots.thoughtbot.com/post/25650434584/writing-better-cucumber-scenarios-or-why-were
As of FactoryGirl 3.5.0, using any of FactoryGirl’s generated step
definitions will print out a deprecation warning. We’ll be removing
the step definitions completely in the 4.0.0 release of FactoryGirl in
accordance with SemVer. I imagine the existing code will be extracted
to a gem similar to Cucumber Rails’ training wheels with a nice
warning urging developers not to use the the steps.
So if you want to use FactoryGirl in Cucumber you should use it in your own step definitions.

You need to include your factories first. factory_girl/step_definitions will iterate over your defined factories to define a step for each.
I use this in features/support/factory_girl.rb:
# Require factories...
require 'spec/factories'
# Then define steps based on factories.
require 'factory_girl/step_definitions'

Try this in features/step_definitions/user_steps.rb
Given /^the following user exists:$/ do |users|
users.hashes.each do |user|
Factory(:user,user)
end
end
Although you may want this instead:
Given /^the following users:$/ do |users|
etc..

Ok, I get that ThoughtBot wants us to write better code, but as an upgrade crutch, we can just put this old file in features/step_definitions:
https://raw.github.com/thoughtbot/factory_girl/3.6.x/lib/factory_girl/step_definitions.rb

Related

Database Cleaner Not Cleaning One Cucumber Scenario

So my team is driving out our rails app (a survey and lite electronic record system) using Cucumber, Rspec and all the gems necessary to use these testing frameworks. I am in the process of setting up a Jenkins CI server and wanted to standardize our databases across our testing, development, and staging environments (we ended up choosing MySQL).
Upon switching the testing environment from SQlite to MySQL we discovered a couple of caching-related testing bugs that we resolved by using relative ids instead of hard-coded ones. example:
describe "#instance_method" do
before(:each) do
#survey = FactoryGirl.create(:survey)
#question_1 = FactoryGirl.create(:question)
#question_2 = FactoryGirl.create(:question)
....
end
context "question has no requirements" do
it "should match" do
# below breaks under MySQL (and postgres), but not SQlite
expect { #survey.present_question?(2) }.to be_true
# always works
expect { #survey.present_question?(#question_2.id) }.to be_true
end
end
end
After resolving this one failing spec, I addressed some unrelated ajax issues that have forever plaguing our test suite. Thinking that I finally masted the art of testing, I confidently ran rake. I was met with this unfriendly sight:
Now of course cucumber features/presenting_default_questions.feature rains green when ran in isolation.
Failing Scenario:
#javascript
Feature: Dynamic Presentation of Questions
In order to only answer questions that are relevant considering previously answered questions
As a patient
I want to not be presented questions that illogical given my previously answered question on the survey
Scenario: Answering a question that does not depend on any other questions
Given I have the following questions:
| prompt | datatype | options | parent_id | requirement |
| Do you like cars? | bool | | | |
| Do you like fruit? | bool | | | |
When I visit the patient sign in page
And I fill out the form with the name "Jim Dog", date of birth "1978-03-30", and gender "male"
And I accept the waiver
Then I should see the question "Do you like cars"
When I respond to the boolean question with "Yes"
Then I should see the question "Do you like fruit?"
When I respond to the boolean question with "No"
Given I wait for the ajax request to finish
Then I should be on the results page
Relevant step:
Then(/^I should be on the results page$/) do
# fails under ``rake`` passes when run in isolation
current_path.should == results_survey_path(1)
end
Then(/^I should be on the results page$/) do
# passes in isolation and under ``rake``
current_path.should == results_survey_path(Survey.last.id)
end
Besides from using Capybara.javascript_driver = :webkit, the cucumber / database cleaner config is unmodified from rails g cucumber:install.
It seems like both the failing rspec and cucumber tests suffer from the same sort of indexing problem. While the solution proposed above works, it's super janky and begs the question as to why a simple absolute index doesn't work (after all the database is cleaned between each scenario and feature). Is there something up with my tests? With database_cleaner?
Please let me know if more code would be helpful!
Relavent gem versions:
activemodel (3.2.14)
cucumber (1.3.6)
cucumber-rails (1.3.1)
database_cleaner (1.0.1)
capybara (2.1.0)
capybara-webkit (1.0.0)
mysql2 (0.3.13)
rspec (2.13.0)
The problem seems to be that you are missing the database_cleaner code for your Cucumber scenarios.
You mentioned that you have the database_cleaner code for your RSpec scenarios, but it seems that you're missing something like this for Cucumber's env.rb:
begin
require 'database_cleaner'
require 'database_cleaner/cucumber'
DatabaseCleaner.strategy = :truncation
rescue NameError
raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end
Around do |scenario, block|
DatabaseCleaner.cleaning(&block)
end
Do you have this code in there?

SalesForce databasedotcom gem conflict with ActiveRecord

I encountered strange problem - when Im trying to get User information from SalesForce using databasedotcom gem like this:
owner = client.find("User", deal_from_sf.OwnerId)
I get ActiveRecord error ActiveRecord::RecordNotFound for User, id:0013000000XXXXX
How can I use this method without patching native gem (as I understand alias for find method will help)?
The answer is so simple - read the documentation!!!
The problem obviously was in the namespace which was Global by default and User treated like ActiveRecord model. But one should add just one line to salesforce.yml file:
sobject_module : YourModuleName
and specify module where your salesForce logic lives)
http://rubydoc.info/github/heroku/databasedotcom/master/Databasedotcom/Client#sobject_module-instance_method

factory_girl_rails & Cucumber::undefined

Having a problem with making this work. Seems it has been a problem for others and I think I have followed all of the advice.
I've set up a stripped down rails 3 .0.14 app to just include cucumber-rails & factory_girl_rails but still no go. I expect I am doing something silly!
Running the cuc test below produces the following:
Scenario: test factory-girl # features/users.feature:3
Given the following user exists: # features/users.feature:4
| name | email |
| Brandon | brandon#example.com |
Undefined step: "the following user exists:" (Cucumber::Undefined)
The user factory has been created, of which I am sure, with a bit of 'pp' output.
Would really appreciate any help to get this sorted.
Ross
Set up
env.rb: snippet
require 'pp'
require 'cucumber/rails'
require 'factory_girl_rails'
require 'factory_girl/step_definitions'
features/support/factories.rb:
FactoryGirl.define do
factory :user do
name 'Adam Advertiser'
email 'a#b.com'still
end
end
pp FactoryGirl.create(:user)
Cucumber features/user.feature:
Feature: a
Scenario: test factory-girl
Given the following user exists:
| name | email |
| Brandon | brandon#example.com |
The problem here is that you have to get your factory required before requiring 'factory_girl/step_definitions', because there is meta-programming in step_definitions which needs to know about your factory. You could explicitly require the factories.rb in the env.rb, but that will end up producing a duplicate definition error, as cucumber will re-require factories.rb.
You need to remove the requiring of step_definitions from the env.rb - that will make it happen too early - and put it at the bottom of factories.rb, or else create a wrapper which requires first the factories (which will need to reside somewhere that cucumber doesn't automatically require) and then the step_definitions.

Extend a module in Rails 3

I want to define a function available_translations which lists the translations I have made for my application into the I18n module.
I tried putting the following into the file lib/i18n.rb, but it doesn't work when I try to use it from the rails console:
module I18n
# Return the translations available for this application.
def self.available_translations
languages = []
Dir.glob(Rails.root.to_s + '/config/locales/*.yml') do |filename|
if md = filename.match #^.+/(\w+).yml$#
languages << md[1]
end
end
languages
end
end
Console:
ruby-1.9.2-p290 :003 > require Rails.root.to_s + '/lib/i18n.rb'
=> false
ruby-1.9.2-p290 :004 > I18n.available_translations
NoMethodError: undefined method `available_translations' for I18n:Module
...
Besides solving my concrete problem, I would be very pleased to learn how this whole module thing in Ruby on Rails works because it still confuses me, so I would appreciate links to the docs or source code very much.
Either of these will solve your problem:
move the code to config/initializers/i18n.rb, or
require your file from config/application.rb, or
name your class otherwise (to trigger autoload)
The code in lib/i18n.rb wil not be loaded by autoload since I18n name will be already loaded, so either you load it yourself or change the class name (and file name) so the new name will trigger autoload behavior.
BTW, the I18n.available_locales() method is presented in rails.

Capybara Acceptance DSL with MiniTest::Spec?

The readme for Capybara (see Using Capybara with MiniTest::Spec) says that I can do this if I include the module correctly, but it doesn't give any illustrative examples of how... I've tried including the module like this:
class MiniTest::Spec
include Capybara::DSL
end
... to no avail. I keep getting this error:
<main>': undefined methodfeature' for main:Object (NoMethodError)
How can I get it to work as it's written in the commented-out code?
spec/acceptance/api/reward_terms_spec.rb:
require "#{Dir.pwd}/spec/acceptance/acceptance_helper"
# this syntax works...
describe 'reward terms acceptance test' do
include Capybara::DSL
describe '#index' do
specify {
visit '/reward_terms'
# ...
}
end
end
# this syntax doesn't work...
# feature 'RewardTerms', %q{
# In order to get all reward terms available to me
# As an API client
# I want to list all active RewardTerms
# } do
# background do
# set_api_headers
# end
# scenario 'RewardTerm index' do
# visit '/reward_terms'
# ...
# end
# end
spec/acceptance/acceptance_helper.rb:
ENV["RAILS_ENV"] = "test"
require "#{Dir.pwd}/config/environment"
require 'minitest/autorun'
require 'capybara/rails'
def set_api_headers(device_id = 'abcd1234')
header 'Accept', 'application/json'
header 'X-Device-Id', device_id
end
There is a nice description in this post for how you should make MinitTest::Spec run with capybara. There he basically includes the Capybara::DSL into the base class of all the specs as in
class RequestSpec < MiniTest::Spec
include Rails.application.routes.url_helpers
include Capybara::DSL
end
this works rather nicely in our setup, but of course it does not reopen the MiniTest::Spec.
Here's a simple test_helper rig to run functional & integration tests in Rails using spec syntax. Based on a gist by tenderlove, the article mentioned above re: MiniTest with Capybara, as well as a lot of tinkering & source-poring.
https://gist.github.com/1607879
You should add minitest-rails-capybara gem to the Gemfile and add a word "feature" to the end of description as follows:
feature 'RewardTerms feature', %q{
In order to get all reward terms available to me
As an API client
I want to list all active RewardTerms
} do
background do
set_api_headers
end
scenario 'RewardTerm index' do
visit '/reward_terms'
#...
end
end
The special word "feature" is case incensitive, and can be "browser". You can customize it by adding a line to the test_helper.rb:
MiniTest::Spec.register_spec_type(/FooBar\z/i, Capybara::Rails::TestCase)