-
-
Save bethesque/5a35a3c1cb9fdab6dce7 to your computer and use it in GitHub Desktop.
# Notes: | |
# Headers and status would still be value based matching | |
# Default to type based matching??? | |
# like(xxx) means xxx and all children would be matched using type based matching | |
# literal(xxx) means xxx and all children would be matched using exact value matching | |
# eg(generate, matcher) would be a regular expression match | |
# each_like([]) would indicate the each element in the array should be like the example given | |
# A like() could be nested inside a literal() which could be nested inside a like() - at each stage, | |
# it changes the matching type for all children until it gets switched back. | |
# Outstanding questions: | |
# Should array order matter? | |
# How to specify something like "an array of strings, length unknown" (eg. the backtrace of an exception) | |
# Ruby code | |
will_respond_with( | |
{ | |
status: 200, | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: { | |
age: 30, | |
address: literal({ | |
street: '123 Fred St', | |
suburb: like('Melbourne'), | |
postcode: '3000', | |
state: eg('VIC',/[A-Z]{3}/) | |
}), | |
phoneNumber: eg("0415 134 234", /\d{4} \d{3} \d{3}/), | |
favouriteColors: each_like(['red']), | |
an_empty_array: [], | |
url: eg('http://localhost:1234/blah', %r{http://.*/blah}) | |
} | |
}) | |
# Generated JSON | |
{ | |
"responseMatchingRules": { | |
"body" : { | |
"$..*": {"match": "type"}, | |
"$.address": {"match":"value", "allowExtraKeys": false}, | |
"$.address.suburb": {"match":"type"}, | |
"$.phoneNumber": {"regex" : "\d{4} \d{3} \d{3}"}, | |
"$.favouriteColors": {"eachLike": true }, | |
"$.url": {"regex" : "http://.*/blah"} | |
} | |
}, | |
"response": { | |
"body": { | |
"age": 30, | |
"address": { | |
"street": "123 Fred St", | |
"suburb": "Melbourne", | |
"postcode": "3000", | |
"state": "VIC" | |
}, | |
"phoneNumber": "0415 134 234", | |
"favouriteColors": [ | |
"red" | |
], | |
"an_empty_array": [], | |
"parents": [ | |
"mum", | |
"dad" | |
], | |
"url": "http: //localhost:1234/blah" | |
} | |
} | |
} | |
end |
I get the impression that this use case would be most useful when using pact to back an integration test on the consumer (I assume that's why you don't know what the event ID is ahead of time), which I don't think is it's best use, because we still get the combinatorial problem. That's why the Condor tests were the worst example of pact usage that we had! I will put it in an issue as a feature that we need to consider for 2.0.0 though.
I've done a bit of work on JSON-based matchers before.
For specifying types (ie. Array / Hash)
what about:
friends: type(Array)
age: type(String)
but it almost feels like you will need a Hash declaration for each property to define a set of rules/matchers:
- type
- length
- regex / pattern(s)
- custom validations (eg. call a method)
There are a couple of reasons I've stuck with the "here's an example" technique rather than the "define the types" technique. One is that pact would have to randomly generate values for the response in the consumer project, and the request when verifying a pact, and randomly generated values are not great for the auto generated documentation. The second is that, as you say, you'd have to start specifying the lengths as well, or you'd get random errors if the generated string was too long. This would add complexity to both the definition and the code. I'm not discounting the idea entirely, but it's not the direction I've been heading in, after giving both concepts a good deal of thought.
Super late to the party on this one.
The good thing about pact 1.0 is that you have a clear document indicating what's being tested structurally.
With the jsonpath matching rules, you've still got your structure, but then you've got a list of rules which are exceptions to the structure. Building a mental model of where those rules apply is challenging, it harms readability, it's less a document and more of a serialised program.
Unfortunately I don't have a good solution, documents are naturally less flexible than programs, and programs are naturally less readable than documents.
I would like to see a mechanism to use the value from the received request. The idea being that some values need to be present, but we are unable know what the value actually will be because they are auto generated. Thus it would be convienient to say: match("") and then use the value from the request if it matches.
One example is a request to the following resource:
The Path includes a UUID of the new resource, so I would like to say:
Then if it matches, the generated value in the pact file can be the original request value.