Corey Maynard
10/02/2023, 8:31 PMclient.getHealth()
in their example there) to hit that defined endpoint. However, in my application we do not have an API class that holds the logic for calls. Instead we are putting that directly in the component:
const FooComponent = () => {
// useAPI is effectively a hook wrapping axios.get in this case
const { isLoading, response, error } = useAPI("/bar/foo/");
....
if (isLoading) {
...
} else if (error) {
...
}
return <p>{response.data}</p>
}
With a component structure like that how would you recommend generating a contract for the /bar/foo/
endpoint? I don't want to write a standalone pact test as shown in the jest-pact documentation, as that would not call any production code:
pactWith(...), provider => {
...
provider.addInteraction({
...
withRequest: {
method: "GET",
path: "/bar/foo/"
})
axios.get("/bar/foo/")
// assert that the request returned 200
}
And obviously because the above doesn't call the actual FooComponent at all it doesn't represent the contract and won't fail if the FooComponent changes.
It seems to me a better solution would be something like this:
const mock = new MockAdapter(axios); // <https://www.npmjs.com/package/axios-mock-adapter>
describe("Test the FooComponent", () => {
it("handles loading", async () => {
mock.onGet("/bar/foo").reply(200, {foo: "Is good"});
render(<FooComponent />)
// wait for loading message to go away
// assert "Is good" appears
})
it("handles error", async () => {
mock.onGet("/bar/foo").reply(500, {detail: "Oops"});
render(<FooComponent />)
// wait for loading message to go away
// assert "Oops" appears in document
})
});
This is a functional test that tests the component and describes the API: /bar/foo/
shall exist and when GET requested shall return a 200 response with a foo
key that holds a string. If it can't it will return an error with a detail key. No other methods are handled on this endpoint.
It would be nice if running a test like that could build a contract off of the mocked requests defined in the test. Is something like that possible?
Thanks for your advice!Matt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Corey Maynard
10/03/2023, 1:17 PM/foo/bar/
- but that seems like something that could be resolved through an additive deduplication before the contract is generated. Just as a swagger file describes the provider's options (/foo/bar
returns a 200 with a JSON object with a 'foo' key, or returns a 500 with a detail key) presumably it should be possible to reduce the two mocked calls in the Jest test to describe the multiple requirements of the single API endpoint consumed?
I don't fully understand the comment about states there either, the swagger document doesn't provide explicit states in it so how would it match up anyways?
I also don't follow what you're saying about how using the swagger file resolves the problem?
As far as the anti-pattern, I've not seen that specific verbage mentioned anywhere, but I've seen multiple sites talking about how using pact for functional testing is a no-no:
• https://docs.pact.io/consumer#use-pact-for-contract-testing-not-functional-testing-of-the-provider
As one exampleCorey Maynard
10/03/2023, 1:19 PMCorey Maynard
10/03/2023, 1:20 PMCorey Maynard
10/03/2023, 1:24 PMCorey Maynard
10/03/2023, 1:35 PMMatt (pactflow.io / pact-js / pact-go)
Yeah, I definitely see how there would be ‘duplicate’ requests, even as you can see in my example from there would be two requests tothat might be straightforward for basic examples, but quickly gets hard - e.g. there might be different shaped payloads, or payloads with different keys that are enums etc., that are worth testing. It would be hard to de-duplicate these without being lossy. But yes, it’s plausible.- but that seems like something that could be resolved through an additive deduplication before the contract is generated/foo/bar/
I don’t fully understand the comment about states there either, the swagger document doesn’t provide explicit states in it so how would it match up anyways?
I also don’t follow what you’re saying about how using the swagger file resolves the problem?Correct. But we don’t need states when comparing consumer requests against the spec, so the problem about “too many” goes away, as it doesn’t create an additional burden on the provider API team. It’s only a problem if the validation happens in a Pact style (request-response) model, because the actual API call is made to the provider that needs to be able to respond accordingly - this is where the maintenance and alignment problem creeps in. See also this cautionary tale 👉 https://pactflow.io/blog/a-disastrous-tale-of-ui-testing-with-pact/
I’ve seen things talking about using cypress to generate a consumer’s contract...how is that any different from generating it via jest tests? both are functional things - cypress is driving a browser to do actions, jest is simulating a browserYou’re right - it’s not, but it’s (and the MSW, Wiremock and similarly others) not designed for use with Pact. It’s designed for use with the BDCT capability.
From the cypress side it seems like you’re assuming that it’s using network stubs: https://pactflow.io/blog/use-cypress-in-contract-testing/ - however for our product we are using cypress to test the whole stack (End to End testing). Therefore we’re not mocking out the cypress requests at all, and instead are performing the cypress testing on a full live server.If you’re doing that, then do you need contracts? You’re testing the real thing anyway? All you’re really doing there is recording what you know (this is a simplistic view of the situation, but I want to make sure you understand the value). The point of Pact is to avoid e2e tests where you can, replacing them with faster, lightweight and reliable tests that can be used in mulitple contexts - including in cypress tests.
Matt (pactflow.io / pact-js / pact-go)
• Consumer’s requests to the provider are embedded directly in the components that use themthis sounds like a bad practice to me, but React in general sounds like a bad practice to me trollparrot
Corey Maynard
10/04/2023, 6:53 PMMatt (pactflow.io / pact-js / pact-go)
I was hoping that by having the Jest tests generate a contract, and having the swagger file be a contractSo yes, you can do that, just not with Pact (the BDCT feature above would support it). You could by all means try if you think you can workaround those problems/limitations discussed - they aren’t insurmountable, but they are definitely something you’d need to handle