Hi all, I really like the idea of contract testing...
# pact-js
s
Hi all, I really like the idea of contract testing the microservices and I am trying to introduce this in our organisation. But I have hit a problem where the request made by the consumer is just flagged incorrect without much explanation. Please refer the test execution logs below. I can't see why this request is incorrect. If you think following log is not enough to debug it I am happy to share more context and the test code. I am using
"@pact-foundation/pact": "^12.1.0",
and
PactV3
Can someone please help me resolve this issue ?
Copy code
 ~/Documents/projects/squiz/dxp-console/ [feat/quality-47*] npm run test:pact

> dxp-console@0.1.0 test:pact
> jest --config=jest.pact.config.ts
      at Object.<anonymous> (apps/component-service/src/Services/component/src/contract-test/helpers/ComponentProvider.ts:8:9)


  console.log
    MOCK SERVER URL => <http://127.0.0.1:8081>

      at apps/component-service/src/Services/component/src/contract-test/ComponentServiceConsumer.spec.ts:80:17


 RUNS  apps/component-service/src/Services/component/src/contract-test/ComponentServiceConsumer.spec.ts
2023-09-04T02:23:57.073080Z  INFO tokio-runtime-worker pact_mock_server::hyper_server: Received request OPTIONS /__dxp/au/components-management/dx-team-uat-6287/v1/component-set
2023-09-04T02:23:57.073488Z  INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: GET, path: /__dxp/au/components-management/dx-team-uat-6287/v1/component-set, query: Some({"sort[]": ["displayName"], "page": ["1"]}), headers: Some({"origin": ["<http://localhost>"], "accept": ["*/*"], "accept-language": ["en"], "user-agent": ["Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML", "like Gecko) jsdom/20.0.3"], "connection": ["keep-alive"], "content-type": ["application/json"], "x-requested-with": ["XMLHttpRequest"], "accept-encoding": ["gzip", "deflate"], "host": ["localhost:8081"], "referer": ["<http://locahost/>"]}), body: Missing )
2023-09-04T02:23:57.075548Z  INFO tokio-runtime-worker pact_mock_server::hyper_server: Responding to CORS pre-flight request
2023-09-04T02:23:57.076940Z  INFO tokio-runtime-worker pact_mock_server::hyper_server: Received request GET /__dxp/au/components-management/dx-team-uat-6287/v1/component-set
2023-09-04T02:23:57.076963Z  INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: GET, path: /__dxp/au/components-management/dx-team-uat-6287/v1/component-set, query: Some({"sort[]": ["displayName"], "page": ["1"]}), headers: Some({"origin": ["<http://localhost>"], "accept": ["*/*"], "accept-language": ["en"], "user-agent": ["Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML", "like Gecko) jsdom/20.0.3"], "connection": ["keep-alive"], "content-type": ["application/json"], "x-requested-with": ["XMLHttpRequest"], "accept-encoding": ["gzip", "deflate"], "host": ["localhost:8081"], "referer": ["<http://locahost/>"]}), body: Missing )
[12:23:57.079] ERROR (29361): pact@12.1.0: Test failed for the following reasons:

  Mock server failed with the following mismatches:

	0) The following request was incorrect:

            	GET /__dxp/au/components-management/dx-team-uat-6287/v1/component-set
 FAIL  apps/component-service/src/Services/component/src/contract-test/ComponentServiceConsumer.spec.ts
  Pact with Component/Management API - Consumer (DXP-Console) Test
    GET /component-set
      ✕ returns an HTTP 200 and a list of component sets (29 ms)

  ● Pact with Component/Management API - Consumer (DXP-Console) Test › GET /component-set › returns an HTTP 200 and a list of component sets
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        5.041 s
Ran all test suites.
t
Can you post your test code? It should be failing with details
Also, those log messages don't look right at all
I'm not sure where they're coming from
Looks like some pact internals that shouldn't be showing up
👀 1
s
my test code goes something like this
Copy code
import { PactV3 as Pact } from '@pact-foundation/pact';
import path from 'path';

const port = 8081;
export const componentProvider = new Pact({
  consumer: 'dxp-console',
  cors: true,
  dir: path.resolve(process.cwd(), 'apps/component-service/src/Services/component/contract-test/pacts'),
  logLevel: 'info',
  port: port,
  provider: 'component-service',
});


describe('Pact with Component/Management API - Consumer (DXP-Console) Test', () => {
  describe('GET /component-set', () => {
    beforeAll(async () => {
      componentProvider
        .given('I have a component set')
        .uponReceiving('a request for all component sets')
        .withRequest({
          method: 'GET',
          path: '/__dxp/au/components-management/dx-team-uat-6287/v1/component-set',
          query: {
            page: '1',
            'sort[]': ['displayName'],
          },
          headers: {
            'accept': '*/*',
            'accept-encoding': 'gzip, deflate',
            'accept-language': 'en',
            'content-type': 'application/json',
            'connection': 'keep-alive',
            'host': 'localhost:8081',
            'origin': '<http://localhost>',
            'referer': '<http://locahost/>',
            'user-agent': 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/20.0.3',
            'x-requested-with': 'XMLHttpRequest',
          },
        })
        .willRespondWith({
          status: 200,
          headers: {
            'Content-Type': 'application/json; charset=utf-8',
          },
          body: GET_COMPONENT_SET_EXPECTED_RESPONSE,
        });
    });

    it('returns an HTTP 200 and a list of component sets', async () => {

      await componentProvider.executeTest(async (mockserver) => {
        console.log("MOCK SERVER URL => " + mockserver.url);
        const componentServiceConfig: ComponentServiceConfiguration = {
          ...mockBaseServiceConfiguration,
          baseUrl: mockserver.url + '/__dxp/au/components-management/dx-team-uat-6287/v1/component-set',
          sessionUrl: '<http://localhost:8081/__dxp/au/components-management/dx-team-uat-6287>',
        };
        componentServiceConfig.httpService = newHttpService;
        const componentService = new ComponentService(componentServiceConfig);
        const response = await lastValueFrom(componentService.getComponentSet(dto));
        //Assert
        expect(response).toEqual(GET_COMPONENT_SET_EXPECTED_RESPONSE);
      });
    });
  });
});
t
The line that says
sessionUrl: '<http://localhost:8081/>
looks suspicious
should that be
mockserver.url
?
Also, is your
baseUrl
correct? Usually it would just be
mockserver.url
, and your API code would know the path
☝️ 1
s
yes correct. That was an oversight. I fixed it to be like this. But that URL is purely provided because of some URL logic in our app.
Copy code
const componentServiceConfig: ComponentServiceConfiguration = {
          ...mockBaseServiceConfiguration,
          baseUrl: mockserver.url + '/__dxp/au/components-management/dx-team-uat-6287/v1/component-set',
          sessionUrl: mockserver.url + '/__dxp/au/components-management/dx-team-uat-6287',
        };
It still fails with the same error
Copy code
[14:26:20.038] ERROR (35262): pact@12.1.0: Test failed for the following reasons:

  Mock server failed with the following mismatches:

	0) The following request was incorrect:

            	GET /__dxp/au/components-management/dx-team-uat-6287/v1/component-set
 FAIL  apps/component-service/src/Services/component/src/contract-test/ComponentServiceConsumer.spec.ts
  Pact with Component/Management API - Consumer (DXP-Console) Test
    GET /component-set
      ✕ returns an HTTP 200 and a list of component sets (27 ms)

  ● Pact with Component/Management API - Consumer (DXP-Console) Test › GET /component-set › returns an HTTP 200 and a list of component sets
t
My guess is this is a bug @Matt (pactflow.io / pact-js / pact-go) - probably this code doesn't do the right thing: https://github.com/pact-foundation/pact-js/blob/ce5973cd6864e7b85c44468553ea6f94e8e34d3f/src/v3/display.ts#L141
Also, those info messages shouldn't be being printed. I fixed that ages ago, looks like it has been unfixed.
This line should be something like
Copy code
return `Unknown mismatch data: ${mismatch}`
(that might not be the problem, of course)
Anyway, I think this is a bug. It's hard to ask you to open a bug report if you don't know what the actual problem is, but, I would confirm that you really are sending the request that you're expecting to send
you can do this by setting the log level to debug, and confirming that the query parameters and headers really are what you say they are
☝️ 1
s
thanks a lot for taking time to analyze this @Timothy Jones. some deductive reasoning exposed a header that was the problem. I have removed it now and the test seems to pass. But yes, It would be nice if Pact error could point me to the wrong header.
💪 1
t
Can you open a bug report on the pact js repo? I’m not a maintainer any more, otherwise I’d do it for you
s
Yes I am happy to do it. Just to confirm the problem here is it safe to say =>
Pact doesn't display the matcher errors when actual and expected requests are different.
?
t
Yep
Well, in this case it’s to do with header mismatches
So that’s (at least) the problem
And the example with your specific header is useful - maybe there’s something about it
👍 1
s
Also I didn't understand your comment about INFO messages. I had log level set to
info
. Is that why its showing up?
t
No, it's for the maintainers. The core logs aren't supposed to show when log level is set to info
👍 1
m
hmm that log level at INFO looks suspicious indeed. I’m wondering if a config has changed somewhere.
In any case, if you could please raise a bug here that would be ace. There are at least 2 issues:
👍 1
1. log levels incorrect (INFO when they should be DEBUG or TRACE) 2. Not printing a helpful error in the case the client can’t determine the problem
👍 1
s
Sure @Matt (pactflow.io / pact-js / pact-go), let me raise the bugs 🐛 🙌
thankyou 1
m
Amazing, thank you!
👍 1
s
🙌 1