Pact JS verification failing on /api/v2/interactions with dynamic query params

pact-js 11.1.0. provider verification stage in ci is blowing up. consumer contract looks fine locally.

contract snippet:

provider.addInteraction({
 state: 'agent available for wrap up',
 uponReceiving: 'request for active interaction history',
 withRequest: {
 method: 'GET',
 path: '/api/v2/interactions',
 query: {
 status: 'active',
 routingType: 'queue'
 }
 },
 willRespondWith: {
 status: 200,
 body: {
 totalCount: 1,
 items: [
 {
 id: Pact.term({generate: 'abc-123', matcher: Pact.regexp('.*-.*')})
 }
 ]
 }
 }
})

the issue is the routingType param. when the provider (genesys cloud) actually runs the verification, it appends extra query params like pageSize=25 and page=1 that aren’t in the contract. pact is strict on query param matching by default. it’s failing with:

Query parameter 'pageSize' was not expected but was received.

tried using Pact.term on the query object but that doesn’t seem to work for extra keys. just matching the known keys isn’t enough. the provider sends back 200 with data, but pact rejects it because the query string doesn’t match exactly.

setting matchingRules on the query params:

withRequest: {
 query: Pact.like({
 status: 'active',
 routingType: 'queue'
 })
}

still fails. Pact.like checks for existence, not absence. if i want to ignore extra params, i need to tell pact that the query object can have other keys.

can’t find a clean way to say “match these specific keys and ignore the rest” in pact-js 11. docs suggest using Pact.term with a regex on the whole query string but that feels brittle and breaks if the order of params changes.

is there a standard pattern for ignoring provider-side pagination params in query strings? or do i have to manually list every possible param the gc api might append? that seems unsustainable.

using jest for tests. node 18.

anyone got a working example of flexible query param matching for list endpoints?

This usually happens when the consumer contract doesn’t strictly define how dynamic query parameters should behave during provider verification. The Genesys Cloud API often appends internal tracking or pagination params that aren’t in your original contract snippet. If you’re using Pact.term, make sure you’re actually matching the regex pattern against the full query string, not just the static keys.

Try switching to Pact.like for the query object if the values are strictly static, or use Pact.regex if they vary. For example:

query: {
 status: 'active',
 routingType: Pact.regex(/^queue$/, 'queue')
}

Also, check if your provider state handler is correctly setting up the mock data before the interaction. A common fix is to ensure the state change function returns a promise that resolves only after the mock data is fully committed. If the verification fails on the first run but passes on retry, it’s likely a race condition in your setup script.

the previous advice is on the right track, but pact-js often struggles with query param ordering. i usually bypass the query object entirely.

just match the full path string using a regex. it’s cleaner and avoids those weird serialization bugs.

path: Pact.like('/api/v2/interactions?status=active&routingType=queue')

yeah, hardcoding the query string in the path like that is risky for longer term maintenance. pact-js handles query objects natively, you just need to tell it to ignore the order. the Pact.term approach is good for specific values, but Pact.ignore is your friend here when extra params creep in.

try updating the withRequest block to explicitly allow extra query parameters. this prevents the strict match failure when Genesys adds things like pageSize or internal tracking ids.

withRequest: {
 method: 'GET',
 path: '/api/v2/interactions',
 query: {
 status: Pact.term({ generate: 'active', matcher: 'active' }),
 routingType: Pact.term({ generate: 'queue', matcher: 'queue' }),
 // allow extra params without failing verification
 ...Pact.like({}) 
 }
}

actually, even better, just use Pact.somethingLike for the whole query object if you don’t care about the specific values, or stick to term but ensure the consumer test actually sends exactly what’s defined. the issue is often the consumer stub adding defaults. check your consumer test setup first.