Introduction Consumer-Driven Contract Testing(Pact-Javascript)

Numanhan Duran
6 min readMay 24, 2023

Hello everyone, I’m back with you after a long time. In this article, I will talk about a test tool that I recently started researching, implementing and using. I am happy to share with you. So let’s start to take a look.

Introduction

Consumer-Driven Contract (CDC) testing has gained popularity in the world of software development as an effective technique for testing interactions between services. One powerful tool for implementing CDC is the Pact framework. In this article, we will explore the basics of the Pact framework and how it can be used with JavaScript to ensure reliable and robust communication between services.

What is Pact?

Pact is an open-source testing framework designed for implementing CDC testing. It enables developers to define and test contracts between service consumers and providers. A contract represents an agreement between the consumer and provider regarding the expected interactions and data formats.

Why use Pact?

Traditional integration testing often relies on end-to-end testing, which can be time-consuming, brittle, and difficult to maintain. Pact offers an alternative approach by focusing on the interactions between services rather than testing the entire system. This approach provides several benefits:

  1. Faster feedback: CDC tests can be executed independently and in parallel, leading to faster feedback on potential issues.
  2. Isolation of concerns: By testing interactions in isolation, changes made by one service do not affect others, promoting decoupling and agility.
  3. Improved collaboration: Contracts serve as a shared understanding between teams, enabling effective collaboration and reducing miscommunication.

Let’s take a look how it works!

Setting up Pact with JavaScript

To start using Pact with JavaScript, you’ll need to follow these steps:

  • Install Pact: Begin by installing the Pact Node module using npm or yarn. Run the following command in your project directory:
npm install --save-dev @pact-foundation/pact
  1. Define Consumer Contracts: Create a test file for your consumer service and define the interactions using the Pact API. Specify the expected request and response formats, including headers and data payloads.
  2. Verify Provider Contracts: In the provider service, implement a test that verifies the interactions defined in the consumer contract. Pact provides utilities to simulate the consumer requests and validate the provider’s responses against the contract.
  3. Publish Contracts: Once the provider tests pass, you can publish the contracts to a Pact Broker — a centralized repository for storing and sharing contracts. The Pact Broker provides a mechanism for versioning, tracking changes, and facilitating collaboration between teams.
  4. Consumer-Driven Tests: Finally, set up CDC tests in your consumer project that utilize the published contracts from the Pact Broker. These tests ensure that the consumer adheres to the contract by making actual requests to the provider and verifying the responses.

Benefits of Pact

  1. Language independence: Pact supports multiple languages, allowing you to define contracts and perform verification in a language of your choice. JavaScript developers can seamlessly integrate Pact into their existing development workflow.
  2. Versatility: Whether you are working with Node.js, Express, or any other JavaScript framework, Pact can be integrated into your testing suite without major modifications.
  3. Collaboration: Pact encourages collaboration between consumer and provider teams by providing a standardized contract format. The shared contract serves as a communication tool, reducing integration issues and fostering cooperation.
  4. Fast feedback: CDC tests are fast, reliable, and can be run frequently during the development process, providing immediate feedback on any breaking changes.

Conclusion

Consumer-Driven Contract (CDC) testing using the Pact framework is a powerful technique to ensure reliable and robust communication between services. With Pact and JavaScript, you can define, verify, and test contracts, promoting collaboration and agility in your development process. By adopting CDC testing, you can build more resilient and scalable systems that facilitate seamless integration

Setting up the Project

Install Pact: Start by installing the Pact Node module using npm or yarn. Run the following command in your project directory:

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

Define Consumer Contracts: Create a test file for your consumer service, let’s say consumer.test.js, and import the necessary Pact modules:

const { Pact } = require('@pact-foundation/pact');
const path = require('path');

Define your consumer contract by describing the expected interaction and response:

describe('Consumer', () => {
const provider = new Pact({
consumer: 'YourConsumer',
provider: 'YourProvider',
port: 1234, // The port number to start the provider service
dir: path.resolve(process.cwd(), 'pacts'), // Directory to store generated contracts
});

beforeAll(() => provider.setup());

afterEach(() => provider.verify());

afterAll(() => provider.finalize());

describe('GET /api/resource', () => {
it('should respond with the correct data', async () => {
await provider.addInteraction({
uponReceiving: 'a request for a resource',
withRequest: {
method: 'GET',
path: '/api/resource',
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: { message: 'Hello, Pact!' },
},
});

// Make a request to your consumer service here

// Assert that the response matches the expected contract
});
});
});

In the above example, we define a test for a GET request to /api/resource endpoint, expecting a response with status 200, JSON content type, and a body containing a message.

Verify Provider Contracts: In the provider service, create a test file, let’s call it provider.test.js, and import the necessary Pact modules:

const { Verifier } = require('@pact-foundation/pact');
const path = require('path');

Define the provider contract verification:

describe('Provider', () => {
const verifier = new Verifier();

it('should validate the contracts', () =>
verifier.verifyProvider({
provider: 'YourProvider',
providerBaseUrl: 'http://localhost:1234', // The base URL of your provider service
pactUrls: [path.resolve(process.cwd(), 'pacts', 'yourconsumer-yourprovider.json')],
}));
});

In the above example, we verify the contract for the provider by specifying the provider name, base URL, and the path to the generated contract file.

Publish Contracts: After the provider tests pass, you can publish the contracts to a Pact Broker. The Pact Broker provides a centralized location for storing and sharing contracts. Publishing can be done using the Pact CLI or programmatically via the Pact Node module.

To publish programmatically, you can use the publishPacts method:

const { Publisher } = require('@pact-foundation/pact');

const publisher = new Publisher();

publisher.publishPacts({
pactFilesOrDirs: [path.resolve(process.cwd(), 'pacts')],
pactBroker: 'http://your-pact-broker-url',
tags: ['production'],
});

In the above example, we specify the path to the directory containing the contracts, the URL of your Pact Broker, and optional tags for versioning.

Consumer-Driven Tests: Finally, in your consumer project, set up CDC tests that utilize the published contracts from the Pact Broker. These tests ensure that the consumer adheres to the contract by making actual requests to the provider and verifying the responses. You can use the pact-js-dsl library in combination with your preferred testing framework (e.g., Mocha, Jest) to write CDC tests.

const { Pact } = require('@pact-foundation/pact');
const axios = require('axios');
const { expect } = require('chai');

describe('Consumer', () => {
const provider = new Pact({
consumer: 'YourConsumer',
provider: 'YourProvider',
pactBrokerUrl: 'http://your-pact-broker-url',
});

before(() => provider.setup());
after(() => provider.finalize());

it('should fulfill the contract', () => {
const EXPECTED_RESPONSE = { message: 'Hello, Pact!' };

return provider.addInteraction({
state: 'a request for a resource',
uponReceiving: 'a request for a resource',
withRequest: {
method: 'GET',
path: '/api/resource',
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: EXPECTED_RESPONSE,
},
}).then(() => {
return axios.get('http://your-provider-url/api/resource')
.then((response) => {
expect(response.status).to.equal(200);
expect(response.data).to.deep.equal(EXPECTED_RESPONSE);
});
});
});
});

In the above example, we define a test that makes a GET request to the provider and asserts that the response matches the contract defined in the Pact Broker.

Conclusion

Setting up a project with the Pact framework using JavaScript allows you to define, verify, and test contracts between services, ensuring reliable communication and promoting collaboration between teams. By following the steps outlined above and utilizing the provided examples, you can start implementing Consumer-Driven Contract testing using Pact in your JavaScript projects.

Thank you for reading. This article series will continue with details. I’m really excited to work with services and service testing. Thir article was just about introduction and how to set-up pact project with using js. See you in next articles.

https://www.linkedin.com/in/numanhanduran/

--

--