Giter Club home page Giter Club logo

pact-js's Introduction

Pact JS

Join the chat at https://gitter.im/realestate-com-au/pact

Build Status Code Climate Coverage Status Issue Count npm

Implementation of the consumer driven contract library Pact for Javascript.

From the Pact website:

The Pact family of frameworks provide support for Consumer Driven Contracts testing.

A Contract is a collection of agreements between a client (Consumer) and an API (Provider) that describes the interactions that can take place between them.

Consumer Driven Contracts is a pattern that drives the development of the Provider from its Consumers point of view.

Pact is a testing tool that guarantees those Contracts are satisfied.

Read Getting started with Pact for more information on how to get going.

NOTE: This project supersedes Pact Consumer JS DSL.

Installation

It's easy, simply run the below:

npm install --save-dev pact

Using Pact JS

Using Mocha?

Check out Pact JS Mocha.

Consumer Side Testing

To use the library on your tests, add the pact dependency:

let Pact = require('pact')

The Pact interface provides the following high-level APIs, they are listed in the order in which they typically get called in the lifecycle of testing a consumer:

API

API Options Returns Description
pact(options) See Pact Node documentation for options Object Creates a Mock Server test double of your Provider API. If you need multiple Providers for a scenario, you can create as many as these as you need.
setup() n/a Promise Start the Mock Server
addInteraction() Object Promise Register an expectation on the Mock Server, which must be called by your test case(s). You can add multiple interactions per server. These will be validated and written to a pact if successful.
verify() n/a Promise Verifies that all interactions specified
finalize() n/a Promise Records the interactions registered to the Mock Server into the pact file and shuts it down.
removeInteractions n/a Promise In some cases you might want to clear out the expectations of the Mock Service, call this to clear out any expectations for the next test run. NOTE: verify() will implicitly call this.

Example

The first step is to create a test for your API Consumer. The example below uses Mocha, and demonstrates the basic approach:

  1. Create the Pact object
  2. Start the Mock Provider that will stand in for your actual Provider
  3. Add the interactions you expect your consumer code to make when executing the tests
  4. Write your tests - the important thing here is that you test the outbound collaborating function which calls the Provider, and not just issue raw http requests to the Provider. This ensures you are testing your actual running code, just like you would in any other unit test, and that the tests will always remain up to date with what your consumer is doing.
  5. Validate the expected interactions were made between your consumer and the Mock Service
  6. Generate the pact(s)

Check out the examples folder for examples with Karma Jasmine, Mocha and Jest. The example below is taken from the integration spec.

let path = require('path')
let chai = require('chai')
let pact = require('pact')
let request = require ('superagent')
let chaiAsPromised = require('chai-as-promised')

let expect = chai.expect

chai.use(chaiAsPromised);

describe('Pact', () => {

  // (1) Create the Pact object to represent your provider
  const provider = pact({
    consumer: 'TodoApp',
    provider: 'TodoService',,
    port: MOCK_SERVER_PORT,
    log: path.resolve(process.cwd(), 'logs', 'pact.log'),
    dir: path.resolve(process.cwd(), 'pacts'),
    logLevel: 'INFO',
    spec: 2
  });

  // this is the response you expect from your Provider
  const EXPECTED_BODY = [{
    id: 1,
    name: 'Project 1',
    due: '2016-02-11T09:46:56.023Z',
    tasks: [
      {id: 1, name: 'Do the laundry', 'done': true},
      {id: 2, name: 'Do the dishes', 'done': false},
      {id: 3, name: 'Do the backyard', 'done': false},
      {id: 4, name: 'Do nothing', 'done': false}
    ]
  }]

  context('when there are a list of projects', () => {
    describe('and there is a valid user session', () => {

      before((done) => {
        // (2) Start the mock server
        provider.setup()
          // (3) add interactions to the Mock Server, as many as required
          .then(() => {
            provider.addInteraction({
              state: 'i have a list of projects',
              uponReceiving: 'a request for projects',
              withRequest: {
                method: 'GET',
                path: '/projects',
                headers: { 'Accept': 'application/json' }
              },
              willRespondWith: {
                status: 200,
                headers: { 'Content-Type': 'application/json' },
                body: EXPECTED_BODY
              }
            })
          })
          .then(() => done())
        })

      // (4) write your test(s)
      it('should generate a list of TODOs for the main screen', (done) => {
        const todoApp = new TodoApp();
        const projects = todoApp.getProjects() // <- this method would make the remote http call
        expect(projects).to.eventually.be.a('array')
        expect(projects).to.eventually.have.deep.property('projects[0].id', 1).notify(done)
      })

      // (5) validate the interactions occurred, this will throw an error if it fails telling you what went wrong
      it('creates a contract between the TodoApp and TodoService', () => {
        return pact.verify()
      })
    })
  });

  // (6) write the pact file for this consumer-provider pair,
  // and shutdown the associated mock server.
  // You should do this only _once_ per Provider you are testing.
  after(() => {
    provider.finalize()
  });  
})

Provider API Testing

Once you have created Pacts for your Consumer, you need to validate those Pacts against your Provider. The Verifier object provides the following API for you to do so:

API Options Returns Description
verifyProvider() n/a Promise Start the Mock Server
  1. Start your local Provider service.
  2. Optionally, instrument your API with ability to configure provider states
  3. Then run the Provider side verification step
const verifier = require('pact').Verifier;
let opts = {
	providerBaseUrl: <String>,       // Running API provider host endpoint. Required.
	pactUrls: <Array>,               // Array of local Pact file paths or Pact Broker URLs (http based). Required.
	providerStatesUrl: <String>,     // URL to fetch the provider states for the given provider API. Optional.
	providerStatesSetupUrl <String>, // URL to send PUT requests to setup a given provider state. Optional.
	pactBrokerUsername: <String>,    // Username for Pact Broker basic authentication. Optional
	pactBrokerPassword: <String>,    // Password for Pact Broker basic authentication. Optional
  timeout: <Number>                // The duration in ms we should wait to confirm verification process was successful. Defaults to 30000, Optional.
};

verifier.verifyProvider(opts)).then(function () {
	// do something
});

That's it! Read more about Verifying Pacts.

Publishing Pacts to a Broker

Sharing is caring - to simplify sharing Pacts between Consumers and Providers, checkout sharing pacts using the Pact Broker.

let pact = require('@pact-foundation/pact-node');
let opts = {
	pactUrls: <Array>,               // Array of local Pact files or directories containing them. Required.
	pactBroker: <String>,            // URL to fetch the provider states for the given provider API. Optional.
	pactBrokerUsername: <String>,    // Username for Pact Broker basic authentication. Optional
	pactBrokerPassword: <String>,    // Password for Pact Broker basic authentication. Optional
	consumerVersion: <String>        // A string containing a semver-style version e.g. 1.0.0. Required.  
};

pact.publishPacts(opts)).then(function () {
	// do something
});

Examples

Note on Jest

Jest uses JSDOM under the hood which may cause issues with libraries making HTTP request. See this issue for background, and the Jest example for a working solution.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

If you would like to implement Pact in another language, please check out the Pact specification and have a chat to one of us on the pact-dev Google group.

The vision is to have a compatible Pact implementation in all the commonly used languages, your help would be greatly appreciated!

Contact

pact-js's People

Contributors

tarciosaraiva avatar mefellows avatar sk1talets avatar jcarlos avatar

Watchers

Nicolas ROGER 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.