Test Ash Validation
Here's a way to test a validation module in Ash framework.
The resource
Let's say that we have an Ash.Resource
defined. Here are the bits that matter. There's a resource with an attribute, genre_id
, that's defined as a relationship. There is an action for :create
. It has a validate
macro in its body. That references a custom validation module.
defmodule MyLibrary.Book do
use Ash.Resource
# ...
attributes do
# ...
end
relationships do
# ...
belongs_to :genre, MyLibrary.Genre do
allow_nil? false
public? true
end
end
actions do
defaults [:read]
create :create do
accept [:genre_id]
validate MyLibrary.IsGreatGenre
end
end
end
The validation
The validation module looks something like this. It's getting the input genre_id
, making a database lookup, then making a genre record data comparison in order to validate:
defmodule MyLibrary.IsGreatGenre do
use Ash.Resource.Validation
@impl true
def validate(changeset, _opts, _context) do
genre_id = Ash.Changeset.get_argument_or_attribute(changeset, :genre_id)
genre = Ash.get!(MyLibrary.Genre, genre_id)
if genre.greatness_level in ["great", "super", "magnificent"] do
:ok
else
{:error, field: "genre_id", message: "Only great genres allowed"}
end
end
end
The validation test
Well, what genres would pass this strictly-great validator? Let's make a test!
defmodule MyLibrary.IsGreatGenreTest do
use MyLibrary.DataCase,
async: false
test "not great genre" do
genre = GenreFixtures.at_greatness_level!("lowly")
changeset = Ash.Changeset.for_create(MyLibrary.Book, :create, %{
genre_id: genre.id
})
assert %Ash.Changeset{
valid?: false,
errors: [
%Ash.Error.Changes.InvalidAttribute{
field: "genre_id",
message: "Only great genres allowed"
}
]
} = changeset
end
test "is great genre" do
genre = GenreFixtures.at_greatness_level!("magnificent")
changeset = Ash.Changeset.for_create(MyLibrary.Book, :create, %{
genre_id: genre.id
})
assert %Ash.Changeset{valid?: true, errors: []} = changeset
end
end
There are two cases: valid and not valid. When you create an Ash.Changeset
, it will be validated and call each validator in the action.
Validated. Tested. Done.