RSpec gives error 'trait not registered: name' - ruby-on-rails-3

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.

Related

Why is this FactoryGirl-created object visible in the test, but not in the view that is being tested?

I'm using RSpec, FactoryGirl, and PhantomJS.
UPDATE:
I have verified that if I create this item in my spec/support/login_macros.rb login_user method, which I call below, the listing object is available in the view.
This seems like a FactoryGirl issue. Why can I create from a factory in that helper method, but can't inside the test itself? Here is the support method:
module LoginMacros
def login_user(admin = false)
myrepo = FactoryGirl.create(:repository, :myname)
plan = FactoryGirl.create(:plan, name: "Test Multi", listing_limit: 5000, repositories_allowed: 5)
user = FactoryGirl.create(:user)
subscription = FactoryGirl.create(:subscription, user: user, plan: plan)
user.add_repository(myrepo)
listing = FactoryGirl.create(:listing, user: user, repository: myrepo)
visit login_path
fill_in 'Email', :with => user.email
fill_in 'Password', :with => user.password
click_button 'Go'
user
end
I have set transactional_fixtures to false in my spec_helper.rb. Here is my spec:
require "spec_helper"
describe "App Integration" do
let!(:user) { login_user }
let!(:myrepo) { user.repositories.where(name: "myrepo" ).first }
it "lets a user add apps to a listing", js: true do
listing = FactoryGirl.create(:listing, user: user, repository: myrepo)
puts listing.inspect
Capybara::Screenshot.screenshot_and_open_image
end
end
Now here is the problem. See that puts line above? It prints out the object.
But in the screenshot, it's as if the object were never created. Like magic!
And yet, both the User and the Repository objects are visible in the view.
Also, I can go to a different view and see that Listing object. Just not on the main page of my application!
Why would that object be visible in one view and not the other? I'm just doing this on the main page:
<h3><%= Listing.count %></h3>
And it is always, always, always zero. Makes zero sense.
It doesn't look like you're ever calling visit inside of your test, so the page would always be blank. You need to call visit root_path # (or whatever path that heading is on) before saving the screenshot.
let! blocks are invoked before it blocks. Since you're viewing the page in a let! block but creating the listing in the it block, the listing isn't created until after you've viewed the page.

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

Can't create a user factory in factory girl when using rspec, devise, guard, and spork

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 >.<

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.