Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Could not find a valid mapping for #<User ...>" only on second and successive tests

I'm trying to write a request test that asserts that the proper links appear on the application layout depending in whether a user is logged in or out. FWIW, I'm using Devise for the authentication piece.

Here's my spec:

require 'spec_helper' require 'devise/test_helpers'  describe "Layout Links" do   context "the home page" do     context "session controls" do       context "for an authenticated user" do         before do           # I know these should all operate in isolation, but I           # want to make sure the user is explicitly logged out           visit destroy_user_session_path            @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")           @user.confirm!            # I tried adding this per the Devise wiki, but no change           @request.env["devise.mapping"] = Devise.mappings[:user]            # Now log a new user in           visit new_user_session_path           fill_in "Email",    :with => @user.email           fill_in "Password", :with => "Asd123"           click_button "Sign in"           get '/'         end          it "should not have a link to the sign in page" do           response.should_not have_selector(             '#session a',             :href => new_user_session_path           )         end          it "should not have a link to registration page" do           response.should_not have_selector(             '#session a',             :href => new_user_registration_path           )         end          it "should have a link to the edit profile page" do           response.should have_selector(             '#session a',             :content => "My Profile",             :href => edit_user_registration_path           )         end          it "should have a link to sign out page" do           response.should have_selector(             '#session a',             :content => "Logout",             :href => destroy_user_session_path           )         end       end # context "for an authenticated user"     end # context "session controls"   end end 

The first test passes, but the last three all fail with the error

Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")   RuntimeError:     Could not find a valid mapping for #<User id: xxx, ...> 

I've searched through the Devise wiki, Google group and search results for a cause, but all I find are unanswered questions or suggestions to set config.include Devise::TestHelpers, :type => :controller but that only applies to controller tests, not request test.


Update

I've done some more troubleshooting and I can't make heads or tails of what is ultimately triggering the problem. Have a look at the following code.

First, for some context here is the User factory declaration. It works fine in unit tests.

# spec/factories.rb Factory.define :user do |f|   f.email { Faker::Internet.email }   f.email_confirmation { |f| f.email }   f.password "AbcD3fG"   f.password_confirmation "AbcD3fG"   f.remember_me { (Random.new.rand(0..1) == 1) ? true : false } end 

Now, consider the following integration test

# spec/requests/user_links_spec.rb require "spec_helper"  describe "User Links" do   before(:each) do     # This doesn't trigger the problem     # @user = nil      # This doesn't trigger the problem     # @user = User.new      # This doesn't trigger the problem     # @user = User.create(     #   :email => "[email protected]",      #   :email_confirmation => "[email protected]",      #   :password => "asdf1234",      #   :password_confirmation => "asdf1234"     # )      # This doesn't trigger the problem     # @user = User.new     # @user.email = Faker::Internet.email     # @user.email_confirmation = @user.email     # @user.password = "AbcD3fG"     # @user.password_confirmation = "AbcD3fG"     # @user.remember_me = (Random.new.rand(0..1) == 1) ? true : false     # @user.save!      # This triggers the problem!     @user = Factory(:user)      # This doesn't trigger the same problem, but it raises a ActiveRecord::AssociationTypeMismatch error instead. Still no idea why. It was working fine before in other request tests.     # @user = Factory(:brand)   end    context "when using `@user = Factory(:user)` in the setup: " do     2.times do |i|       it "this should pass on the 1st iteration, but not the 2nd (iteration ##{i+1})" do         # This doesn't trigger an error         true.should_not eql(false)       end        it "this should pass on the 1st iteration, but trigger the error that causes all successive test cases to fail (iteration ##{i+1})" do         # Every test case after this will be borken!         get '/'       end        it "this will fail on all iterations (iteration ##{i+1})" do         # This will now trigger an error         true.should_not eql(false)       end     end   end end 

If we comment out or replace the get '/' bit with anything else (or nothing at all), the tests all run fine.

So, I don't know if this is a factory_girl issue (I tend to doubt it since I can use User factories elsewhere w/o issue) or a Devise issue (I started getting these errors after setting up that gem in my application, but I also only had one other request test which did work fine but is now getting that AssociationTypeMismatch error; correlation ≠ causation...) or an RSpec issue or some other weird edge-case gem conflict.

like image 553
Chris Bloom Avatar asked Jun 15 '11 19:06

Chris Bloom


Video Answer


1 Answers

Add this line to your routes.rb

# Devise routes devise_for :users # Or the name of your custom model 
like image 81
Bruno Paulino Avatar answered Oct 21 '22 17:10

Bruno Paulino