Writing tests for JSON parsers in Elm

I want to write some proper testing for my JSON parsers/encoders, as I find they are the source of most of the bugs I create lately. I attempted to just use Elm-Test, but find it hard, as just putting my test JSON as a string in the source code doesn’t work very well (the pasting of the string literal messes up the json syntax), and writing comparisons to check each field feels a bit off somehow.

So how do other people here test their JSON parsers?

One thing that might help are multiline strings:

myJson = """{
  "message": "You can have quotes in here!",
}"""

roundtripTest : Test
roundtripTest =
  Test.test "decode/encode roundtrip" <|
    \() -> 
      case Json.Decode.decodeString myDecoder myJson of
        Ok value ->
          -- We can't compare the string/Json.Value to the original directly, because the field ordering or whitespace could differ and we don't care about that
          case Json.Decode.decodeValue myDecoder (myEncode value) of
            Err err ->
              Expect.fail <| "Failed encode->decode roundtrip: " ++ Debug.toString err

            Ok value2 ->
              value2
                |> Expect.equal value1

        Err err ->
          Expect.fail <| "Failed decoding fixture JSON: " ++ Debug.toString err

Admittedly roundtrip tests make more sense when you’re starting from the structured data, not from a JSON string.

Other than that, no, elm-test doesn’t currently support providing filesystem JSON files to your tests as strings. But I think that might make sense, in some shape.

1 Like

If you use multiline strings like Janiczek suggested, note that if your JSON contains backslashes you need to double them: \\\. You can do that with find-and-replace.

At work we use (a fork of) elm-codec. Codecs have a couple of benefits:

  • The decoders and encoders are pretty much guaranteed to match and roundtrip.
  • When adding a new variant to a custom type, or a new field to a record, you can’t forget to update a decoder or encoder (you’ll get a compiler error).
  • You get a standardized JSON encoding.

Once you get over the hurdle of codecs feeling weird they’re great.

At work we use F# in the backend, which is sorta similar to Elm. We often copy-paste types and codecs between the two languages, and just adjust the syntax slightly for the target language. This results in frontend and backend usually being able to talk to each other via JSON without trouble.

Sometimes we write codecs for JSON we have stored in our database. We have a script that downloads all JSON of choice, and runs it through our codecs, to make sure that it all can be decoded properly, and then we encode it again and decode once more to make sure it roundtrips.

Because of the above, we don’t write many tests for JSON decoding and encoding. We only do it when we have to do something especially tricky, due to having to deal with some annoying JSON format we cannot control. Other than that, JSON is pretty much on auto pilot.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.