This is a practical code example to accompany the Consumer-Driven Contract Testing with Pact article that I wrote.
Here is how to set up and use Pact with PactFlow for consumer-driven contract testing (CDC) between a React frontend web application (the consumer) and an Express.js REST API (the provider) in the context of a ProductsCatalog API, for the interaction of creating a new product.
Step 1: Set Up Pact in the Consumer (React App)
- Install Pact in the Consumer Project:
npm install --save-dev @pact-foundation/pact
- Write a Consumer Pact Test:
Create a test file (e.g.,
pactTests/CreateProductPact.spec.js
) in your consumer project:
const { Pact } = require('@pact-foundation/pact');
const path = require('path');
const { createProduct } = require('../src/api'); // Function that makes the API call
const provider = new Pact({
consumer: 'ProductsCatalogConsumer',
provider: 'ProductsCatalogAPI',
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'INFO',
spec: 2,
});
describe('Products API Pact', () => {
beforeAll(() => provider.setup());
afterAll(() => provider.finalize());
beforeEach(() => {
const interaction = {
state: 'provider allows product creation',
uponReceiving: 'a request to create a product',
withRequest: {
method: 'POST',
path: '/products',
headers: { 'Content-Type': 'application/json' },
body: {
name: 'New Product',
price: 29.99,
},
},
willRespondWith: {
status: 201,
headers: { 'Content-Type': 'application/json' },
body: {
id: 1,
name: 'New Product',
price: 29.99,
},
},
};
return provider.addInteraction(interaction);
});
it('should create a product successfully', async () => {
const response = await createProduct({ name: 'New Product', price: 29.99 });
expect(response).toEqual({
id: 1,
name: 'New Product',
price: 29.99,
});
});
afterEach(() => provider.verify());
});
- Run the Consumer Pact Test:
jest pactTests/CreateProductPact.spec.js
This is typically executed by the CI pipeline together with other unit tests.
- Publish the Pact File to PactFlow:
Create a script (e.g.,
publishPact.js
):
const pact = require('@pact-foundation/pact-node');
const path = require('path');
pact.publishPacts({
pactFilesOrDirs: [path.resolve(process.cwd(), 'pacts')],
pactBroker: '[https://your-pactflow-url](https://your-pactflow-url)',
consumerVersion: '1.0.0',
tags: ['prod'],
});
- Run the script:
node publishPact.js
This is typically executed by the CI pipeline after all tests pass with green lights.
Step 2: Set Up Pact in the Provider (Express.js API)
- Install Pact in the Provider Project:
npm install --save-dev @pact-foundation/pact
- Write a Provider Verification Test:
Create a test file (e.g.,
pactTests/VerifyPacts.spec.js
) in your provider project:
const { Verifier } = require('@pact-foundation/pact');
const path = require('path');
const server = require('../src/server'); // Your Express app
server.listen(8080, () => {
console.log('Provider API listening on [http://localhost:8080'](http://localhost:8080'));
});
describe('Pact Verification', () => {
it('validates the expectations of ProductsCatalogConsumer', () => {
return new Verifier({
provider: 'ProductsCatalogAPI',
providerBaseUrl: '[http://localhost:8080](http://localhost:8080)',
pactBrokerUrl: '[https://your-pactflow-url](https://your-pactflow-url)',
providerVersion: '1.0.0',
tags: ['prod'],
publishVerificationResult: true,
}).verifyProvider();
});
});
- Run the Provider Verification Test:
jest pactTests/VerifyPacts.spec.js
This is typically executed by the CI pipeline together with other unit tests.
Step 3: Configure PactFlow
- Set Up PactFlow:
- Sign up for a PactFlow account and create a new workspace.
- Obtain the PactFlow URL and authentication token.
- Configure CI/CD Pipelines:
- Ensure your CI/CD pipeline runs the consumer tests, publishes the pacts to PactFlow, and then triggers the provider verification tests.
Summary of the workflow
- Consumer (React App):
- Write consumer tests using Pact.
- Generate Pact files during test execution.
- Publish Pact files to PactFlow.
- Provider (Express.js API):
- Fetch Pact files from PactFlow.
- Verify the provider against the Pact files.
- Publish verification results back to PactFlow.
By following these steps, you ensure that both the consumer and provider are aligned through the contract, facilitating seamless integration and continuous delivery.