Request validation fails after upgrade to v12
pieter-stek opened this issue ยท 6 comments
Software versions
- OS: Windows 11
- Consumer Pact library: PactJS 12.1.0
- Provider Pact library: au.com.dius.pact.provider:junit5:4.6.1
- Node Version: 16.18.0
Issue Checklist
Please confirm the following:
- I have upgraded to the latest
- I have the read the FAQs in the Readme
- I have triple checked, that there are no unhandled promises in my code and have read the section on intermittent test failures
- I have set my log level to debug and attached a log file showing the complete request/response cycle
- For bonus points and virtual high fives, I have created a reproduceable git repository (see below) to illustrate the problem
Expected behaviour
I updated PactJS from 11.0.2 to 12.1.0 and without any other changes the contract test started failing.
Actual behaviour
Mock server failed with the following mismatches:
0) The following request was incorrect:
PUT /picking-capacity/capacities/1
'Content-Type': Expected value 'application/json' at index 1 but was missing
Steps to reproduce
import { PactV3 } from "@pact-foundation/pact";
import axios from "axios";
import path from "path";
const provider = new PactV3({
port: 8082,
dir: path.resolve(process.cwd(), "pacts"),
cors: true,
pactfileWriteMode: "update",
consumer: "application",
provider: "applicationApi",
logLevel: "debug",
});
describe("serviceUnderTest", () => {
it("should validate PUT request", async () => {
await provider.addInteraction({
states: [{ description: "resource exists" }],
uponReceiving: "update",
withRequest: {
method: "PUT",
path: "/resource/1",
headers: {
"Content-Type": "application/json",
},
body: {},
},
willRespondWith: {
status: 200,
headers: {
"Content-Type": "application/json",
},
body: {},
},
});
await provider.executeTest(async () => {
await axios.put("http://localhost:8082/resource/1", {});
});
});
})
Relevant log files
It looks like the core is expecting two headers, as can be seen by it expecting it at index 1 (not index 0, for 1 value for content-type
header)
It received the right request:
2023-07-27T12:05:59.358269Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Creating pact request from hyper request
2023-07-27T12:05:59.358285Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Extracting query from uri /resource/1
2023-07-27T12:05:59.358364Z INFO tokio-runtime-worker pact_mock_server::hyper_server: Received request PUT /resource/1
2023-07-27T12:05:59.358373Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server:
----------------------------------------------------------------------------------------
method: PUT
path: /resource/1
query: None
headers: Some({"host": ["localhost:8082"], "user-agent": ["axios/1.4.0"], "connection": ["keep-alive"], "accept": ["application/json", "text/plain", "*/*"], "content-length": ["8"], "content-type": ["application/json"], "accept-encoding": ["gzip", "compress", "deflate", "br"]})
body: Present(8 bytes, application/json) '{"id":1}'
----------------------------------------------------------------------------------------
But you can see it's expecting two:
2023-07-27T12:04:10.904720Z INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: PUT, path: /resource/1, query: None, headers: Some({"Content-Type": ["application/json", "application/json"]}), body: Present(8 bytes, application/json) )
It works in v0.4.5
of libpact_ffi
so something between that and v0.4.6
is causing it. I'll continue to investigate.
I've traced it to this commit. I'll raise this issue upstream to track it, thanks for reporting.
See our documentation for more information.
I should say, in this case, I think because the Content-Type
is a special header and it's defaulting to application/json
(possibly why it's expecting two header values) you can simply omit that header from your expectations and things will work. It doesn't seem to affect other headers, which strengthens that theory. This test for example should work:
import { PactV3 } from '@pact-foundation/pact';
import axios from 'axios';
import path from 'path';
const provider = new PactV3({
port: 8082,
dir: path.resolve(process.cwd(), 'pacts'),
cors: true,
consumer: 'application',
provider: 'applicationApi',
logLevel: 'debug',
});
describe('serviceUnderTest', () => {
it('should validate PUT request', async () => {
await provider.addInteraction({
states: [{ description: 'resource exists' }],
uponReceiving: 'update',
withRequest: {
method: 'PUT',
path: '/resource/1',
headers: {
Foo: 'bar',
},
body: {
id: 1,
},
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: {
id: 1,
},
},
});
await provider.executeTest(async () => {
await axios.put(
'http://localhost:8082/resource/1',
{
id: 1,
},
{
headers: {
Foo: 'bar',
},
}
);
});
});
});
I can confirm that if I omit the Content-Type
header from the request expectation, the test succeeds. The corresponding provider tests also still succeed if I do that.
Thanks for confirming.