Search code examples
ruby-on-railsrspecrspec-rails

Passes validation even though column is nil Rspec


Rspec

it "should lastname" do
        valid_params[:lastname]     = nil
        user                        = User.new(valid_params)

        expect(user).to_not be_valid
end

it "should have username" do
        valid_params[:username]     = nil
        user                        = User.new(valid_params)

        expect(user).to_not be_valid
end

Migration file

create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :firstname,          null: false, default: ""
      t.string :lastname,           null: false, default: ""
      t.string :username,           null: false, default: ""
      t.boolean :admin,             default: false

Model I do not have any validations except Devise validations

class User < ApplicationRecord
    after_initialize :set_initial_password
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :validatable

  private
  def set_initial_password
    if !self.firstname.nil? && !self.lastname.nil?
        self.password = self.firstname.downcase + self.lastname.downcase
    end
  end
end

Error

  1) User should have username
     Failure/Error: expect(user).to_not be_valid
       expected #<User id: nil, email: "wynell_daniel@schiller.co", firstname: "Garfield", lastname: "Koepp", username: nil, admin: false, created_at: nil, updated_at: nil> not to be valid

Rspec test does pass for lastname but not for username eventhough they have same conditions.


Solution

  • For a validation to fail first you must have a validation so your model needs the following

    validates :username, presence: true
    

    Models do not validate against the database. They will validate against validation methods in the model. Without the validation your model will be valid but the database will reject it if you have not null restrictions in the DB

    UPDATE response to comments

    What you think is happening is not what is actually happening. There is only one reason why lastname test is passing and that is because user object is invalid. As you have not posted the full test only you can determine why the user object is failing validation in this case.

    To find out what the errors are you should inspect the objects errors. Try the following code (untested but should work fine) and look at the console output for a list of invalid attributes

    it "should lastname" do
            valid_params[:lastname]     = nil
            user                        = User.new(valid_params)
            user.errors.each do |error|
              puts("Err: #{error.inspect}")
            end 
            expect(user).to_not be_valid
    end
    

    Then you will understand what exactly is failing. If lastname is actually failing you will see the reason as blank or invalid for lastname. if lastname does not appear in the output then it is not in error. Should you see lastname in the error list then there is a validation on lastname in devise. I am not at all familiar with devise as I always roll my own authentication logic so perhaps this is something to do with one of the options you have included.

    I can not say this clearly enough. If there is no validation code then it is not possible for a model instance to be invalid.