surpher/PactSwift

Add the eachKeyLike matcher

luizesramos opened this issue ยท 2 comments

๐Ÿ—ฃ Context

The current Pact DLS defines the eachKeyLike Matcher with an example here

The Java implementation of the Matcher and describes eachKeyLike as:

Accepts any key, and each key is mapped to a map that must match the 
following/provided object definition Note: this needs the Java system property 
"pact.matching.wildcard" set to value "true" when the pact file is verified.

pact-js implementation of eachKeyLike matcher.

๐Ÿ’ฌ Narrative

When the Producer issues a response containing a dictionary with one or more Keys
I want to be able to validate the type and format of the Values in the dictionary without knowing the Keys
So that I can add or remove values from the Producer's dictionary without the Consumer flagging a contract issue.

๐Ÿ“ Notes

๐Ÿ— Design

Example: this service response

{
  "abc": { "field1": "value1", "field2": 123 },
  "xyz": { "field1": "value2", "field2": 456 }
}

Could be validated with

Matcher.eachKeyLike([
  "field1":  Matcher.somethingLike("a string"),
  "field2": Matcher.somethingLike(0)
])

Note: the response validation is possible without knowing the keys "abc" and "xyz" in the service response above.

โœ… Acceptance Criteria

GIVEN a dictionary populated with key-value pairs
WHEN the eachKeyLike matcher is applied on the dictionary
THEN the broker will not make assertions on the dictionary key, only on the values.

๐Ÿšซ Out of Scope

Regex validation for the keys. We can create a follow-up issue for that, if the DSL requires it.

Matcher.EachKeyLike(_:) has been added to PactSwift on branch feature/matcher-each-key-like. This is the first MVP to support this. In the future might find some more time to allow different variations of the struct's init (eg: passing in a dictionary). For now, this should suffice.

For the following response containing "abc" and "xyz" during consumer test and where they should be considered as wildcards at provider verification time:

{
  "abc": { "field1": "value1", "field2": 123 },
  "xyz": { "field1": "value2", "field2": 456 }
}

use the EachKeyLike matcher as:

.willRespondWith(
  status: 200,
  body: [
    "abc": Matcher.EachKeyLike([ 
        "field1": Matcher.SomethingLike("value1"),
        "field2": Matcher.IntegerLike(123)
    ]),
    "xyz": Matcher.EachKeyLike([
      "field1": Matcher.SomethingLike("value2"),
      "field2": Matcher.IntegerLike(456)
    ])
  ]
)

The generated matchers will look like:

"matchingRules": {
  "body": {
    "$.*": {
      "combine": "AND",
      "matchers": [{"match": "type"}]
    },
    "$.*.field1": {
      "combine": "AND",
      "matchers": [{"match": "type"}]
    },
    "$.*.field2": {
      "combine": "AND",
      "matchers": [{"match": "integer"}]
    }
  }
},

Available from PactSwift v0.13.0.