ash-project / splode

Aggregatable and consistent errors for Elixir
MIT License
17 stars 4 forks source link

Add a method for traversing errors/outputting to a simple format #4

Open sevenseacat opened 7 months ago

sevenseacat commented 7 months ago

Is your feature request related to a problem? Please describe.

When testing validations in an Ash project for example, it's a bit messy to neatly assert what errors were/weren't returned when calling an action.

eg.

# `errors` is a struct of type `%Ash.Error.Invalid{errors: [...], ...}`
# I got a bit misled thinking it was a changeset, but it is not!
{:error, errors} = Album.create(%{cover_image_url: "invalid"}, actor: actor)

# There should be an error on the cover_image_url field but how to get it, to verify 
# that the validation ran correctly?

# This returns the full message with stacktrace that would be printed if I called `create!`, eg. 
# Exception.message(errors) #=> "Input Invalid\n\n* attribute name is required\n  (elixir 1.15.7) 
# lib/process.ex:860: Process.info/2\n  (ash 2.19.8) lib/ash/error/exception.ex:59: 
# Ash.Error.Changes.Required.exception/1\n  (ash 2.19.8) lib/ash/changeset/changeset.ex:2255:...
dbg(Exception.message(errors))

Describe the solution you'd like

The Phoenix app generator generates a test helper function for Ecto changesets that looks like this -

  @doc """
  A helper that transforms changeset errors into a map of messages.

      assert {:error, changeset} = Accounts.create_user(%{password: "short"})
      assert "password is too short" in errors_on(changeset).password
      assert %{password: ["password is too short"]} = errors_on(changeset)

  """
  def errors_on(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
      Regex.replace(~r"%{(\w+)}", message, fn _, key ->
        opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
      end)
    end)
  end

It would be awesome if there was some Ash/Splode equivalent, an inbuilt way to traverse errors or convert them directly to a readable format that can then be queried.

AshPhoenix already has something like it for forms as well.