Error when checking enum value with shoulda-matchers
Asked Answered
S

2

12

In my device model, I have

enum device_type: { ios: 1 , android: 2 }
validates :device_type, presence: true, inclusion: { in: device_types.keys }

And in my device_spec.rb, I write some tests for this like

describe 'validations' do
  subject { FactoryGirl.build(:device) }

  it { is_expected.to allow_values('ios', 'android').for(:device_type) }
  it { is_expected.to validate_inclusion_of(:device_type).in_array(%w(ios android)) }
  it { is_expected.not_to allow_value('windows').for(:device_type) }
end

When I ran rspec, the test allow_values('ios', 'android') was passed, but the remaining two were failed.

1) Device should ensure inclusion of device_type in ["ios", "android"]

Failure/Error: it { is_expected.to validate_inclusion_of(:device_type).in_array(%w(ios android)) }

 ArgumentError:
   '123456789' is not a valid device_type

2) Device should not allow device_type to be set to "windows"

Failure/Error: it { is_expected.not_to allow_value('windows').for(:device_type) }

 ArgumentError:
   'windows' is not a valid device_type

"It is not a valid device_type" is correct but why are these tests failed?

Searby answered 28/12, 2015 at 15:13 Comment(5)
I have the feeling you left part of the spec out. It looks from the error message that you are trying to create! a device with the type '123456789'. You should try using create without the ! or use build and expect device.valid? to eq false.Zinovievsk
I added the factory part. I use build exactly. And '123456789' is not included in my factory, it is from shoulder-matchersSearby
I am not sure about the is_expected syntax. I would just write the test as :Zinovievsk
shoulda-matchers is considering device_type as a fixnum value (actually, it's an integer in db). didn't find a workaround for that yet. take a look into the source code: github.com/thoughtbot/shoulda-matchers/blob/…Autoicous
More information, but no real solution here: #29780621Habituate
W
4

When you define an attribute as enum, you can just test using Shoulda matchers

it { should define_enum_for(:device_type).with(:ios, :android) }

If you try to assign any other value, ActiveRecord will raise an ArgumentError (is not a valid device_type).

More recent shoulda syntax:

it { should define_enum_for(:device_type).with_values([:ios, :android]) }
Weaponeer answered 18/4, 2019 at 16:49 Comment(1)
This syntax only works if the enums are 0-based. As is, it will fail with something like this: Expected <<method>> to define :device_type as an enum backed by an integer, mapping ‹"ios"› to ‹0› and ‹"android"› to ‹1›. However, :device_type actually maps ‹"ios"› to ‹1› and ‹"android"› to ‹2›.Estheresthesia
J
0

I guess this issue is resolved as it was asked 6 years ago xd. But I'll leave what I think about this. The test is failing because the error comes from the enum who is trying to insert a value that he does not have (windows and 123456789). I understand you want the test to fail and it fails but the test when you ask if its valid it check the validations of the model, and this does not fail because of that.

I thought two different solutions. First one (use regex):

validates :title, format: {with: /^(option1|option2|option3)$/}

that way the validations are going to fail, and it wont be a ArgumentError.

Second one (use raise_error):

expect {...}to raise_error(ArgumentError)

that way what you are looking is not for the validations to be invalid, instead you want the ArgumentError to popup. It is important you send the expect a block (you send a block with {} ) that way it will work.

Hope this helps.

Jahvist answered 19/8, 2022 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.