pact-foundation / pact-js

JS version of Pact. Pact is a contract testing framework for HTTP APIs and non-HTTP asynchronous messaging systems.
https://pact.io
Other
1.64k stars 349 forks source link

Typescript: inconsistent typings for MessageProviderPact #396

Closed maze-le closed 3 years ago

maze-le commented 4 years ago

Software versions

Expected behaviour

The typings for the property: consumer in a MessageProviderOptions object should be optional. It actually works, if I trick the typescript-processor to ignore the type of the MessageProviderOptions object.

Actual behaviour

The property: consumer in a MessageProviderOptions object, used to initialize a MessageProviderPact is not optional. But I have a Provider that communicates with different Consumers. In this case, I would like to omit the consumer property, and define my handlers without specifying a concrete consumer.

Steps to reproduce

import { MessageProviderPact } from "@pact-foundation/pact";

describe("Provider Tests", () => {
  let taskmanagerPact: MessageProviderPact;

  // a mail request for one of our backend services
  const mailRequest: unknown = {
    type: "mail:send",
    props: {
      from: "lalala@example.com",
      to: "ohmy@example.com",
      subject: "Complete Registration",
      profile: "COMPLETE_REGISTRATION"
    }
  };

  describe("Mailer", () => {
    beforeAll(() => {
      const mailSendHandler = () => Promise.resolve(mailRequest);
      const otherHandler = () => Promise.resolve({ example: true });

      taskmanagerPact: = new MessageProviderPact({
        // consumer: "Mailer"    // this property should be optional!
        provider: "Taskmanager",
        messageProviders: {
          "a valid mail request": () => mailSendHandler(),
          "another request for a different consumer": () => otherHandler()
        },
        logLevel: "debug",
        pactBrokerUrl: "https://our-local-broker.example.com/",
        publishVerificationResult: true,
        pactBrokerUsername: "admin",
        pactBrokerPassword: "-secret-", // this is an example...
        providerVersion: `1.1.0-22`
      });
    });

    it("verifies the sent mail", async () => {
      await taskmanagerPact.verify();
    });
  });
});

This gives me the following error when I try to run the test with jest/ts-node:

  ● Test suite failed to run

    TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
    test/integr/Example.test.ts:22:44 - error TS2345: Argument of type '{ provider: string; messageProviders: { "a valid mail request": () => Promise<unknown>; "another request for a different consumer": () => Promise<{ example: boolean; }>; }; logLevel: "debug"; ... 4 more ...; providerVersion: string; }' is not assignable to parameter of type 'MessageProviderOptions'.
      Property 'consumer' is missing in type '{ provider: string; messageProviders: { "a valid mail request": () => Promise<unknown>; "another request for a different consumer": () => Promise<{ example: boolean; }>; }; logLevel: "debug"; ... 4 more ...; providerVersion: string; }' but required in type 'MessageProviderOptions'.

     22       mailerPact = new MessageProviderPact({
                                                   ~
     23         // consumer: "Mailer",
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ... 
     34         providerVersion: `1.1.0-22`
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     35       });
        ~~~~~~~

      node_modules/@pact-foundation/pact/dsl/options.d.ts:30:5
        30     consumer: string;
               ~~~~~~~~
        'consumer' is declared here.

Interestingly, I can trick typescript into accepting the options object without the consumer property, by coercing the object as top-type <any> and it works:

      // (...)
      taskmanagerPact: = new MessageProviderPact({
        // consumer: "Mailer"    // this property should be optional!
        provider: "Taskmanager",
        messageProviders: {
          "a valid mail request": () => mailSendHandler(),
          "another request for a different consumer": () => otherHandler()
        },
        logLevel: "debug",
        pactBrokerUrl: "https://our-local-broker.example.com/",
        publishVerificationResult: true,
        pactBrokerUsername: "admin",
        pactBrokerPassword: "-secret-", // this is an example...
        providerVersion: `1.1.0-22`
      } as any);
      // (...)

It would be very nice, if the type of the MessageProviderOptions object would reflect that behaviour, so I don't have to trick the typescript-processor into accepting it anyway.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

mefellows commented 4 years ago

This will be fixed in #437 .

TimothyJones commented 3 years ago

@mefellows That PR was merged, can this be closed?

mefellows commented 3 years ago

Yep, I guess so!