atrium
atrium copied to clipboard
assertion functions for Json
Platform (JVM and/or JS): JVM/JS
Code related feature
Yet to be defined how it should look like and how it should behave. Following a suggestion:
assert("{val: "value", obj: {prop: \"value\"}}").isJson {
property("obj").isObject {
property("prop").toBe("value")
}
}
Where it normally should not matter in which order the properties appear. However, I am not sure how we should treat data which we did not expect (val
in the above example).
Sometimes even order matters, for such cases we could introduce something like inOrder
:
assert("{val: \"value\", obj: {prop1: \"val1\", prop2: \"val2\"}}").isJson.inOrder{
property("obj").isObject {
property("prop").toBe("val2") // does not fail, inOrder is per object
property("prop").toBe("val1")
}
property("val").toBe("value") // fails because not in order
}
Ideas and feedback are welcome.
Another use case is comparing a json against a predefined json:
assert(json).isJson(expectedJson)
Meaning we could parse the expectedJson
and turn it into the above assertions. In such a case we would certainly want that it fails if there is unexpected data.
In case someone needs the properties to be in order, then one could use:
assert(json).isJson.propertiesInOrder.toBe(expectedJson)
I guess failing if there is unexpected data should also be the normal case for isJson {}
where we could have an option ignoreUnexpectedProperties
:
assert(json).isJson.ignoreUnexpectedProperties.toBe(expectedJson)
Which we could combine with other options as well.
Another example with isJson{}
assert("{val: "value", obj: {prop: \"value\"}}").isJson.ignoreUnexpectedProperties {
property("obj").isObject.inOrder {
property("prop").toBe("value")
}
}
Does not fail even though val
was unexpected
Maybe we should shorten the syntax and use p
instead of property
so that it resembles closer a json structure?
Another way to think about ignoreUnexpectedProperties
might be something like "contains".
@keturn Makes sense if you don't compare against another json. Yet, how would you define on which level it can occur or is it only on the current level (that would be a possibility)? In the sense of, would
assert(json).isJson.contains{ property("a").toBe("b") }
hold if we have { obj: { a: "b" }}
?
Or how would you expect the syntax looks like?
A few other edge cases we have to define:
- what if a json defines a property multiple times -> I suggest we fail as well
- what if the json is invalid -> I suggest we fail as well
And naming needs a decision, I saw that others use key
instead of property
(in the sense of key/value) and the ECMA standard refers to it as name
. What should we use?
I guess something like using JsonPath to select a value/obj/array and make an assertion could be handy as well. No need to support that from the start though, if someone should need it "immediately" then let me know it.
JsonPath just wouldn't conform with the DSL and is not an assertion language but rather a retreival language... if JsonArray is treated like a List and JsonObject like a map, then regular assertions could be made on its structure. This would be easier to maintain, as all it would need is initial parsing that I suppose most platforms already have in some form or other... what would jsonpath add to this?
I would use JsonPath for retrieval, it could make assertions more readable in certain cases. Following an example:
assert(json).isJson {
path("/store/book/author").contains("J. R. R. Tolkien", "F. Kafka")
}
This would collect all authors of books and one could make an assertion about them. Of course, one could also do the retrieval beforehand and then assert on the resulting list. This is one of the reasons why this is a low prio feature and I will not add it at the beginning.