Open iamchughmayank opened 1 year ago
Looks like there's a bug where the request filters are inappropriately applied to the state handlers.
What's happening is the state handler request is being redirected by your request filter, which means it is never called. You can fix this by removing your request filter.
I think the reason this hasn't been picked up before is because that's not how you're supposed to use request filters. I'm not 100% sure what you're trying to do, but you almost never need request filters - they're for rare situations where you need to inject authentication headers because you don't control the auth part of the server.
If you need the state handler to set up a client ID that is used in the test, then you need to:
1) Generate the contract to expect a variable from the provider state in the path (you can use fromProviderState
to do this).
2) Return the client ID in your state setup (return { clientId: 12 }
or return Promise.resolve({ clientId: 12 })
)
Thanks for a prompt response @TimothyJones :)
I'm not 100% sure what you're trying to do, but you almost never need request filters - they're for rare situations where you need to inject authentication headers because you don't control the auth part of the server.
In my actual provider service, we have fixtures that help us to create on-demand test data for our unit tests to be destroyed at the end of test session. For example, if the unit test is looking for clientId = 100
, the fixtures help to create that clientId
. This helps us to avoid using static data in our tests and test db which can go stale easily.
I am trying to reuse those fixtures in the contract tests as well by creating the data as per state.
From the test lifecycle in pact documentation, I figured that if I set the clientId
for each Given
state and then used requestFilter
to use that clientId
, it should become easy to test various cases like "valid id", "invalid id", "not found", etc. At the same time keeping the consumer test fairly intuitive that path to be tested will be /clients/:id
and not something that will be generated by provider.
If you need the state handler to set up a client ID that is used in the test, then you need to:
Generate the contract to expect a variable from the provider state in the path (you can use fromProviderState to do this). Return the client ID in your state setup (return { clientId: 12 } or return Promise.resolve({ clientId: 12 }))
Thanks for pointing that out :) I was able to implement it and get my contract working here: https://github.com/iamchughmayank/pact-stateHandler-issue-demo
While my consumer and provider API teams DO NOT have any comms challenge and both the services are handled internally (no public API here), using both stateHandler and requestFilter felt intuitive. Do you think this issue will be picked up?
That’s a question for a maintainer. I think they’re all taking a well-deserved rest over the Christmas and new year period at the moment.
The request filter isn’t intended for this use case- I think you would run in to other maintenance issues if you tried scaling up that approach (for example, the path rewrite approach only works for one interaction- what happens if you have two?).
Importantly- if you’re rewriting parts of the interaction in the request filter, how do you know that what was tested at the client side matches what is tested at the provider side? The ability to know that your consumer expectation matches your provider behaviour is a key part of pact, and you would lose this if you built a lot on top of rewriting requests in the filters.
Thanks for the report @iamchughmayank. The request filters are expected to work on the state handlers and requests to your provider. The reason you're seeing the POST
is that the framework core actually calls the state handlers over HTTP.
This could be documented better, so I will leave this request open as a documentation issue.
Request filters are a powerful and advanced feature that most users shouldn't need, and as Tim has mentioned you should be able to solve your problem using other features.
In the case where pact is hosting the state handlers itself, I feel like the request filters would be expected not to be applied?
Yes I think so too, however at this point it would be a breaking change to not also apply it to the provider states (you could perhaps argue it as a bug that is fixed, but the impact would be the same).
I think there is some small utility in preserving that behaviour but not enough to justify a separate feature.
So either we document the behaviour and/or rename it because it's misleading, or remove it and release a new major version.
Thanks @TimothyJones and @mefellows for the explanation and details :) I am able to use fromProviderState
to solve for my use-case :)
Software versions
Issue Checklist
Please confirm the following:
Issue Description
I am new to Pact and I am trying to create an MVP for contract testing between two of our services.
I was able to setup a simple example test without any state, however, I am unable to setup multiple states using
stateHandlers
. I have tried following the example here forV3
and also here which usessetup
in the providerState but to no avail.When I run the tests, I am observing two issues with my tests:
providerState
is not being set properly before therequestFilter
request.method
asGET
, the API call to the provider service is going withPOST
. If I manually override it in therequestFilter
, I am able to convert it toGET
I have checked various forums/existing issues and Stackoverflow, however, I could not find anyone facing problems with
stateHandlers
basic implementation.Any help in
Expected behaviour
I am expecting the stateHandler to change a variable value as per the state name which will be then picked up by the
requestFilter
to bring provider in desirable state.Steps to reproduce
Demo repository: https://github.com/iamchughmayank/pact-stateHandler-issue-demo
Relevant log files
Pact File
Provier Spec
In the above case, when I run the test, I get a
GET
request withclientId
asundefined
even though thestateHandler
has been setup to change the idClientService | 172.17.0.1 - - [29/Dec/2022:15:46:56 +0000] "GET /clients/undefined HTTP/1.1" 404 67 "-" "-"
The pact tests fail with error:
Debug logs