3

I am trying to use Pact in my Angular 13 workspace with Jest for writing contract tests. I am using latest version of Pact which is v10.4.1.

However, I am running into problems related to Mock Server. It seems that Mock Server is not receiving any requests. I have added multiple debug logs to check which URL is used by Angular's HttpClient and it appears to point correctly to Mock Server's dynamic URL. See this -

console.log
**** Adding Interaction with path: /users/1
  at src/app/services/user.service.pact.spec.ts:44:15

console.log
**** MockServer:: URL: http://127.0.0.1:50118, ID: unknown
  at src/app/services/user.service.pact.spec.ts:65:17

console.log
**** UserService.get(): http://127.0.0.1:50118/users/1
  at UserService.get (src/app/services/user.service.ts:29:13)

From above -

  • Mock Server is running at http://127.0.0.1:50118.
  • Has one interaction registered with path as /users/1.
  • And Client is making http request to http://127.0.0.1:50118/users/1.

But still it's not working.

Also, I am not sure why Mock Server Id is coming out as "undefined".

Error I get is as below -

RUNS  src/app/services/user.service.pact.spec.ts
2023-02-08T10:33:00.360413Z DEBUG ThreadId(01) pact_matching::metrics: Could not get the tokio runtime, will not send metrics - there is no reactor running, must be called from the context of a Tokio 1.x runtime
2023-02-08T10:33:00.360795Z DEBUG ThreadId(01) pact_mock_server::server_manager: Shutting down mock server with ID ca85dcf4-01b7-4d4e-af7a-890baaa75559 - MockServerMetrics { requests: 0 }
2023-02-08T10:33:00.363789Z DEBUG ThreadId(01) pact_mock_server::mock_server: Mock server ca85dcf4-01b7-4d4e-af7a-890baaa75559 shutdown - MockServerMetrics { request  console.error
    Unhandled Promise rejection: Test failed for the following reasons:

      Mock server failed with the following mismatches:

        0) The following request was expected but not received:
            Method: GET
            Path: /users/1 ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: Test failed for the following reasons:

      Mock server failed with the following mismatches:

        0) The following request was expected but not received:
            Method: GET
            Path: /users/1
        at PactV3.<anonymous> (C:\angular-pact\node_modules\@pact-foundation\src\v3\pact.ts:227:29)
        at step (C:\angular-pact\node_modules\@pact-foundation\pact\src\v3\pact.js:33:23)
        at Object.next (C:\angular-pact\node_modules\@pact-foundation\pact\src\v3\pact.js:14:53)
        at fulfilled (C:\angular-pact\node_modules\@pact-foundation\pact\src\v3\pact.js:5:58)
        at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (C:\angular-pact\node_modules\zone.js\bundles\zone-testing-bundle.umd.js:409:30)

May be I am missing something very trivial/basic, I would really appreciate if you have any clue / suggestion on what might be wrong in my project?

I have uploaded my Angular project to GitHub here, where this is reproducible. (After cloning, command to run is npm run test:pact).

  • @matthew-fellows - Can I please bring in your attention to this issue? I would really appreciate if you can look into this soon. Thanks. – Subodh Godbole Feb 13 '23 at 08:55

1 Answers1

0

There are two problems here:

  1. Your executeTest callback is completing before the request has been sent. (When the Promise from the callback you passed to executeTest resolves, Pact expects you to have sent the request). To fix this, you need to not resolve your callback until you have sent the request.

  2. The use of done inside that test callback is not waiting for Pact to run its test (which means that the test will incorrectly pass if/when it is actually failing). To fix this, you must await or return the provider.executeTest(...) call.

I don't know angular, but changing your test from:

    it('should get a User', (done) => {
      provider.executeTest(async(mockServer) => {
        console.log(`**** MockServer:: URL: ${mockServer.url}, ID: ${mockServer.id}`);
        service.setUrlPrefix(mockServer.url);

        service.get(userId).subscribe({
          next: (response) => {
            console.debug(response);
            expect(response).toEqual(expectedUser);
            done();
          },
          error: (error: HttpErrorResponse)=> {
            done();
          }
        });
      });
    });

to:

    it('should get a User', () => {
      return provider.executeTest(async (mockServer) => {
        console.log(
          `**** MockServer:: URL: ${mockServer.url}, ID: ${mockServer.id}`
        );
        service.setUrlPrefix(mockServer.url);

        return new Promise<void>((resolve, reject) => {
          service.get(userId).subscribe({
            next: (response) => {
              console.debug(response);
              expect(response).toEqual(expectedUser);
              resolve();
            },
            error: (error: HttpErrorResponse) => {
              reject(error);
            },
          });
        });
      });
    });

will at least fix it. Of course, there might be a more idiomatic way to wait for the request in Angular.

Timothy Jones
  • 21,495
  • 6
  • 60
  • 90