Pact JS
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
It's easy, simply run the below:
npm install --save-dev pact
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:
import { default as Pact, Matchers, Interceptor } from 'pact-js'
const interceptor = new Interceptor()
var Pact = require('pact-js')
var matchers = Pact.Matchers
matchers.term()
matchers.somethingLike()
matchers.eachLike()
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 examples with Karma Jasmine / Mocha. The example below is taken from the integration spec.
import path from 'path'
import { expect } from 'chai'
import Promise from 'bluebird'
import request from 'superagent'
import wrapper from '@pact-foundation/pact-node'
import { default as Pact } from 'pact'
import wrapper from '@pact-foundation/pact-node'
describe('Pact', () => {
const mockServer = wrapper.createServer({
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2
})
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 provider
after(() => {
wrapper.removeAllServers()
});
beforeEach((done) => {
mockServer.start().then(() => {
provider = Pact({ consumer: 'My Consumer', provider: 'My Provider', port: 1234 })
done()
})
})
afterEach((done) => {
mockServer.delete().then(() => {
done()
})
})
context('with a single request', () => {
it('successfully writes Pact file', (done) => {
beforeEach((done) => {
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())
})
afterEach((done) => {
provider.finalize().then(() => done())
})
it('successfully verifies', (done) => {
const verificationPromise = request
.get('http://localhost:1234/projects')
.set({ 'Accept': 'application/json' })
.then(provider.verify)
expect(verificationPromise).to.eventually.eql(JSON.stringify(EXPECTED_BODY)).notify(done)
})
})
})
})
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>,
pactUrls: <Array>,
providerStatesUrl: <String>,
providerStatesSetupUrl <String>,
pactBrokerUsername: <String>,
pactBrokerPassword: <String>,
};
pact.verifyPacts(opts)).then(function () {
});
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>,
pactBroker: <String>,
pactBrokerUsername: <String>,
pactBrokerPassword: <String>
};
pact.publishPacts(opts)).then(function () {
});
Using Mocha?
Check out Pact JS Mocha.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - 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