devonestes / assertions

Helpful assertions for ExUnit
MIT License
142 stars 27 forks source link

Assertion for errors in `Absinthe.run` response? #26

Closed darrenklein closed 2 years ago

darrenklein commented 2 years ago

Hello, and many thanks for all of your hard work on this library!

What would be the appropriate way to test for errors resulting from calls to Absinthe.run? For example, the API provides the assert_response_matches macro, which will pattern-match on the :data key in the result:

    defmacro assert_response_matches(schema, document, options, do: expr) do
      quote do
        ExUnit.Assertions.assert {:ok, %{data: unquote(expr)}} =
                Absinthe.run(unquote(document), unquote(schema), unquote(options))
      end
    end

But I have some error scenarios that I'd like to test, where the result of the call to Absinthe.run here is something like

 %{
   data: %{"someMutation" => nil},
   errors: [
     %{
       field: "someField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the future"],
       path: ["updateSomeField"]
     },
     %{
       field: "anotherField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the past"],
       path: ["updateSomeOtherField"]
     }
   ]
 }

where I'd like to test that the error messages are coming back as I expect. Unless I'm misunderstanding, I don't think that assert_response_matches in its current form will be able to do that. I looked through the other assertions in the API you provide, but I couldn't find any means for testing the contents of the :error key (though I'm often known to overlook the obvious). Is there a way to test the :error portion of the response with this library?

Now, of course I can just test Absinthe.run(document, schema, options) and that's fine, but since your library provides so many other useful tools, I'd like to be able to use it for this, too. If there is a way, I'd appreciate it if you could point me toward it. If not, I would really love the opportunity to code up an assert_error_matches macro and submit it for PR.

Thanks again!

devonestes commented 2 years ago

This is intentionally missing. The tricky thing about what you're talking about is that you don't want to assert a match on lists, and the top level error key is always a list. So, for testing this you'll always want to do something like:

expected_errors = [
     %{
       field: "someField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the future"],
       path: ["updateSomeField"]
     },
     %{
       field: "anotherField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the past"],
       path: ["updateSomeOtherField"]
     }
   ]
%{errors: errors} = Absinthe.run(document, schema, options)
assert_lists_equal(errors, expected_errors)

I don't know why, but I really only like the do/end macro notation for pattern matches, and in this case something like this I just don't find easy to use or helpful at all, to be honest.

assert_errors_equal(document, schema, options) do
  [
     %{
       field: "someField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the future"],
       path: ["updateSomeField"]
     },
     %{
       field: "anotherField",
       locations: [%{column: 5, line: 2}],
       message: ["must be in the past"],
       path: ["updateSomeOtherField"]
     }
   ]
 end

The reason there's the macro for the pattern match is because of the way pattern matches on maps work. You can't do the same as above for pattern matching on a valid response because it basically uses == in this case for the expected result and the actual result.

expected_data = %{
  dog: %{
    name: "Miki"
  }
}
assert %{data: ^expected_data} = Absinthe.run(document, schema, options)

So, yeah, I don't think this is a great fit, actually, because the only API I can think of for it is kind of clunky, and it would only save one line of code. If you can think of some other API for this, though, let me know and I'll consider it!

darrenklein commented 2 years ago

Thanks for getting back to me on this, I see what you mean. Off the top of my head, I don't have any ideas, but I'll stew on it a bit and will let you know!

In the meanwhile, testing against the results of Absinthe.run/3 works out perfectly fine for me. Appreciate your feedback and hard work!