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.
Add this line to your routes.rb
# Devise routes devise_for :users # Or the name of your custom model
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With