Giter Club home page Giter Club logo

nestjs-pact's Introduction

ISC license npm version Codecov Coverage CircleCI semantic-release

NestJS + Pact Logo

NestJS + Pact

Injectable Pact.js Consumer/Provider for NestJS

Table Of Contents

Installation

Pact-JS v10.x+ users

npm i -D nestjs-pact @pact-foundation/pact

Pact-JS v9.x users

npm i -D [email protected] @pact-foundation/[email protected]

Example

If you want to see a fully working end-to-end example with NestJS and Pact I recommend you to jump to the NestJS official examples at the PactJS Github repository

About

This package enables you to consume Pact.js in a way that can be used very easily in NestJS.
Like the nature of Pact, this package is for testing purposes only.

If you are not familiar with Pact, Pact is fast, easy and reliable testing framework for integrating web apps, APIs and microservices. Read more on Pact official website

There are two main modules suggested; one for the Provider role (Verifier), and one for the Consumer role (creating Pact files and publish), each loaded separately. Of course, you can also use both modules and play the role of Consumer and Provider at the same time.

Introduction

The use of each of the modules suggested here, is made in the common and accepted form of NestJS modules. The simplest way is to use the register method and pass the settings directly. It is also enable to use the registerAsync method to pass the settings in the form of useFactory or useClass for example.

One more thing - the usage of the modules is for testing purposes only, which is not quite common in the use of NestJS modules, so there are some good examples down below. The obvious advantage of this package is that Pact can be used in combination with the techniques and benefits offered by NestJS.

Consumer

In order to use the Consumer module, you need to follow a few simple steps, let's go over it!

First, create a file called pact.module.ts in your test folder (or wherever you put your tests), and simply load the PactConsumerModule like below:

test/pact/pact.module.ts

import { Module } from '@nestjs/common';
import { PactConsumerModule } from 'nestjs-pact';

@Module({
  imports: [
    PactConsumerModule.register({ ... }),
  ],
})
export class PactModule {}

Yay, now let's create the test file! let's call it my-test.spec.ts

test/pact/my-test.spec.ts

import { Pact } from '@pact-foundation/pact';
import { Test } from '@nestjs/testing';
import { PactFactory } from 'nestjs-pact';
import { PactModule } from '@test/pact/pact.module';

describe('Pact', () => {
  let pactFactory: PactFactory;
  let provider: Pact;

  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      imports: [SomeOtherModule, AndAnotherModuleYouNeed, PactModule],
    }).compile();

    pactFactory = moduleRef.get(PactFactory);

    provider = pactFactory.createContractBetween({
      consumer: 'Consumer Service Name',
      provider: 'Provider Service Name',
    });

    await provider.setup();
  });

  afterEach(() => provider.verify());

  afterAll(() => provider.finalize());

  describe('when something happens', () => {
    describe('and another thing happens too', () => {
      beforeAll(() => provider.addInteraction({ ... }));

      it('should do something', () => {
        return expect( ... );
      });
    });
  });
});

Now let's look how we can publish the pacts created from the test file to a Pact broker!

test/pact/publish-pacts.ts

import { NestFactory } from '@nestjs/core';
import { Logger, LoggerService } from '@nestjs/common';
import { Publisher } from '@pact-foundation/pact';
import { PactModuleProviders } from 'nestjs-pact';
import { PactModule } from '@test/pact/pact.module';

(async () => {
  const app = await NestFactory.createApplicationContext(PactModule);

  const publisher: Publisher = app.get(PactModuleProviders.PactPublisher);
  const logger: LoggerService = app.get(Logger);

  if (process.env.CI !== 'true') {
    logger.log('Skipping Pact publish as not on CI');
    process.exit(0);
  }

  try {
    await publisher.publishPacts();

    logger.log('Pact contract publishing complete!');
    logger.log('');
    logger.log('Head over to https://test.pact.dius.com.au/ and login with');
    logger.log('=> Username: dXfltyFMgNOFZAxr8io9wJ37iUpY42M');
    logger.log('=> Password: O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1');
    logger.log('to see your published contracts.');
  } catch (e) {
    logger.error('Pact contract publishing failed: ', e);
  }
})();

npx ts-node test/pact/publish-pacts.ts

Run the file and you are good to go :)

Note: in your tsconfig.json file make sure you set allowJs to true in order to run the file

Provider

The usage in the Provider service is quite easy; In your /test folder (or wherever you put your tests) create a simple test module with NestJS Test.createTestingModule method and import the PactProviderModule module from nestjs-pact.

You can use register or registerAsync method, make sure you stick to PactProviderOptions interface options.
After creating the Nest application from the testing module, pass the app instance to the verify method, it will generate a random (available) port, spin up the application and run the verifier against the application url.

You can read more about Pact Verification in the official Pact documentation

Here is a quick and simple example:

import { Test } from '@nestjs/testing';
import { INestApplication, Logger, LoggerService } from '@nestjs/common';
import { PactProviderModule, PactVerifierService } from 'nestjs-pact';
import { AppModule } from '@app/app.module';

describe('Pact Verification', () => {
  let verifierService: PactVerifierService;
  let logger: LoggerService;
  let app: INestApplication;

  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      imports: [AppModule, PactProviderModule.register({ ... })],
    }).compile();

    verifierService = moduleRef.get(PactVerifierService);
    logger = moduleRef.get(Logger);

    app = moduleRef.createNestApplication();

    await app.init();
  });

  it('validates the expectations of Matching Service', async () => {
    const { output } = await verifierService.verify(app);

    logger.log('Pact Verification Completed!');
    logger.log(output);
  });

  afterAll(async () => {
    await app.close();
  });
});

License

Distributed under the MIT License. See LICENSE for more information.

Acknowledgements

nestjs-pact's People

Contributors

lennartquerter avatar omermorad avatar dependabot[bot] avatar you54f avatar semantic-release-bot avatar omer-morad-ni avatar bewatts avatar joffraybillon avatar timothyjones avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.