Rails 7 Custom validation breaks rspec model validations tests

I'm having a little trouble with one of my model specs. I recenttly added a custom validation to the model and now model_spec breaks in one of the validations. Here is my model target.rb:

class Target < ApplicationRecord
  validate :targets_count, on: :create #custom validation
  validates :title, presence: true
  validates :radius, presence: true, numericality: { greater_than: 0 }
  validates :lat, :lon, presence: true, numericality: true
  belongs_to :user
  belongs_to :topic

  def targets_count
    return unless user.targets.count >= 3

    errors.add(:base, "You can't create more than 3 targets")
  end
end

And here is the spec:

require 'rails_helper'

RSpec.describe Target, type: :model do
  describe 'validations' do
    subject { build :target }
    it { is_expected.to validate_presence_of(:title) }
    it { is_expected.to validate_presence_of(:radius) }
    it { is_expected.to validate_presence_of(:lat) }
    it { is_expected.to validate_presence_of(:lon) }
    it { is_expected.to belong_to(:user) }
    it { is_expected.to belong_to(:topic) }
    it { is_expected.to validate_numericality_of(:radius).is_greater_than(0) }
    it { is_expected.to validate_numericality_of(:lat) }
    it { is_expected.to validate_numericality_of(:lon) }
  end
end

Every test pass except this one:

it { is_expected.to belong_to(:user) }

And the console returns this error message:

 Target validations is expected to belong to user required: true
     Failure/Error: return unless user.targets.count >= 3

     NoMethodError:
       undefined method `targets' for nil:NilClass

           return unless user.targets.count >= 3
                             ^^^^^^^^
     # ./app/models/target.rb:29:in `targets_count'
     # ./spec/models/target_spec.rb:30:in `block (3 levels) in <top (required)>'

If I comment out the custom validation then every test pass.

I'm using FactoryBot and here are the factories for targets and users

FactoryBot.define do
  factory :target do
    title { Faker::Name.name }
    radius { Faker::Number.between(from: 1.0, to: 600_000.0).round(2) }
    lat { Faker::Address.latitude }
    lon { Faker::Address.longitude }
    association :user, factory: :user
    association :topic, factory: :topic
  end
end
FactoryBot.define do
  factory :user do
    email      { Faker::Internet.unique.email }
    password   { Faker::Internet.password(min_length: 8) }
    username   { Faker::Internet.unique.user_name }
    first_name { Faker::Name.unique.name }
    last_name  { Faker::Name.unique.last_name }
    uid        { Faker::Internet.uuid }
  end
end

Any help will be much appreciated!!!

Upvotes: 0

Views: 367

Answers (1)

spickermann
spickermann

Reputation: 107117

To test this line

it { is_expected.to belong_to(:user) }

RSpec needs checks what happens if there is no user assigned.

But when there is no user assigned, then this line

return unless user.targets.count >= 3

raises an error because it calls targets on nil.

I would argue that the targets_count validation is not required if there is no user assigned yet. Therefore I would fix this issue by changing that method to

def targets_count
  return unless user
  return unless user.targets.count >= 3

  errors.add(:base, "You can't create more than 3 targets")
end

Upvotes: 0

Related Questions