Closed sanketi closed 7 years ago
I assume you wish to address the response part of the fragment.
If you wish to match a JSON which has an unknown (zero or more) objects under "Certification"
, with the key being any string (Java, Scala etc.), and the value being any object, then I can't think of a way of achieving this with Pact.
However, I would suggest changing your schema to something like:
"Certification": [
{
"language": "Java",
"version": "1.7",
"year": 2015
},
{
"language": "Scala",
"version": "2.11",
"year": 2016
}
]
Then you can use DslPart
to build a body matcher like so:
val body = new PactDslJsonBody()
.minArrayLike("Certification", 1, 1)
.stringType("language")
.stringType("version")
.integerType("year")
.closeObject()
.closeArray()
This will eventually generate a pact file similar to this:
{
"provider": {
"name": "My Provider"
},
"consumer": {
"name": "My Consumer"
},
"interactions": [
{
"description": "a request for foo with a body",
"request": {
"method": "GET",
"path": "/foo",
"body": ""
},
"response": {
"status": 200,
"body": {
"Certification": [
{
"language": "MpTNFzmpGufqeCoKZsJp",
"version": "wyVICggKfSytgwObduad",
"year": 604416835
},
{
"language": "MpTNFzmpGufqeCoKZsJp",
"version": "wyVICggKfSytgwObduad",
"year": 604416835
},
{
"language": "MpTNFzmpGufqeCoKZsJp",
"version": "wyVICggKfSytgwObduad",
"year": 604416835
}
]
},
"matchingRules": {
"$.body.Certification": {
"min": 1,
"match": "type"
},
"$.body.Certification[*].language": {
"match": "type"
},
"$.body.Certification[*].year": {
"match": "integer"
},
"$.body.Certification[*].version": {
"match": "type"
}
}
}
}
],
"metadata": {
"pact-specification": {
"version": "2.0.0"
},
"pact-jvm": {
"version": ""
}
}
}
@alonpeer has described a elegant solution if you are able to change the format of the JSON.
As to optional values, we don't really support them (the idea is to leave optional things out and only include the important things in the contract. Also see https://docs.pact.io/faq/#why-is-there-no-support-for-specifying-optional-attributes)
There is a specification change proposed (https://github.com/pact-foundation/pact-specification/tree/version-4#additional-matchers) to introduce an or
condition with additional matchers, but it is a work in progress.
Thank you @alonpeer for the detailed example. At this point unfortunately I cant change the schema to make this change.
@uglyog : thank you for your comment as well. So I will exclude these optional attributes from my test.
How about this contract:
The customer may use pact-jvm for free as it is open source. Conditionally, if it were to support optional attributes, the customer must pay $1m.
But hey, optional stuff isn't important, so let's just ignore it and let the customer use it for free ;-)
This is a real shame to not support conditional parts in responses. Is there no solution/workaround to this problem still?
Given I have different types of objects:
[
{
type: "TYPE_A"
},
{
type: "TYPE_B"
}
]
I would like to be able to write a matcher, which only focuses on TYPE_A, hence making my matching rules conditional on the type.
Given the schema-less nature of JSON, this should definitely be supported.
I stumbled across this old issue which seems to be linked from a few places so I thought a quick update is warranted.
First up, support for your use case @bengro is part of the ArrayContains
matcher. It is possible, but is different than what the OP is asking for which is support for conditional/optional attributes which Pact does support, it's just that each variant needs individual testing.
Given the schema-less nature of JSON, this should definitely be supported.
This statement is orthogonal to what we're doing here. Pact is a specification-by-example framework whose job is to prevent things from breaking. Whether or not a schema exists is irrelevant, as the presence of a schema itself doesn't guarantee behaviour.
For more on this topic see https://pactflow.io/blog/schemas-are-not-contracts/ and the Pact justification here: https://docs.pact.io/faq/#why-is-there-no-support-for-specifying-optional-attributes.
Hi, This is a question. What is the best way for me to define something like below in Pact Fragment -
So basically inside Certification object, each object can be null or have some additional fields.
What would be a good way to do this so it accepts values or null?