Assertion with in failed (changeset.errors)

Dear all,

I’ve been reading the Programming Phoenix book and have been enjoying it tremendously so far. However, I’ve encountered a a problem with the ExUnit test in user_test.exs which I can’t solve on my own yet.

My problem is similar to this thread. But in my case, the next testcase is faulty.

  test "registration_changeset password must be at least 6 chars long" do
    attrs = Map.put(@valid_attrs, :password, "12345")
    changeset = User.registration_changeset(%User{}, attrs)

    assert {:password, "should be at least %{count} character(s)", count: 6} in changeset.errors
  end

When I run the test, I get the following error:

  1) test registration_changeset password must be at least 6 chars long (Rumbl.UserTest)
     test/models/user_test.exs:19
     Assertion with in failed
     code:  {:password, "should be at least %{count} character(s)", [count: 6]} in changeset.errors()
     left:  {:password, "should be at least %{count} character(s)", [count: 6]}
     right: [password: {"should be at least %{count} character(s)",
              [count: 6, validation: :length, min: 6]}]
     stacktrace:
       test/models/user_test.exs:23: (test)

How can I fix my test case? I tried different techniques, but nothing worked :neutral_face: Any hints would be greatly appreciated!

Elixir version: 1.4.1
Phoenix version: 1.2.1

3 Likes

The fix for now would be:

{:password, {"should be at least %{count} character(s)",
          [count: 6, validation: :length, min: 6]}} in changeset.errors()

But that’s rather unpleasant and verbose. I would propose adding a function that looks like this:

def errors_on(changeset, field) do
  for {message, opts} <- Keyword.get_values(changeset.errors, field) do
    Enum.reduce(opts, message, fn {key, value}, acc ->
      String.replace(acc, "%{#{key}}", to_string(value))
    end)
  end
end

Then you can do:

"should be at least 6 characters" in errors_on(changeset, :password)
8 Likes

Thank you very much for the fast response, José! Your fix worked for me. I adopted the function and added it to my test/support/model_case.exs.

All tests are green now and I can continue the journey.

1 Like

Please note that Keyword.get_values(changeset.errors, field) is not handling errors on embeds (these are stored as changeset.changes.<embed_name>.errors) so it might be better to use Ecto.Changeset.traverse_errors which does that.

In fact the example usage should perfectly fit your use case: https://hexdocs.pm/ecto/Ecto.Changeset.html#traverse_errors/2-examples

1 Like