Git Product home page Git Product logo

pact-js's Introduction

Pact JS

Pact for all things Javascript.

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: we are currently in the process of replacing Pact Consumer JS DSL with this library. Please bare with us whilst we transition. If you want to use Pact with JS and are new to Pact, start here.

Installation

This package is not yet published to NPM so you will need to install it manually by modifying your package.json.

It's easy, simply add the line below to your devDependencies group...

"pact": "pact-foundation/pact-js"

... then run npm install and you are good to go.

Using Pact JS

Consumer Side Testing

The library provides a Verifier Service, Matchers and an API Interceptor:

Verifier Sets up a test double (Verifier Provider API) with expected interactions. It's also responsible for generating Pact files.

Matchers are functions you can use to increase the expressiveness of your tests, and reduce brittle test cases. See the matching docs for more information.

Interceptor is a utility that can be used to intercept requests to the Provider, where it's not simple for you to change your API endpoint.

To use the library on your tests, do as you would normally with any other dependency:

// ES6
import { default as Pact, Matchers, Interceptor } from 'pact-js'

// you have to new the Interceptor
// the others are just plain objects
const interceptor = new Interceptor()

// ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
// ES5
var Pact = require('pact-js')
var matchers = Pact.Matchers

// you have to new the Interceptor
var Interceptor = new Pact.Interceptor()

Then to write a test that will generate a Pact file, here's an example below - it uses Mocha. There's a bit going on in there as we are spinning up the Pact Verifier Service Provider to mock a real server on the provider server. This is needed because that's where we will record our interactions.

More questions about what's involved in Pact? Read more about it.

Check the examples folder for other examples.

import { expect } from 'chai'
import Promise from 'bluebird'

// import the Verifier so you write your pacts
import { default as Pact } from 'pact-js'
import request from 'superagent-bluebird-promise'

// great library to spin up the Pact Verifier Server
// that will record interactions and eventually validate your pacts
import wrapper from '@pact-foundation/pact-node'

describe('Pact', () => {

  // when using the wrapper, you will need to tell it where to store the logs
  // make sure you the folders created before hand
  const mockServer = wrapper.createServer({
    port: 1234,
    log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
    dir: path.resolve(process.cwd(), 'pacts'),
    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}
    ]
  }]

  var pact

  after(() => {
    wrapper.removeAllServers()
  });

  beforeEach((done) => {
    mockServer.start().then(() => {
      // in order to use the Verifier, simply pass an object like below
      // it should contain the names of the consumer and provider in normal language
      pact = Pact({ consumer: 'My Consumer', provider: 'My Provider' })
      done()
    })
  })

  afterEach((done) => {
    mockServer.delete().then(() => {
      done()
    })
  })

  context('with a single request', () => {
    it('successfully writes Pact file', (done) => {

      // the Verifier is Promise-based so make sure the function that is used
      // to invoke the endpoint returns a Promise
      // essentially this would be your client library in your source code
      // e.g.: client.requestProjects()
      function requestProjects () {
        return request.get('http://localhost:1234/projects').set({ 'Accept': 'application/json' })
      }

      // This is how you create an interaction
      pact
        .interaction()
        .given('i have a list of projects')
        .uponReceiving('a request for projects')
        .withRequest('get', '/projects', null, { 'Accept': 'application/json' })
        .willRespondWith(200, { 'Content-Type': 'application/json' }, EXPECTED_BODY)

      // and this is how the verification process invokes your request
      // and writes the Pact file if all is well, returning you the data of the request
      // so you can do your assertions
      pact.verify(requestProjects)
        .then((data) => {
          expect(JSON.parse(data)).to.eql(EXPECTED_BODY)
          done()
        })
        .catch((err) => {
          done(err)
        })
    })
  })
})

Provider API Testing

Once you have created Pacts for your Consumer, you need to validate those Pacts against your Provider.

First, install Pact Node:

npm install @pact-foundation/pact-node --save

Then run the Provider side verification step:

var pact = require('@pact-foundation/pact-node');
var 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
};

pact.verifyPacts(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.

var pact = require('@pact-foundation/pact-node');
var 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
};

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

Using Mocha?

Check out Pact JS Mocha.

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

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.