Factory Girl Devise user factory is not valid - doesn't pass RSpec test
Asked Answered
J

2

6

I'm new to programming and have been learning Ruby on Rails for about 11 weeks.

When trying to test my user factory for validation, I get

  1) User has a valid factory
     Failure/Error: expect(@user.valid?).to eq(true)

       expected: true
            got: false

       (compared using ==)

I'm using Devise for my user model, and FactoryGirl for my factories.

Here is my user factory:

FactoryGirl.define do 
  factory :user do
    name "John Fahey"
    sequence(:email, 100) { |n| "person#{n}@example.com" }
    password "password"
    password_confirmation "password"
    confirmed_at Time.now
  end
end

...and here is my spec

require 'rails_helper'

  describe User do 
    before do
      @user = build(:user)
    end

  it "has a valid factory" do
   expect(@user.valid?).to eq(true)
   end 
end

I've been working on getting this spec to pass for a while now. For a while I was getting the "email already taken" error and I've gotten past that. I even got the spec to pass once, but I was using the now deprecated "should be" syntax. When I go to the correct ":expect" syntax I get this error. Does anyone have an idea of what I'm doing wrong here?

Here is my model

class User < ActiveRecord::Base

  #== schema information. 
  # create_table "users", force: true do |t|
  #   t.string   "name"
  #   t.string   "email",                  default: "", null: false
  #   t.string   "encrypted_password",     default: "", null: false
  #   t.string   "reset_password_token"
  #   t.datetime "reset_password_sent_at"
  #   t.datetime "remember_created_at"
  #   t.integer  "sign_in_count",          default: 0,  null: false
  #   t.datetime "current_sign_in_at"
  #   t.datetime "last_sign_in_at"
  #   t.string   "current_sign_in_ip"
  #   t.string   "last_sign_in_ip"
  #   t.string   "confirmation_token"
  #   t.datetime "confirmed_at"
  #   t.datetime "confirmation_sent_at"
  #   t.string   "unconfirmed_email"
  #   t.datetime "created_at"
  #   t.datetime "updated_at"
  # end

  # add_index "users", ["email"], name: "index_users_on_email", unique: true
  # add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true


  has_one :list
  has_many :items, through: :list
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable
end

here is what I see when I create a user instance in the rails console and test for errors:

2.0.0-p576 :004 > @user = User.create
   (0.2ms)  begin transaction
   (0.2ms)  rollback transaction
 => #<User id: nil, name: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_coun
t: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sen
t_at: nil, unconfirmed_email: nil, created_at: nil, updated_at: nil>
2.0.0-p576 :005 > @user.save
   (1.0ms)  begin transaction
   (0.1ms)  rollback transaction
 => false
2.0.0-p576 :006 > puts(@user.errors)
#<ActiveModel::Errors:0xa7cff88>
 => nil
2.0.0-p576 :007 >

When i print the error messages, I get

2.0.0-p576 :007 > puts(@user.errors.messages)
{:email=>["can't be blank"], :password=>["can't be blank"]}
 => nil

here's something interesting. Just to make sure, I did a rake db:migrate, and a rake db:test:prepare. The test passed. Then I did the exact test again, and it failed.

vagrant@rails-dev-box:~/code/blocitoff$ rake db:migrate
vagrant@rails-dev-box:~/code/blocitoff$ rake db:migrate
vagrant@rails-dev-box:~/code/blocitoff$ rake db:test:prepare
vagrant@rails-dev-box:~/code/blocitoff$ rspec spec/models/user_spec.rb
#<ActiveModel::Errors:0xbdf0740>
.

Finished in 0.1764 seconds (files took 8.96 seconds to load)
1 example, 0 failures
vagrant@rails-dev-box:~/code/blocitoff$ rspec spec/models/user_spec.rb
#<ActiveModel::Errors:0xa97066c>
F

Failures:

  1) User has a valid factory
     Failure/Error: expect(@user.valid?).to eq(true)

       expected: true
            got: false

       (compared using ==)
Jujitsu answered 29/11, 2014 at 13:29 Comment(15)
please post app/models/user.rb with validations.Fibrinolysis
Without seeing your model it is tough to say. Debug why it complains within 'has a valid factory', e.g. with: @user.errors before assertion.Winfredwinfrey
Okay, I've updated my question to include my model and schema info.Jujitsu
@Jujitsu try debug as say @blelump, put @user.save;puts(@user.errors) and look in to log/test.log for any occurence. Devise have own validations looks like some of it fail your test.Fibrinolysis
Ok. when I try to debug and create a user instance, the instance doesn't even have a user_id. Isn't rails supposed to automatically generate that?Jujitsu
I added my rails console activity to my question above, btw.Jujitsu
try puts(@user.errors.messages), this should show what kind of error you have. Rails automatically generate id column only if records saved to db.Fibrinolysis
Okay, it says email can't be blank, and password can't be blank. But those are in my factory.Jujitsu
try create with valid attributes @user = User.create(email: "person#[email protected]", password: '11111111') and look on errors again.Fibrinolysis
see my latest edit to the question.Jujitsu
I am pretty sure what your test db already have some records, so with records conflict with new insertions. Try drop db with bundle exec rake db:drop and try again bundle exec rake db:create and bundle exec rake db:migrate. For easy clean db after all test assertions use database_cleanerFibrinolysis
Respond to the errors you're getting in the console test. Provide the missing attributes and then see what it complains about. Or modify your test to output the errors.Slavic
Ok, I did that, ran the test, and it passed. But I ran the test again, and it failed. Its sending out a confirmation email. Is that the problem?Jujitsu
@Jujitsu read my comment about database cleaner. Problem in existing records in your db.Fibrinolysis
Thank you. I had bad syntax in my database cleaner file. Everything works now,Jujitsu
S
3

Your email attribute needs to be unique and you're not cleaning your database between tests, so you're getting on error on second and subsequent executions of your test. See https://relishapp.com/rspec/rspec-rails/docs/transactions to learn about use of transactions in RSpec.

Slavic answered 29/11, 2014 at 14:42 Comment(3)
Well, the problem was, I DID have a database cleaner. However, I had bad syntax in my database cleaner file. didn't capitalize DatabaseCleaner. Instead, has databaseCleaner.Jujitsu
I'm curious: Did you generate a visible error with the databaseCleaner reference?Slavic
No. I was just getting ready to say that I already had a database cleaner. I then checked the file to make sure everythign was in order - and found out that it wasn't. Than you for your help on this, by the way.Jujitsu
G
1

Just to package what Peter said, I was able to solve my problem by adding this setting to my spec_helper.rb.

RSpec.configure do |config|
  config.use_transactional_fixtures = true
end
Gao answered 5/8, 2015 at 19:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.