This has been causing some frustration recently...
It seems that using Factories in my cucumber tests, in some situations causes AssociationTypeMismatch errors such as:
MyModel(#65776650) expected, got MyModel(#28190030) (ActiveRecord::AssociationTypeMismatch)
These seem to happen when there is an association reference - as if the Factory created object is different to the real one. See this question for more details: Cucumber duplicate class problem: AssociationTypeMismatch
I have been gradually changing Factory calls to real Model.create or mock_model calls. It would be nice to keep using Factory girl... I wonder if there is something I may have done wrong?
Thank you
I had this happening with me on Rails 3.1.0 rc5, and got it working.
To expand on Jonas' answer.
You should change your Gemfile to be like this:
gem 'factory_girl', '~> 2.0.0', :require => false
gem 'factory_girl_rails', '~> 1.1.0', :require => false
And then if you are using Spork, make your spec/spec_helper.rb file look like this:
Spork.each_run do
require 'factory_girl'
require 'factory_girl_rails'
end
It seems to happen if ActiveSupport unloads and reloads a constant that you have a reference to.
I've experienced the same with Rspec/Capybara, and what helped was a mixture of different things:
Make sure you have cached_classes set to false in your test environment (config/environments/test.rb)
In your gemspec, try replacing require 'factory_girl_rails' with 'factory_girl'
I'm using Spork (a test server), which seems to make this stuff increasingly difficult.
If you are using a test server, evaluate whether you should put ', :require => false' after factory_girl in your gemspec.
The topic is also covered in this google groups thread
Please let us know if any of this helped.
If you're using Spork, make sure to reload your factories after reloading your models.
E.g.
Spork.each_run
if Spork.using_spork?
print "Reloading models ... "
ActiveSupport::Dependencies.clear
puts "done"
print "Reloading factories ... "
FactoryGirl.reload
puts "done"
end
end
This happens because cache_classes is false, as is required by Spork. Capybara reloads Rails classes for every request (or, to be correct, Rails' reloader middleware does, which is not called for normal tests), and this freaks out the factories (exactly why, I'm not sure). You can either reload them, or simply run your Capybara specs outside of Spork.
So you need two things: to only run Capybara outside of Spork, and to set cache_classes to false only for Spork.
To only run Capybara outside of Spork, I have a Guardfile that runs specs in spec/requests outside of Spork and other specs inside of Spork here:
https://gist.github.com/1731900
Then, in config/environments/test.rb:
config.cache_classes = !ENV['DRB']
Your Capybara specs will be a bit slower, as they need to boot rails, but everything will Just Work.
I had some success with reloading the Factory definitions try something like this:
class Factory
def self.reload_definitions #:nodoc:
self.factories.clear
definition_file_paths.each do |path|
load("#{path}.rb") if File.exists?("#{path}.rb")
if File.directory? path
Dir[File.join(path, '*.rb')].each do |file|
load file
end
end
end
end
end
I ran into this issue when I passed the "class" option to my factory that was inherited by other factories:
factory :draft_resource, :class => Resource do
factory :resource, :parent => :draft_resource do
The only solution I could find was to simply not do this.
I ran into this same issue and spent probably ten hours trying every solution on this thread and everywhere else on the web. I started ripping out huge chunks of code trying to get it as close to another app of mine in which I couldn't reproduce the problem. Finally, I came across some helper functions in my spec_helper file:
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token if defined?(cookies)
end
A sign_in helper intended to work both in controller and request specs. And it does, sort of--just not with spork. When I removed the capybara helpers the issue was resolved:
def sign_in(user)
cookies[:remember_token] = user.remember_token
end
Related
I have the following Cucumber feature testing an input form using typeahead.js:
#javascript
Scenario: Creating a battery using typeahead
When I create a new battery using typeahead
Then I should be on the show battery page
And I should see the battery created message
The test fails on the second step with the following error message:
ActiveRecord::RecordNotFound (ActiveRecord::RecordNotFound)
./features/step_definitions/admin/car_part_steps/battery_steps.rb:37:in `/^I should be on the show battery page$/'
features/admin/creating_car_parts/creating_batteries.feature:20:in `Then I should be on the show battery page'
The relevant step definitions are as follows:
When /^I create a new battery using typeahead$/ do
select_from_typeahead :field => 'battery_manufacturer_typeahead',
:select => #manufacturer.name
fill_in 'Type', :with => '700W'
click_button 'Create Battery'
end
Then /^I should be on the show battery page$/ do
battery = Battery.find_by_type_and_manufacturer_id!('700W', #manufacturer.id)
current_path.should == admin_battery_path(battery)
page.should have_content(battery.type)
end
The select_from_typeahead function is as follows:
def select_from_typeahead(params)
params[:js_field] ||= params[:field]
params[:select_typeahead] ||= params[:select]
fill_in params[:field], :with => params[:select][0, 2]
page.execute_script "$('##{params[:js_field]}').trigger('focus')"
page.execute_script "$('##{params[:js_field]}').trigger('keydown')"
sleep 0.5
page.execute_script "$('.tt-suggestion:contains(\"#{params[:select_typeahead]}\")').trigger('mouseenter').trigger('click')"
end
The problem appears not to have anything to do with the typeahead itself however, as the code works in the browser, and if I add some debug output, I notice that the battery gets saved to the database in the first step when running the test as well, it just mysteriously disappears before the second step runs.
I think it's an issue with database_cleaner, as I know that doesn't play nice with Javascript when set to use transactions, but I've already tried setting it to use truncation instead and disabled transactional fixtures and it still doesn't work.
My features/support/env.rb currently looks like this:
require 'simplecov'
SimpleCov.start 'rails'
require 'cucumber/rails'
Capybara.default_selector = :css
Capybara.javascript_driver = :webkit
ActionController::Base.allow_rescue = false
Cucumber::Rails::World.use_transactional_fixtures = false
DatabaseCleaner.strategy = :truncation
Cucumber::Rails::Database.javascript_strategy = :truncation
My environment is as follows:
rails 4.0.2
cucumber 1.3.10
cucumber-rails 1.4.0
capybara 2.2.0
capybara-webkit 1.1.0
database_cleaner 1.2.0
Am I missing something, is there some other way database_cleaner might still interfere with my test, or is it something else entirely that I haven't thought of?
Any ideas would be very welcome!
I don't think it has to do with Database Cleaner. That wouldn't do cleanup until the end of your scenario. To debug, I highly recommend installing Capybara Screenshot so that you can see exactly what is going on in your page. It provides you the method screenshot_and_open_image, which you can use to pop open an image of what the browser looks like at that exact moment. My guesses are that:
Your jQuery isn't doing what you expect because of timing issues - have you tried longer pauses?
Your transaction isn't committed. Have you looked in test.log to see if the transaction was committed?
Is your form failing validation? Try putting a screenshot_and_open_image at the beginning of your I should be on the show battery page step to see. Another thing I use is a shared step like this, so that I can add screenshots in my scenarios for debugging:
And /^I take a screenshot$/ do
Capybara::Screenshot.screenshot_and_open_image
end
When running our rspec suite of tests
bundle exec rspec spec/
The logs are cluttered with far to many log statements. In particular, the controller specs show things like this multiple times:
{"controller"=>"myController", "action"=>"create"}
I would like to get rid of these but can't find the source. There are no puts statements which match anything like this nor are there any Rails.logger calls. I'm assuming this is a log level issue but I could be wrong. Setting config.log_level in environment/test.rb has no effect.
The current rspec configuration looks like this
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.mock_with :rspec
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
end
config.before(:each) do
DatabaseCleaner.clean
end
config.color_enabled = true
config.tty = true
config.formatter = :documentation # :progress, :html, :textmate
end
Any thoughts on how I might disable these type of logs?
Side note: Gemfile is using 'rails', '3.2.13' and 'rspec-rails', '2.14.0'
In case someone comes across this same thread later on, I found that I had the same problem the author described, however, it came from having the Heroku rails_12factor gem in my Gemfile.
Another user said that the gem was causing double output for them: Double console output?
As soon as I either commented it out or put it in the :production group, all of the verbose SQL output in my console went away.
So just another thing to check if you have the same problem, but the author's solution isn't what fixes it for you.
The issue was not with Rspec after all. Instead Someone had written 'p params' in a controller helper. This question is not really valid due to this.
Relishapp's docs were very useful in uncovering this
https://www.relishapp.com/rspec/rspec-rails/docs
I have all my capybara tests working with my authlogic members area using the default driver, but when i change one test to use selenium driver as it has ajax in it, it gives my theis error :
You must activate the Authlogic::Session::Base.controller with a controller object before creating objects
Things are working with default driver for authlogic so must be something to do with selenium ??
I have include Authlogic::TestCase in my spec_helper and
activate_authlogic
domain.user_sessions.create(user)
in a before each.
Any one help me with this please ?
thanks rick
I posted a cucumber solution here: Log-in through authlogic without having to fill in form every time
For RSpec integration tests it's similar.
In your spec_helper.rb:
require "authlogic/test_case"
RSpec.configure do |config|
...
config.include Authlogic::TestCase
ApplicationController.skip_before_filter :activate_authlogic
config.before(:each, :type => :request) do
activate_authlogic
UserSession.create(User.find_by_email!(email))
end
...
end
Obviously, if your site is not login only you may want to move the two lines in config.before into a before block in your specific test for logged in specs. If you leave as is you can delete the session with UserSession.find.destroy or obviously follow the logout link (if this makes more sense in your spec).
I think the following code will work to activate authlogic:
Authlogic::Session::Base.controller = Authlogic::ControllerAdapters::RailsAdapter.new(self)
Having said that, I prefer defining a step that actually goes to the login form, fills it out, and logs in. It's slower, but I rarely run my entire integration test suite manually, usually the continuous integration server takes care of that.
This work for me (Rails 3.2.1) :
In spec_helper.rb
require 'authlogic/test_case'
include Authlogic::TestCase
In In my controller_specs :
def valid_session
activate_authlogic # run before tests are executed
user = Factory(:user)
UserSession.create(user, true) #create an authlogic session
#user = #controller.current_user
{}
end
# exemple of valid_session utilization in your test:
# valid_session
# user_id = #user.id
#
# or
#
# get :index, {}, valid_session
Enjoy!
When I visit my sign in page in a browser everything works fine.
When I visit my sign in page in an rspec integration/request test, I get the following error:
ActionView::Template::Error:
undefined method `title' for #<#<Class:0x00000007af9180>:0x00000007af32a8>
The title method is used by the view and defined in ApplicationHelper which devise seems to find when using the browser. However, during rspec integration tests, devise is unable to find the helper method.
Is there anything I should be stubbing? It seems wrong to be stubbing in integration tests. Any other ideas?
(This question is not about how to include devise helpers in integration tests. I'm manually filling in the sign in forms to authenticate).
Looks like this issue. (in some cases related to ActiveAdmin https://github.com/gregbell/active_admin/wiki/Use-spork)
Here I found a hack that works for me (REE 1.8.7, Rails 3.1, Capybara, Devise, active_admin).
However, this is not likely to be merged, so I forked spork-rails to here with that patch applied. And as you probably know I can point my Gemfile to that repo:
gem 'spork-rails', :git => "git://github.com/chopmo/spork-rails.git"
Not optimal but it gets the job done for now.
I had a similar problem using Cucumber when I installed devise:
undefined local variable or method `flash_block' for #<#<Class:0x007ffd0a28dae8>:0x007ffd0b2f6d58> (ActionView::Template::Error)
I solved it by including the module in env.rb
Spork.prefork do
include FlashBlockHelper
I hope this helps.
Inside /spec/support create devise.rb with this:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Make sure your spec_helper.rb includes:
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
and that your specs have:
require 'spec_helper'
I've been using spork all day, and most of the time it is a really great.
However, I am often running into a few problems where I need to restart Spork in order for my tests to pass... and now I'm wondering if it's more trouble than it's worth. I am new at ruby, so sometimes I can't predict if the error is due to a refresh problem, or if the error is due to my unfamiliarity with Ruby and Rails.
What do I need to put into Spork.each_run block so that my validations and other things are refreshed so that I don't have to restart the spork server?
Thanks
EDIT: If you can upgrade to Ruby 2.0 this is your best bet. It is fast enough and will let you work in regular way without the need for tools like Spork, Zeus, and ect. And in essence you won't need anything I wrote below.
If you still need some speed bump while developing check out the Fast Rails Commands cast.
Well yes, you want to reload Spork if you changed environment, initializer or spec_helper files (and for that guard-spork is perfect), but not when you updated one of your classes (models) as this would deny the purpose of tools like spork. I had the very same issue: I could delete all methods in a model, and tests would still pass, because Spork hold "old" model class in memory. Restarting Spork was required.
Reason:
Some plugins cause the model code to be preloaded so some work is required to block that from happening.
https://github.com/sporkrb/spork/issues/37
https://github.com/sporkrb/spork/issues/94
You want to prevent model code preloaded, as this will not "reload" them if you make any changes (like with validations).
Solutions:
Depends from gems that are involved. In my case, I had to deal with Devise and FactoryGirl, but in essence, you do it by using Spork.trap_method as described on wiki: https://github.com/sporkrb/spork/wiki/Spork.trap_method-Jujitsu
Additionally you can run spork -d to get a list of files that are preloaded, it may be helpful to track which gems may be involved in causing this issue.
Example:
Rails 3.0.x + Rspec2 + Spork 0.9.0.rcX + Capybara + Devise + FactoryGirl
# spec/spec_helper.rb
Spork.prefork do
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
# set "gem 'factory_girl', :require => false" in Gemfile
require 'factory_girl'
# deal with Devise
require "rails/application"
Spork.trap_method(Rails::Application, :reload_routes!)
require File.dirname(__FILE__) + "/../config/environment.rb"
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
# Devise controller test helpers:
config.include Devise::TestHelpers, :type => :controller
end
end
Spork.each_run do
# deal with factory girl
Factory.definition_file_paths = [File.join(Rails.root, 'spec', 'factories')]
Factory.find_definitions
end
Please note that config.cache_classes = true need to be set to true in test environment, otherwise you may get errors from gems like FactoryGirl.
This made my model tests (specs) run quickly, and "reload" them every time I save a file and fire rspec.
EDIT: If you're running on Ruby 1.9.3 you can try out an interesting alternative: Zeus - https://github.com/burke/zeus
Use Guard to reload Spork when you update your classes Guard::Spork allows to automatically & intelligently start/reload your RSpec/Cucumber Spork server(s).
https://github.com/guard/guard-spork
http://flux88.com/2011/04/using-guard-spork-with-mongoid-devise/
From http://www.rubyinside.com/how-to-rails-3-and-rspec-2-4336.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+RubyInside+%28Ruby+Inside%29 :
A minor snafu will remain, though. If
you update app/models/person.rb, the
change won't take effect in your tests
since Spork has the old Person still
in memory. One way around this is to
edit config/environments/test.rb and
change:
config.cache_classes = true
To:
config.cache_classes = false
With more recent versions of Factory Girl, you don't need to do much. First, add FactoryGirl.reload in Spork.each_run. If you have factories with the class parameter, they should be string.
factory :my_model, class: 'MyModel' do...
instead of
factory :my_model, class: MyModel do...