Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

payload changed by pact between consumer test and provider test #1210

Closed
5 tasks done
ajoanny opened this issue Apr 22, 2024 · 6 comments
Closed
5 tasks done

payload changed by pact between consumer test and provider test #1210

ajoanny opened this issue Apr 22, 2024 · 6 comments
Labels
awaiting feedback Awaiting Feedback from OP

Comments

@ajoanny
Copy link

ajoanny commented Apr 22, 2024

Thank you for reporting a bug! We appreciate it very much. Issues are a big input into the priorities for Pact-JS development

All italic text in this template is safe to remove before submitting

Thanks again!

Software versions

Please provide at least OS and version of pact-js

  • OS: MacOS Sonoma v14.4.1
  • Consumer Pact library: v14.3.3
  • Provider Pact library: v14.3.3
  • Node Version: v20.11.1

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

Hello !

Expected behaviour

When this request is defined in the consumer test

.withRequest('POST', '/api/test', (builder) => {
  builder.headers({
    'Content-Type': 'application/vnd.api+json',
  });
  builder.jsonBody({ data: { attributes: { name: 'name' } } });
})

Then the request body used in the provider test should be

  { data: { attributes: { name: 'name' } } }

Actual behaviour

The body used in the request for the provider is

{"body":{"type":"Buffer","data":[123,34,100,97,116,97,34,58,123,34,97,116,116,114,105,98,117,116,101,115,34,58,123,34,110,97,109,101,34,58,34,110,97,109,101,34,125,125,125]}

Steps to reproduce

Consumer test :

const provider = new PactV4({
  provider: 'provider',
  consumer: 'consumer',
  dir: path.resolve(process.cwd(), 'pacts'),
  spec: 4,
  logLevel: 'debug',
});

describe('POST /api/test', () => {
  it('send a request', () => {
    const body = { data: { attributes: { name: 'name' } } };
    return provider
      .addInteraction()
      .uponReceiving('json api content type')
      .withRequest('POST', '/api/test', (builder) => {
        builder.headers({
          'Content-Type': 'application/vnd.api+json',
        });
        builder.jsonBody(body);
      })
      .willRespondWith(200, () => {})
      .executeTest(async (mockserver) => {
        const response = await axios.request({
          baseURL: mockserver.url,
          headers: {
            'Content-Type': 'application/vnd.api+json',
          },
          method: 'POST',
          url: `/api/test`,
          data: body,
        });

        expect(response.status).toEqual(200);
      });
  });
});

Provider test:

describe('Order-API contracts in order that', () => {
  it('comply with consumers expectations', () => {
    return new Verifier({
      provider: 'provider',
      providerVersion: '1.0',
      providerBaseUrl: 'http://localhost:8080',
      pactBrokerUrl: getPactBrokerURL(),
      consumerVersionSelectors: [{ branch: 'fix/pact' }],
      publishVerificationResult: true,
      failIfNoPactsFound: false,
      enablePending: true,
      logLevel: 'debug',
    })
      .verifyProvider()
      .then(() => {
        console.log('Successfully verified Pact contracts!');
      });
  });
});

The request handler :

const schema = z.object({
  data: z.object({
    attributes: z.object({
      name: z.string(),
    }),
  }),
});

routes.post('/api/test', async (req, res) => {
  const result = schema.safeParse(req.body);
  if (result.success) {
    res.status(200).send();
  } else {
    res.status(400).send();
  }
});

I have a workaround which is to use the content-type 'application/json' to keep the body as it was defined in the consumer test. I dont know if it should be flagged as a bug, but it's really surprising that the request was not exactly the same on both side of participants.

If I have enough time today I'll use the template to create a repository to reproduce the behavior.

Have a nice day 👋🏽 !

Provide a Minimal, Reproducible Example. You can create your own repository, or use this template that's already hooked up to CI and everything.

Relevant log files

consumer-provider.json
provider.log
consumer.log

Please ensure you set logging to DEBUG and attach any relevant log files here (or link to a gist).

@ajoanny ajoanny added bug Indicates an unexpected problem or unintended behavior triage This issue is yet to be triaged by a maintainer labels Apr 22, 2024
@mefellows
Copy link
Member

This seems like a bug in the core. I'll investigate later and raise an upstream issue if that's the case.

It should be treated as a JSON media type.

Thanks for the detailed report.

@ajoanny
Copy link
Author

ajoanny commented Apr 22, 2024

Thanks a lot, if needed you can reproduce the behavior using this repository https://github.com/ajoanny/pact-issue-1210.

@mefellows
Copy link
Member

I think it is bug in Pact JS, as the CLI verifier was correctly returning string data

Likely in the proxy. Adding the custom type in there yields a change from:

[09:46:45.411] DEBUG (37365): [email protected]: incoming request: {"body":{"type":"Buffer","data":[123,34,100,97,116,97,34,58,123,34,97,116,116,114,105,98,117,116,101,115,34,58,123,34,110,97,109,101,34,58,34,110,97,109,101,34,125,125,125]},"headers":{"content-type":"application/vnd.api+json","accept":"*/*","accept-encoding":"gzip, deflate","host":"127.0.0.1:49895","content-length":"39"},"method":"POST","path":"/"}

to

[09:47:25.306] DEBUG (37590): [email protected]: incoming request: {"body":{"data":{"attributes":{"name":"name"}}},"headers":{"content-type":"application/vnd.api+json","accept":"*/*","accept-encoding":"gzip, deflate","host":"127.0.0.1:49901","content-length":"39"},"method":"POST","path":"/"}

I suspect the proxy is not writing the body back correctly, it may be as a result of #1199, possibly

buffer: Readable.from(parseBody(req)),
.

@mefellows mefellows removed the triage This issue is yet to be triaged by a maintainer label Apr 22, 2024
@mefellows
Copy link
Member

OK, I think the problem is in your express server. At least, the repro can be fixed by changing the express.json() usage to the following:

server.use(express.json({
  type: [
      'application/vnd.api+json', // uncomment to fix
  ],
}));

I've tested this on the latest Pact JS and it seems to work OK.

The bodyParser documentation referenced in express is not entirely clear on the behaviour, but I think the real issue is that +json types are not included by default. See this issue: expressjs/body-parser#519.

@mefellows mefellows added awaiting feedback Awaiting Feedback from OP and removed bug Indicates an unexpected problem or unintended behavior labels Apr 23, 2024
@ajoanny
Copy link
Author

ajoanny commented Apr 23, 2024

It works fine ! Thank you 🙏🏽 🙏🏽 🙏🏽 ! I will fix the code on my server.
Sorry for the inconvenience.

Have a nice day !
Thanks again for the quick reply !

@mefellows
Copy link
Member

No worries!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting feedback Awaiting Feedback from OP
Projects
None yet
Development

No branches or pull requests

2 participants