Skip to content

Commit

Permalink
Adds validations for active model errors
Browse files Browse the repository at this point in the history
Allows asserting that the correct validations were added to a model.
Streamline the testing process for validations and make it easier for developers to understand the purpose of each test case.
  • Loading branch information
DanielaVelasquez committed May 15, 2024
1 parent 2e7dc14 commit c7d35c1
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 1 deletion.
9 changes: 9 additions & 0 deletions activesupport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
* Adds `assert_error`, `assert_no_error`, `assert_valid` and `assert_not_valid` to ensure a model has the right validations
```ruby
assert_error :name, :blank, :user
assert_no_error :name, :blank, :user
assert_valid :name, :blank, :user
assert_not_valid :name, :blank, :user
```

*Daniela Velasquez*

Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activesupport/CHANGELOG.md) for previous changes.
44 changes: 44 additions & 0 deletions activesupport/lib/active_support/testing/assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,50 @@ def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
retval
end

# Assertion that an active model doesn't have an error on a field
#
# assert_no_error :name, :blank, :user
def assert_no_error(attribute, type, obj, msg = nil)
raise ArgumentError.new("#{obj.inspect} does not respond to #errors") unless obj.respond_to?(:errors)
msg = message(msg) {
data = [attribute, type]
"Expected %s to not be %s" % data
}
assert_empty obj.errors.where(attribute, type), msg
end

# Assertion that an active model has a specific error on a field
#
# assert_error :name, :blank, :user
def assert_error(attribute, type, obj, msg = nil)
raise ArgumentError.new("#{obj.inspect} does not respond to #errors") unless obj.respond_to?(:errors)
msg = message(msg) {
data = [attribute, type]
"Expected %s to be %s" % data
}
refute_empty obj.errors.where(attribute, type), msg
end

# Assertion that an active model's attribute is not valid after validation
#
# assert_not_valid :name, :blank, :user
def assert_not_valid(attribute, type, obj, msg = nil)
raise ArgumentError.new("#{obj.inspect} does not respond to #validate") unless obj.respond_to?(:validate)

obj.validate
assert_error(attribute, type, obj, msg)
end

# Assertion that an active model's attribute is valid after validation
#
# assert_valid :name, :blank, :user
def assert_valid(attribute, type, obj, msg = nil)
raise ArgumentError.new("#{obj.inspect} does not respond to #validate") unless obj.respond_to?(:validate)

obj.validate
assert_no_error(attribute, type, obj, msg)
end

private
def _assert_nothing_raised_or_warn(assertion, &block)
assert_nothing_raised(&block)
Expand Down
103 changes: 103 additions & 0 deletions activesupport/test/active_model_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true

require_relative "abstract_unit"
require "active_model"

class ActiveModelTest < ActiveSupport::TestCase
def setup
@active_model = Class.new do
include ActiveModel::Model
include ActiveModel::Attributes

attribute :name, :string
attribute :last_name, :string
validates :name, :last_name, presence: true
end.new
end

test "#assert_no_error asserts active model does not have an error on a field" do
@active_model.name = "name"
@active_model.validate

assert_no_error :name, :blank, @active_model
end

test "#assert_no_error raises ArgumentError with a non-active record" do
error = assert_raises(ArgumentError) do
assert_no_error :name, :blank, Object.new
end

assert_includes error.message, "does not respond to #errors"
end

test "#assert_no_error raises a Minitest::Assertion when validation fails" do
@active_model.validate
error = assert_raises(Minitest::Assertion) do
assert_no_error :name, :blank, @active_model
end
assert_includes error.message, "Expected name to not be blank"
end

test "#assert_error asserts active model has an error on a field" do
@active_model.validate
assert_error :name, :blank, @active_model
end

test "#assert_error raises ArgumentError with a non-active record" do
error = assert_raises(ArgumentError) do
assert_error :name, :blank, Object.new
end

assert_includes error.message, "does not respond to #errors"
end

test "#assert_error raises a Minitest::Assertion when validation fails" do
@active_model.name = "h"
@active_model.validate
error = assert_raises(Minitest::Assertion) do
assert_error :name, :blank, @active_model
end
assert_includes error.message, "Expected name to be blank"
end

test "#assert_not_valid asserts active model has error on a field after validation" do
assert_not_valid :name, :blank, @active_model
end

test "#assert_not_valid raises ArgumentError with message about the object nor responding to validate" do
error = assert_raises(ArgumentError) do
assert_not_valid :name, :blank, Object.new
end

assert_includes error.message, "does not respond to #validate"
end

test "#assert_not_valid raises a Minitest::Assertion when validation fails" do
@active_model.name = "Hi"
error = assert_raises(Minitest::Assertion) do
assert_not_valid :name, :blank, @active_model
end
assert_includes error.message, "Expected name to be blank"
end

test "#assert_valid asserts active model does not have an error on a field after validation" do
@active_model.name = "name"

assert_valid :name, :blank, @active_model
end

test "#assert_valid raises ArgumentError with message about the object nor responding to validate" do
error = assert_raises(ArgumentError) do
assert_valid :name, :blank, Object.new
end

assert_includes error.message, "does not respond to #validate"
end

test "#assert_valid raises a Minitest::Assertion when validation fails" do
error = assert_raises(Minitest::Assertion) do
assert_valid :name, :blank, @active_model
end
assert_includes error.message, "Expected name to not be blank"
end
end
2 changes: 1 addition & 1 deletion railties/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
* Use Kamal for deployment by default, which includes generating a Rails-specific config/deploy.yml.
This can be skipped using --skip-kamal. See more: https://kamal-deploy.org/

*DHH*
*DHH*

Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/railties/CHANGELOG.md) for previous changes.

0 comments on commit c7d35c1

Please sign in to comment.