Shoulda-matcher How to validate uniqueness of enum attribute?
Asked Answered
L

1

6

I use rspec-rails with shoulda-matcher to test my model. Here is the code:

user_ticket.rb

class UserTicket < ActiveRecord::Base
  belongs_to :user
  belongs_to :ticket

  enum relation_type: %w( creator supporter )

  validates_uniqueness_of :relation_type, scope: [:user_id, :ticket_id]
end

user_ticket_spec.rb

RSpec.describe UserTicket, type: :model do
  subject { FactoryGirl.build(:user_ticket) }

  describe 'Relations' do
    it { should belong_to(:user) }
    it { should belong_to(:ticket) }
  end

  describe 'Validations' do
    it { should define_enum_for(:relation_type).with(%w( creator supporter )) }
    # PROBLEM HERE
    it { should validate_uniqueness_of(:relation_type).case_insensitive.scoped_to([:user_id, :ticket_id]) }
  end
end

When I run the test case the result is always:

Failure/Error: it { should validate_uniqueness_of(:relation_type).case_insensitive.scoped_to([:user_id, :ticket_id]) }

     ArgumentError:
       'CREATOR' is not a valid relation_type

I just think shoulda matcher wants to validate the uniqueness with some kinds of relation_type values: uppercase, lowercase,..etc. My question is in this situation, how to make the test pass with such of defined model validations?

Lingam answered 5/9, 2016 at 7:47 Comment(0)
F
16

It's failing because you're asking it to test validation case insensitively. Typically this would be used to test a range of values with different cases cause validation to fail. However, you're not even allowed to set the value because of the enum; it doesn't even get to the validation check.

It is testing the validation with "creator" and "CREATOR" (at least). enums are case sensitive so these would be two different values in the enum and you've only declared "creator". When it tries to assign "CREATOR" to test the validation your enum gets upset and refuses to allow it.

You may want to validate the uniqueness without case sensitivity in which case you want:

validate_uniqueness_of(:relation_type).ignoring_case_sensitivity

From the validates_uniqueness_of docs:

By default, validate_uniqueness_of will check that the validation is case sensitive: it asserts that uniquable attributes pass validation when their values are in a different case than corresponding attributes in the pre-existing record.

Use ignoring_case_sensitivity to skip this check.

Or you might want to skip the uniqueness checks in your test altogether and trust that rails only allows unique values in an enum.

Farant answered 5/9, 2016 at 8:38 Comment(2)
about: "skip the uniqueness checks", what if we need to use scope, validates_uniqueness_of :type, scope: :user_id, unfortunately this check is not working in this case: it { is_expected.to validate_uniqueness_of(:type).scoped_to(:user_id) }. So need to extend shoulda or write the test manuallyInspectorate
Seems legit github.com/thoughtbot/shoulda-matchers/issues/997Rondo

© 2022 - 2024 — McMap. All rights reserved.