What is @pact-foundation/pact?
@pact-foundation/pact is a consumer-driven contract testing tool for microservices and distributed systems. It allows you to define the interactions between service consumers and providers in a contract, which can then be used to verify that both sides adhere to the contract.
What are @pact-foundation/pact's main functionalities?
Consumer Pact
This code demonstrates how to set up a Pact mock provider for a consumer service. It defines an interaction where the provider is expected to return data when a GET request is made to the /data endpoint.
const { Pact } = require('@pact-foundation/pact');
const path = require('path');
const provider = new Pact({
consumer: 'ConsumerService',
provider: 'ProviderService',
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'INFO'
});
provider.setup().then(() => {
// Define interactions
provider.addInteraction({
state: 'provider has data',
uponReceiving: 'a request for data',
withRequest: {
method: 'GET',
path: '/data',
headers: { 'Accept': 'application/json' }
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: { key: 'value' }
}
});
// Verify interactions
return provider.verify();
}).finally(() => provider.finalize());
Provider Verification
This code demonstrates how to verify a provider against a Pact file. It uses the Verifier class to ensure that the provider service meets the expectations defined in the Pact file.
const { Verifier } = require('@pact-foundation/pact');
const opts = {
providerBaseUrl: 'http://localhost:8080',
pactUrls: ['path/to/pact-file.json']
};
new Verifier().verifyProvider(opts).then(output => {
console.log('Pact Verification Complete!');
console.log(output);
}).catch(e => {
console.error('Pact Verification Failed: ', e);
});
Pact Broker Integration
This code demonstrates how to publish Pact files to a Pact Broker. It uses the Publisher class to upload the Pact files, making them available for provider verification.
const { Publisher } = require('@pact-foundation/pact');
const opts = {
pactFilesOrDirs: ['path/to/pacts'],
pactBroker: 'http://pact-broker-url',
consumerVersion: '1.0.0'
};
new Publisher(opts).publishPacts().then(() => {
console.log('Pacts successfully published!');
}).catch(e => {
console.error('Failed to publish pacts: ', e);
});
Other packages similar to @pact-foundation/pact
contractual
Contractual is another contract testing tool that focuses on defining and verifying contracts between microservices. It is similar to @pact-foundation/pact but offers a different API and may have different integrations and features.
hoverfly
Hoverfly is a tool for API simulation and testing. It allows you to create simulations of APIs and verify interactions. While it is not specifically a contract testing tool like @pact-foundation/pact, it can be used to achieve similar goals by simulating and verifying API interactions.
mockserver
MockServer is a tool for creating mock HTTP servers and verifying requests. It can be used for contract testing by defining expected interactions and verifying that the server behaves as expected. It offers a different approach compared to @pact-foundation/pact but can be used for similar purposes.
Pact JS
Fast, easy and reliable testing for your APIs and microservices.
Pact is the de-facto API contract testing tool. Replace expensive and brittle end-to-end integration tests with fast, reliable and easy to debug unit tests.
- ⚡ Lightning fast
- 🎈 Effortless full-stack integration testing - from the front-end to the back-end
- 🔌 Supports HTTP/REST and event-driven systems
- 🛠️ Configurable mock server
- 😌 Powerful matching rules prevents brittle tests
- 🤝 Integrates with Pact Broker / PactFlow for powerful CI/CD workflows
- 🔡 Supports 12+ languages
Why use Pact?
Contract testing with Pact lets you:
- ⚡ Test locally
- 🚀 Deploy faster
- ⬇️ Reduce the lead time for change
- 💰 Reduce the cost of API integration testing
- 💥 Prevent breaking changes
- 🔎 Understand your system usage
- 📃 Document your APIs for free
- 🗄 Remove the need for complex data fixtures
- 🤷♂️ Reduce the reliance on complex test environments
Watch our series on the problems with end-to-end integrated tests, and how contract testing can help.
|
Documentation
This readme offers a basic introduction to the library. The full documentation for Pact JS and the rest of the framework is available at https://docs.pact.io/.
Tutorial (60 minutes)
Learn the key Pact JS features in 60 minutes: https://github.com/pact-foundation/pact-workshop-js
Need Help
Installation
npm i -S @pact-foundation/pact@latest
# 🚀 now write some tests!
Looking for the previous stable 9.x.x release?
Requirements
Node 16+ as of pact-js v12
- If using pact-js v11 or lower,
- make sure the
ignore-scripts
option is disabled, pact uses npm scripts to compile native dependencies and won't function without it. - Pact uses native extensions and installs them via the
node-gyp
package. This requires a build chain for a successful installation. See also issue #899. This is now prebuilt in pact-js v12+
Do Not Track
In order to get better statistics as to who is using Pact, we have an anonymous tracking event that triggers when Pact installs for the first time. The only things we track are your type of OS, and the version information for the package being installed. No PII data is sent as part of this request. You can disable tracking by setting the environment variable PACT_DO_NOT_TRACK=1
:
Usage
Consumer package
The main consumer interface are the PactV3
class and MatchersV3
exports of the @pact-foundation/pact
package.
Writing a Consumer test
Pact is a consumer-driven contract testing tool, which is a fancy way of saying that the API Consumer
writes a test to set out its assumptions and needs of its API Provider
(s). By unit testing our API client with Pact, it will produce a contract
that we can share to our Provider
to confirm these assumptions and prevent breaking changes.
In this example, we are going to be testing our User API client, responsible for communicating with the UserAPI
over HTTP. It currently has a single method GetUser(id)
that will return a *User
.
Pact tests have a few key properties. We'll demonstrate a common example using the 3A Arrange/Act/Assert
pattern.
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
const provider = new PactV3({
dir: path.resolve(process.cwd(), 'pacts'),
consumer: 'MyConsumer',
provider: 'MyProvider',
});
public getMeDogs = (from: string): AxiosPromise => {
return axios.request({
baseURL: this.url,
params: { from },
headers: { Accept: 'application/json' },
method: 'GET',
url: '/dogs',
});
};
const dogExample = { dog: 1 };
const EXPECTED_BODY = MatchersV3.eachLike(dogExample);
describe('GET /dogs', () => {
it('returns an HTTP 200 and a list of dogs', () => {
provider
.given('I have a list of dogs')
.uponReceiving('a request for all dogs with the builder pattern')
.withRequest({
method: 'GET',
path: '/dogs',
query: { from: 'today' },
headers: { Accept: 'application/json' },
})
.willRespondWith({
status: 200,
headers: { 'Content-Type': 'application/json' },
body: EXPECTED_BODY,
});
return provider.executeTest((mockserver) => {
dogService = new DogService(mockserver.url);
const response = await dogService.getMeDogs('today')
expect(response.data[0]).to.deep.eq(dogExample);
});
});
});
You can see (and run) the full version of this in ./examples/v3/typescript
, as well as other examples in the parent folder.
To run the examples
- Clone the repo
git@github.com:pact-foundation/pact-js.git
Run a single example
- Change into the required example folder
cd examples/e2e/v3/typescript
- Install all the examples dependencies
npm install
- Run all the example -
npm run test
Run all examples
- Change into the examples folder
cd examples
- Install all the examples dependencies
./installAll.sh
- Run all the examples
./runAll.sh
Provider package
The main provider interface is the Verifier
class of the @pact-foundation/pact
package.
Verifying a Provider
A provider test takes one or more pact files (contracts) as input, and Pact verifies that your provider adheres to the contract. In the simplest case, you can verify a provider as per below using a local pact file, although in practice you would usually use a Pact Broker to manage your contracts and CI/CD workflow.
const { Verifier } = require('@pact-foundation/pact');
server.listen(8081, () => {
importData();
console.log('Animal Profile Service listening on http://localhost:8081');
});
describe('Pact Verification', () => {
it('validates the expectations of Matching Service', () => {
let token = 'INVALID TOKEN';
return new Verifier({
providerBaseUrl: 'http://localhost:8081',
pactUrls: [ path.resolve(process.cwd(), "./pacts/SomeConsumer-SomeProvider.json") ],
})
.verifyProvider()
.then(() => {
console.log('Pact Verification Complete!');
});
});
});
It's best to run Pact verification tests as part of your unit testing suite, so you can readily access stubbing, IaC and other helpful tools.
Compatibility
Specification Compatibility
* v3 support is limited to the subset of functionality required to enable language inter-operable Message support.
Supported Platforms
OS | Architecture | Supported | Pact-JS Version |
---|
MacOS | x86_64 | ✅ | All |
MacOS | arm64 | ✅ | 9.x + |
Linux (libc) | x86_64 | ✅ | All |
Linux (libc) | arm64 | ✅ | 10.x + |
Linux (musl) | x86_64 | ✅ | 13.x + |
Linux (musl) | arm64 | ✅ | 13.x + |
Windows | x86_64 | ✅ | All |
Windows | x86 | ❌ | 9.x - |
Windows | arm64 | ❌ | - |
Roadmap
The roadmap for Pact and Pact JS is outlined on our main website.
Contributing
See CONTRIBUTING.