Even though functions that use this one all have HasCallStack, the fact
that this function itself doesn't means that all errors are reported as
from this line anyway:
Failures:
./Yesod/Test.hs:1571:28:
1) ...
This should correct that.
My team makes frequent use of `statusIs`, but in virtually all cases where `statusIs` fails, we need to add a call to `printBody` to do further debugging.
Following in the footsteps of `requireJSONResponse`, this PR automatically prints a portion of the body when `statusIs` fails, assuming the body looks like a text-based response (e.g. not a JPEG).
I've found that a status code alone is often very misleading and leads people on a wild good chase, because e.g. a 403 could be triggered for many different reasons.
I'm opening this PR as a draft to confirm people like the idea of doing this. If so I'll do a closer review of the code (this is my first draft basically), and also write some tests + test the code works in all cases.
This function checks that a response body is JSON, and parses it into a Haskell value. Having something like this function is pretty essential to using Yesod as a JSON API server, so I think it's a good addition. You can use it to parse a Haskell record directly (usually by adding FromJSON classes to your response types), or parse a Value and pull out individual fields, maybe using something like `aeson-lens` (though probably a testing-specific library would be better).
I debated over these things:
1. The name. I was thinking of something like [assert/require/decode/parse]JSON[Response/Body]. I ultimately went with requireJSONResponse:
- decode/parse sound like the aeson functions that return Either or Maybe, and I wanted this function to throw an error if it failed
- I'm open to using `assertJSONResponse`—it matches the other functions (`assertEq`) better—but I think it reads less like English.
- I chose Response over Body because (a) It also checks the content-type header, which is not in the body (b) "Body" felt slightly in-the-weeds of HTTP; I think "response" is more approachable.
2. Should it require the JSON content type? You can definitely have a server that returns JSON without JSON content types, but I think that's a such a bad idea, it's more likely requiring it helps people if they accidentally don't add the header.
3. Should it take a String parameter to add to the error message? This would match `assertEq`, but other functions like `statusIs` don't take a message. Ultimately I went without it, because the messages felt like I was repeating myself: `(comment :: Comment) <- requireJSONResponse "the response has a comment"`
[weeder: Detect dead code](https://hackage.haskell.org/package/weeder)
deleted depends is
* mime-mail
* wai-eventsource
I sort build-depends, because duplicate depend some exist, to sort is detect to easy.