pact-foundation / pact-js

JS version of Pact. Pact is a contract testing framework for HTTP APIs and non-HTTP asynchronous messaging systems.
https://pact.io
Other
1.61k stars 344 forks source link

Convenience matchers for exact matches and spreading objects #730

Open TimothyJones opened 3 years ago

TimothyJones commented 3 years ago

Checklist

Feature description

Add a matcher that spreads an object and does a like on each property, and add a matcher that is restricted to an exact string.

Use case

Sometimes you want to wrap most (but not all) of an object in a Matchers.like() call, for example where you care about an exact string for type.

On slack, Chris asked if it was possible to do:

body: {
  ...Matchers.like(fullObject),
  type: "some_string_you_switch_on"
}

Sadly, it isn't. However, you can do:

Matchers.like({
  ...fullObject,
  type: Matchers.term({ 
    generate: "some_string_you_switch_on", 
    matcher: "some_string_you_switch_on"
  })
})

But, maybe we can make that nicer. Suggested options:

{
  ...Matchers.eachPropertyLike(fullObject),
  type: "some_string_you_switch_on"
}

and

Matchers.like({
  ...fullObject,
  type: Matchers.exactString("some_string_you_switch_on")
})
mefellows commented 2 years ago

So the issue that I think we're trying to solve here is the fact that matchers recurse and you may not want everything to be a type matcher. We can actually achieve this through the equals matcher that essentially resets the cascading matching rules on that value (and any children):

So you could do this:

body: Matchers.like({
    "foo": "bar",
    "baz:" equals("bat") // <- this can be any JSON type, and may also be deeply nested
})

or perhaps more composably:

body: {
  ...Matchers.like(someExample),
  type: equals("someExactString")
}

The equals matcher can be used anywhere deep in the JSON object, so that would help with cases where you have nested values that must be exact matches.