Can't create a user factory in factory girl when using rspec, devise, guard, and spork - ruby-on-rails-3

I've seen this issue several places, but none of the solutions seem to work.
I have a Rails 3.1 app with the latest versions of guard, spork, factory girl, rspec, and devise.
Whenever I try to create a user factory (the user model is a devise model) then I get this error:
Could not find a valid mapping for #<User...model attributes...>
I'm not sure what the problem is.
I ran rake db:test:prepare. I followed the instructions in this stackoverflow question: "Could not find a valid mapping for #<User ...>" only on second and successive tests
ALso, I attempted the solution in this answer from google groups:
https://groups.google.com/forum/?fromgroups#!topic/plataformatec-devise/StpbEsDCec0[1-25]
And, here's all the relevant code:
Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
require 'capybara/rspec'
guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
watch('config/application.rb')
watch('config/environment.rb')
watch('config/environments/test.rb')
watch(%r{^config/initializers/.+\.rb$})
watch('Gemfile')
watch('Gemfile.lock')
watch('spec/spec_helper.rb') { :rspec }
watch('test/test_helper.rb') { :test_unit }
watch(%r{features/support/}) { :cucumber }
end
guard 'rspec', :version => 2, :cli => '--drb' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara request specs
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
</code>
This is in my spec/factories.rb
FactoryGirl.define do
load "#{Rails.root}/app/models/user.rb"
factory :user, class: User do |user|
email 'owner#example.com'
password '12345678'
password_confirmation '12345678'
companyid 'example_company'
end
end
This is my spec/controllers/api_controller_spec.rb
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = FactoryGirl.create(:user)
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
And I have this at the end of my config/application.rb
ActionDispatch::Callbacks.after do
# Reload the factories
return unless (Rails.env.development? || Rails.env.test?)
unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
I'm really desperate for an answer here because otherwise I won't be able to test my User model (which is the most important model I have).
Feel free to comment and ask any questions.
EDIT: code looked funny in places, so I edited it for clarity
UPDATE:
So I tried simplifying everything to get to the core of the problem, and I'm pretty sure that devise and factory girl don't "like" each other. I'm still getting the exact same error whenever I try and create a user factory.
This is my new setup (I reverted to a previous git commit and I no longer have guard or spork).
My factories.rb is exactly the same as Michael Durant's except I have an extra line:
companyid 'example'
That's just a requirement for my app.
My spec_helper.rb requires rubygems and capybara/rspec and that's it.
And this is my spec/models/user_spec.rb
require 'spec_helper'
describe 'User associations' do
it 'tests creation of user' do
debugger
user = FactoryGirl.create(:user)
User.count.should be(1)
end
end
Also, this is interesting: When I hit that debugger statement and type in
eval User
It shows the mapping of a valid User.
UPDATE:
So, it's not factory girl that's the problem. It's devise.
This is the new api_controller_spec.rb file and it comes up with the same error of not having a valid mapping of the user.
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = User.new
user.email = 'owner#example.com'
user.password = '12345678'
user.password_confirmation = '12345678'
user.company_id = 'company'
user.save
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
THere isn't a problem with any other environment as I can create users fine through the console, while a local server is running, or when the code is pushed up to Heroku. It might be rspec or something else, but I'm just not sure at this point.

I would recommend you simplify things to find the issue. Currently I feel you have too much going on / too many variable factors.
I would recommend the following:
1 Make a new branch. I assume you are using git, if not use it (git init) and make a fork.
2 Remove all the spork and guard stuff. They are helpful in speeding up your tests and running tests in a CI (Continuous Integration), but they are certainly not 'needed' and removing them will help uncover what the real problems are.
3 Set up your user factory correctly. We use this:
FactoryGirl.define do
sequence :email do |n|
"email#{n}#factory.com"
end
factory :user do
email
first_name { 'First' }
last_name { 'Last' }
password { "password" }
password_confirmation { "password" }
association :area
role { 'super_user' }
end
end
4 Set up your spec_help correctly.
We use these requires in our spec_helper.rb:
require 'rubygems'
require 'capybara/rspec'
5 Try to get one user test to pass using spec/models/user_spec.rb, something like:
require 'spec_helper'
describe 'User associations' do
subject { User.new }
it { should validate_presence_of :area }
...

So, the answer had nothing to do with guard, spork, rspec, or factory_girl.
The problem was that I had my devise_for :users routes commented out since I've been doing a huge overhaul of my rails app.
It's always something stupidly simple >.<

Related

Devise & Rspec: User requires account activation in requests spec even after confirmed

I have the following code in my requests spec:
describe 'Poll' do
subject { page }
context 'as system admin' do
let(:user) { Fabricate(:system_admin) }
before { login user}
it 'is accessible' do
visit '/admin/poll'
current_path.should == '/admin/poll'
end
describe 'sending poll' do
it 'sends to all users' do
save_and_open_page
end
end
end
end
The login user doesn't seem to work even if the method seems to be working fine. I tried using login user inside the it 'is accessible' do block and that specs works fine if I do it that way. If I remove it from there and put it in a before block like above. The user doesn't stay signed in. I put in a save_and_open_page to debug and I get this notification in the page:
Your account was not activated yet. If a reset password link was sent to you, use that link to change your password.
I'm using Devise, RSpec, Capybara and Rails 3. I've also set user to confirm! in my Fabrication file. Below is how it looks:
Fabricator(:system_admin) do
first_name { sequence(:first_name) { |n| "Person#{n}"} }
last_name { sequence(:last_name) {|n| "#{n}" } }
email { sequence(:email) { |n| "person_#{n}#example.com"} }
password "foobar"
password_confirmation "foobar"
company_name { sequence(:company_name) { |n| "google#{n}" } }
role "system_admin"
after_create do |user|
user.confirm!
user.create_company
end
end
Question: What could be the problem? How come the user isn't staying logged in and why do I get that message saying that I should activate my account? Isn't user.confirm! enough?
could this be the problem?
Fabricate(:system_admin) != Fabricator(:system_admin)
So if you debug your save_and_open_page and it tells you that the account is not activated it seemes your fabricate is not working properly. have you tried and debug that?
what does your save_and_open_page do? does it try to use the user for something? because I have experienced when defined with a let, if not touched the variable(user in this case) then it does no exist on that context. besides. whats the error when you run the specs like this on it "is acessible"? just says there is no user logged in?
so you can either stub your methods for login(for example if you have method called current_user that gives you the logged in user or something) or instead of using let, instiate like:
user = Fabricate(:system_admin)
but hey there is a lot of good advices here:
http://betterspecs.org/
it seems like your blocks context and describe are too complex. I am also not following this guidelines 100% but I think I should and you too would benefit from this.
let me know if you found out another reason why its not working!
I think before(:each) should resolve the problem
Add this Devise method:
confirmed_at { Time.now }
So your after_create method should looks like:
after_create do |user|
user.confirm!
user.confirmed_at { Time.now }
user.create_company
end

RSpec gives error 'trait not registered: name'

I tried to test my Rails 3 application on Windows with RSpec. I've wrote tests and factories, but can't solve the issues which raise when I run RSpec on command line.
Here is one of the test files:
require 'spec_helper'
describe "SignIns" do
it "can sign in" do
user = FactoryGirl.create(:user)
visit new_user_session_path
fill_in "login", with: user.username
fill_in "password", with: user.password
click_on "sign in"
current_user.username.should == user.username
end
end
And here's the factories.rb:
factory :layout do
name "layout1"
end
factory :club do
sequence(:name) { |i| "Club #{i}" }
contact_name "John Doe"
phone "+358401231234"
email "#{name}#example.com"
association :layout
end
factory :user do
sequence(:username) { |i| "user#{i}" }
password 'password'
email "test#example.com"
club
end
When I try to run RSpec it gives the following error:
trait not registered: name
#C: in 'object'
#.spec/features/sign_in_spec.rb:11:in 'block (2 levels) in (top(required))
What am I doing wrong?
I know this is an old question, but in case anyone else ends up here when searching "Trait not registered":
When using a dependent attribute like how email depends on name in the :club factory from the question, you need to wrap the attribute in curly braces so it gets lazy evaluated:
email {"#{name}#example.com"}
It's a FactoryGirl error, and it seems you're using (at spec/features/sign_in_spec.rb:11) something like :
FactoryGirl.create :user, :name
This will only work if you registered a trait called name for the Factory user, more on traits here
Note that if you just want to override the name of the created user, the syntax is
FactoryGirl.create :user, name: 'THE NAME'
For future readers' reference:
What didn't work -
ArgumentError:
Trait not registered: user_id
FactoryBot.define do
factory :startup do
user_id
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
end
end
How I solved this issue using either of these, when everything seemed to look right:
put empty curly braces after user_id
FactoryBot.define do
factory :startup do
user_id {}
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
end
end
Move user_id below other block-using helpers:
FactoryBot.define do
factory :startup do
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
user_id
end
end
Another late answer. I banged my head awhile because I forgot my model is very new and I didn't migrate the test database. So the attribute in fact did not exist.
i.e. had to run beforehand
rails db:migrate RAILS_ENV=test
In my case, none of the above(below?) answers helped to solve trait not registered error.
This time it was caused by improper order of loading factories. I've moved a file with declared global traits and FactoryBot started to load it in an improper order.
How did I fix it?
Rename it as, "spec/factories/01_factory_traits" and the issue is solved.
Perhaps there is a better way but it works.

Add tests for dependent :destroy in the Relationship model (Chapter 11, Exercise 1 Rails Tutorial, 2nd Ed)

Pretty sure these tests are working correctly. Got them to fail by removing the dependent: :destroy options on the has_many :relationships and has_many :reverse_relationships in user.rb.
Wanted to share what I did in case anyone else is working through Michael Hartl's Rails Tutorial 2nd Edition, Chapter 11 Exercises.
A few questions arose from this exercise (see bottom of this post). If anyone could help, that'd be great.
Chapter 11, Exercise 1:
Add tests for dependent :destroy in the Relationship model (Listing 11.4 and Listing 11.16) by following the example in Listing 10.15.
Here's my test:
spec/models/user_spec.rb
require 'spec_helper'
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar", password_confirmation: "foobar")
end
subject { #user }
[...code omitted...]
describe "relationship associations" do
let(:other_user) { FactoryGirl.create(:user) }
before do
#user.save
#user.follow!(other_user)
other_user.follow!(#user)
end
it "should destroy associated relationships" do
relationships = #user.relationships
#user.destroy
relationships.should be_empty
end
it "should destroy associated reverse relationships" do
reverse_relationships = #user.reverse_relationships
#user.destroy
reverse_relationships.should be_empty
end
end
A couple questions arose from this exercise:
Question 1:
My initial tests were
relationships.should be_nil
reverse_relationships.should be_nil
But, realized an array was still being returned, despite no user existing.
So, when a user doesn't exist and an association method is called, the result is still an array? Is this always true?
Question 2:
I wanted to play around with deleting relationships and reverse_relationships for a user in the rails console.
I tried this
> user = User.first
> user.relationships
# returns a bunch of relationships
> user.relationships.destroy
=> []
> user.relationships
# returns same bunch of relationships
How do I actually destroy the relationships permanently? Seems like good thing to know when exploring in console.
Thanks! I'm still pretty new to Rails
may be you need smt like this
it { should have_many(:relationships).dependent(:destroy) }
I'm a ruby/rails noob too.
Question 1:
Searched rubyonrails.org for has_many and it says
Returns an array of all the associated objects. An empty array is returned if none are found.
On a side note, you can test for both nil and empty:
relationships.present?.should be_false
Question 2:
The user.relationships.destroy requires an :id
user.relationships.destroy '1'
Thanks for posting your code with your question. I only wanted to post this as a comment and not an answer, but it seems I can't yet. Anyway, I just wanted to add a small potential candidate to your tests, but from the other_user's perspective. The test is similar to the follow/unfollow tests, so hopefully it'd not too redundant, but it tests relationships directly and not the followed_users and followers that go through them.
describe "relationship associations" do
...
context "when a follower/followed user is destroyed" do
subject { other_user }
before { user.destroy }
its(:relationships) { should_not include(user) }
its(:reverse_relationships) { should_not include(user) }
end
end
Ruby on Rails Tutorial 2nd Edition.
Exercise 11.5.1 Add tests for destroying relationships associated with a given user.
This code works for me. I've tried to follow the example Listing 10.15.
spec/models/user_spec.rb
require 'spec_helper'
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com", password: "foobar", password_confirmation: "foobar")
end
subject { #user }
.
.
.
.
describe "user relationships associations" do
let (:other_user) { FactoryGirl.create(:user) }
let (:another_user) { FactoryGirl.create(:user) }
before do
#user.save
#user.follow!(other_user)
#user.follow!(another_user)
other_user.follow!(#user)
other_user.follow!(another_user)
another_user.follow!(#user)
another_user.follow!(other_user)
end
its(:followed_users) { should include(other_user) }
its(:followers) { should include(another_user) }
it "should destroy associated followers" do
followers = #user.followers
#user.destroy
followers.each do |follower|
follower.followed_users.should_not include(#user)
end
end
it "should destroy associated followed users" do
followed_users = #user.followed_users
#user.destroy
followed_users.each do |followed_user|
followed_user.followers.should_not include(#user)
end
end
end
end
Re: paul, the relationships array is not constituted by users, so his include() should always be false, so the test always green.
Re: maria, it appears that the followed_users and followers methods won't return a user who doesn't exist, even when if a relationship referencing he or she remains. So this test is never red also.
another solution:
describe "relationships" do
let(:other_user) { FactoryGirl.create(:user) }
before do
#user.save
#user.follow!(other_user)
end
let(:relationship) { #user.relationships.last }
describe "should be destroyed when the followed user is destroyed" do
before { other_user.destroy }
its(:relationships) { should_not include(relationship) }
end
describe "should be destroyed when the following user is destroyed" do
subject { other_user }
before { #user.destroy }
its(:reverse_relationships) { should_not include(relationship) }
end
end
The above answers work, but I figure I would share mine it's shorter.. :D
describe "following" do
let(:other_user) { FactoryGirl.create(:user) }
before do
#user.save
#user.follow!(other_user)
other_user.follow!(#user)
end
it { should be_following(other_user) }
its(:followed_users) { should include(other_user) }
it "should destroy associated followed_users and followers" do
#user.destroy
#user.relationships.present?.should be_false
#user.reverse_relationships.present?.should be_false
expect(other_user.followers).not_to include(#user)
expect(other_user.followed_users).not_to include(#user)
end
.
.
.
.
end
end
P.S you can leave out:
#user.relationships.present?.should be_false
#user.reverse_relationships.present?.should be_false
but I throw it in there for someone who wants to make sure that all associated destroy action is at work.

rspec let method + loop

i am having trouble running my rspec examples in a loop.
describe "GET all providers" do
let(:current_user) { Factory(:user) }
[:twitter, :facebook, :google_oauth2].each do |provider|
before :each do
current_user.confirm!
sign_in current_user
request.env['devise.mapping'] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.add_mock provider, {
:uid => '123456789',
:info => {
:email => current_user.email
}
}
end
it 'should add the authorization' do
get provider # method to create the authorization
authorization = Authorization.where(:provider => request.env["omniauth.auth"][:provider], :uid => request.env["omniauth.auth"][:uid]).first
current_user.authorizations.should include authorization
end
end
end
currently these examples all pass. the problem though is that current_user is a new user instance through each iteration of the loop, despite memoizing the current_user method. so if i add a test for current_user.authorizations.count.should == 3 it fails.
this became less of needing to actually test it, and more understanding why it isnt behaving how i expect. shouldn't let(:current_user) { Factory(:user) } persist the same user instance across all examples?
Here is a gist I came up with that might help you understand let and let!:
https://gist.github.com/3489451
let memoizes the return value within each it example, but executes the block every time it is called for the first time in the example.
For example, if you call current_user the first time in an it example block, the { Factory(:user) } block is executed. Calling current_user a second or any subsequent time within the same it example block does not execute the { Factory(:user) } block; the return value is memoized.

How do I write a Rails 3.1 engine controller test in rspec?

I have written a Rails 3.1 engine with the namespace Posts. Hence, my controllers are found in app/controllers/posts/, my models in app/models/posts, etc. I can test the models just fine. The spec for one model looks like...
module Posts
describe Post do
describe 'Associations' do
it ...
end
... and everything works fine.
However, the specs for the controllers do not work. The Rails engine is mounted at /posts, yet the controller is Posts::PostController. Thus, the tests look for the controller route to be posts/posts.
describe "GET index" do
it "assigns all posts as #posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
which yields...
1) Posts::PostsController GET index assigns all posts as #posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
I've tried all sorts of tricks in the test app's routes file... :namespace, etc, to no avail.
How do I make this work? It seems like it won't, since the engine puts the controller at /posts, yet the namespacing puts the controller at /posts/posts for the purpose of testing.
I'm assuming you're testing your engine with a dummy rails app, like the one that would be generated by enginex.
Your engine should be mounted in the dummy app:
In spec/dummy/config/routes.rb:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
My second assumption is that your engine is isolated:
In lib/posts.rb:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
I don't know if these two assumptions are really required, but that is how my own engine is structured.
The workaround is quite simple, instead of this
get :show, :id => 1
use this
get :show, {:id => 1, :use_route => :posts}
The :posts symbol should be the name of your engine and NOT the path where it is mounted.
This works because the get method parameters are passed straight to ActionDispatch::Routing::RouteSet::Generator#initialize (defined here), which in turn uses #named_route to get the correct route from Rack::Mount::RouteSet#generate (see here and here).
Plunging into the rails internals is fun, but quite time consuming, I would not do this every day ;-) .
HTH
I worked around this issue by overriding the get, post, put, and delete methods that are provided, making it so they always pass use_route as a parameter.
I used Benoit's answer as a basis for this. Thanks buddy!
module ControllerHacks
def get(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "DELETE")
end
private
def process_action(action, parameters = nil, session = nil, flash = nil, method = "GET")
parameters ||= {}
process(action, parameters.merge!(:use_route => :my_engine), session, flash, method)
end
end
RSpec.configure do |c|
c.include ControllerHacks, :type => :controller
end
Use the rspec-rails routes directive:
describe MyEngine::WidgetsController do
routes { MyEngine::Engine.routes }
# Specs can use the engine's routes & named URL helpers
# without any other special code.
end
– RSpec Rails 2.14 official docs.
Based on this answer I chose the following solution:
#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { #routes = UserManager::Engine.routes }
end
The additional benefit is, that you don't need to have the before(:each) block in every controller-spec.
Solution for a problem when you don't have or cannot use isolate_namespace:
module Posts
class Engine < Rails::Engine
end
end
In controller specs, to fix routes:
get :show, {:id => 1, :use_route => :posts_engine}
Rails adds _engine to your app routes if you don't use isolate_namespace.
I'm developing a gem for my company that provides an API for the applications we're running. We're using Rails 3.0.9 still, with latest Rspec-Rails (2.10.1). I was having a similar issue where I had defined routes like so in my Rails engine gem.
match '/companyname/api_name' => 'CompanyName/ApiName/ControllerName#apimethod'
I was getting an error like
ActionController::RoutingError:
No route matches {:controller=>"company_name/api_name/controller_name", :action=>"apimethod"}
It turns out I just needed to redefine my route in underscore case so that RSpec could match it.
match '/companyname/api_name' => 'company_name/api_name/controller_name#apimethod'
I guess Rspec controller tests use a reverse lookup based on underscore case, whereas Rails will setup and interpret the route if you define it in camelcase or underscore case.
It was already mentioned about adding routes { MyEngine::Engine.routes }, although it's possible to specify this for all controller tests:
# spec/support/test_helpers/controller_routes.rb
module TestHelpers
module ControllerRoutes
extend ActiveSupport::Concern
included do
routes { MyEngine::Engine.routes }
end
end
end
and use in rails_helper.rb:
RSpec.configure do |config|
config.include TestHelpers::ControllerRoutes, type: :controller
end