Andrey Deineko
Andrey Deineko

Reputation: 52357

Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError

class User
  #...
  validates :debit_card_status_change_date,
    timeliness: { type: :date, allow_blank: true }
  #...
end

spec:

it { is_expected.to allow_value(nil).for(:debit_card_status_change_date) }
it { is_expected.to allow_value("").for(:debit_card_status_change_date) }
it { is_expected.not_to allow_value("abc").for(:debit_card_status_change_date) }

Why would second and third test fail?

Failure/Error: it { is_expected.to allow_value("").for(:debit_card_status_change_date) }
  Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError:
    Expected Class to be able to set debit_card_status_change_date to "", but got nil instead.

Failure/Error: it { is_expected.not_to allow_value("abc").for(:debit_card_status_change_date) }
  Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError:
    Expected Class to be able to set debit_card_status_change_date to "abc", but got nil instead.

Everything worked before upgrading from rails4.0, rspec 2 and shoulda-matchers 2.x.x to rails 4.2, rspec 3.3.1 and shoulda-matchers 3.0

Upvotes: 0

Views: 697

Answers (1)

Elliot Winkler
Elliot Winkler

Reputation: 2344

Sorry you're having trouble with the latest release.

As of 3.0 another change was made where allow_value will raise an error if the value you're providing to the matcher and the value that the model actually uses when performing the validation aren't the same. In this case, you're attempting to set "" and "abc" on a column that ends up typecasting these values to nil (since it's a date column). These are all fundamentally different values, so the matcher gets confused and doesn't know how to interpret this.

You have two solutions:

  1. Remove the tests for "" and "abc". Since these get converted to nil, you essentially have the same test repeated twice.
  2. If you want to keep these tests anyway, you can add ignore_interference_by_writer to the end (after for), and that will tell the matcher to ignore any value changes.

Upvotes: 1

Related Questions