Consumer-Driven Contract Testing with Pact for Angular and Spring Boot

Setting up Contract Testing using Pact, Angular with Karma and Jest and Spring Boot with JUnit 5

Richard Hendricksen
6 min readDec 4, 2019

When setting up Contract testing for our project we had some issues getting Pact working nicely with Angular Testbed and Karma/Jest. The code examples that are available are either outdated or simply not working when having multiple providers.

In this article I will go step by step showing how to setup a Consumer-Driven Contract Testing framework with Pact. It will include an Angular frontend as a Consumer and a Spring Boot backend as a Provider.

Code Example

I have created an example repository on GitHub containing all the code:

Getting started

Create a new directory which will be the root for our Consumers, Providers and contracts. We will use both Typescript/Javascript and Java for this guide.

Creating the Consumer

Since the framework is consumer-driven we will start with our first consumer, the Angular frontend. We will both use Karma and Jest to run the Pact tests.

Angular CLI

To create the first Angular app we will use Angular CLI. First create a directory consumers from the root dir and in this directory run:

ng new angular-karma

Keep every setting default and the Angular app will be created

As you can see above we will create an Angular app per testrunner to keep things clear. We will start with Karma.

Adding the service

To have something to contract test we will add a User service to our Angular project. Go to the src/app folder and create the user.service.ts file. It will be a simple service for our User endpoint:

Setting up Pact using Karma

Install the following packages:

npm install --save-dev @pact-foundation/karma-pact @pact-foundation/pact-node @pact-foundation/pact-web

At this time there is still an issue with the @pact-foundation/karma-pact plugin not working with Karma 4, so we need to lower the Karma version to ^3.1.4 in the package.json file.

Edit the karma.conf.js file in the root of the Angular project:

The important things to note about pact :

  • the used specification version
  • which port the Pact mock service will be running
  • where the contracts will be written. Since we will not be using a Pact broker for this guide, we will use a shared directory in the root folder to share contract between Consumers and Providers.

Also note the proxies part that makes sure our calls get proxied to the Pact mock server.

Now run ng test/npm run test / yarn test to start the Karma testrunner. It will start the Pact mock server:

INFO: pact-node@10.2.2/9882 on hades.local: 
Creating Pact Server with options:
{"cors":true,"spec":3,"port":1234,"log":"<logdir>","dir":"<pactdir>","pactFileWriteMode":"overwrite","ssl":false,"host":"localhost"}
INFO [pact]: Pact Mock Server running on port: 1234

Since we don’t have any Contract tests yet this is all Pact will do for now

Adding Consumer Contract Test

To integrate closely with Angular we will write our Contract tests next to the service. To separate it from unit tests we will call it user.service.pact.spec.ts

To write our contract test we first need to setup the Pact framework. To use Pact with Karma we need to use PactWeb instead of the Pact Node.js library. In the beforeAll we add a new PactWeb configuration for this service:

This configuration determines which Consumer/Provider pair is contract tested. The port number is for the port on which the Pact mock server should be available.

We will use Angular TestBed to setup our service for testing:

Next are the callbacks for verifying the mock service and writing the contract file:

With all this plumbing we can create our first contract test:

In the beforeAll we setup the mock service to accept a GET request on the /api/users/1 path and return an example user we defined above. The test will then call our Angular service and validate the expected response is returned.

When we now run ng test a contract file is generated in the root pacts folder. If you view this file you can see it contains our definition of the contract as defined by our test code for this Consumer/Provider pair:

Setting up Pact using Jest

When using Jest instead of Karma there are some setup changes, but the contract tests stay the same.
Create a new Angular app from the root dir using ng new angular-jest .
Add the same user.service.ts as shown for the Karma framework.

Then install the following packages:

npm install --save-dev @angular-builders/jest @pact-foundation/pact @pact-foundation/pact-node @types/jest jest jest-preset-angular

Add the jest.pact.config.js file in the root of the Angular project:

Things to note in this config are the testUrl param, which makes sure all our calls will be directed to our Pact mock server. Also we have a setupFile that will setup our Jest framework. It’s located in pact/jest/setupJest.ts :

To make sure Jest will work we need to edit the tsconfig.spec.json and add the emitDecoratorMetadata and experimentalDecorators tags. This prevent errors with the jest-preset-angular package as stated here:

The final file to edit will be angular.json . Default Angular uses Karma instead of Jest for testing. Find the test part in the json and change it to:

Things to note here are the runInBand parameter to make sure Jest will run the Pact tests sequentially instead of parallel.

Adding Consumer Contract Test

This step is mostly the same as for our Karma setup, with a few minor changes. We will be using the Pact Node.js library instead. First setup the Pact mock server:

The other steps are the same as for Karma:

After this the contract test is exactly the same as in the Karma framework:

Now we can run the contract test using ng test.

Creating the Provider

Since we now have our Consumers and their contracts we can create the Provider. We will use Spring Boot for that.

Setup Spring Boot

I used the Spring Initializr site to create the base for the Provider. Create a Maven project using Java. Fill in the required fields and then extract it to the providers/spring-boot folder.

You can run the backend service using mvn clean spring-boot:run

Adding User Service

We will add a new RestController to handle our request for the User Service:

We also will need a model for User:

Setting up Pact using JUnit 5

To setup our contract verification we will use the JUnit 5 Pact extension.
First add the following packages to your pom file:

To make use of our contracts in the root folder we include them in our testResources so we can acces them from the Java classpath:

Setting up the contract verification is now very simple:

Things to note:

  • @Provider annotation refers to the Provider name, it has to match the Provider name used in the Consumer test. It will only test contracts that match the Provider name.
  • @PactFolder refers to the folder the test can find the contracts.
  • The start will start our Spring Boot application.
  • In the before method we point Pact to the correct base url where the Provider is available.
  • The @State annotation provides a method to setup our backend to reach that state. In our case we don’t need do to anything.
  • Finally in the pactVerificationTestTemplate method the contracts are verified.

Afterthoughts

In this guide we created an Angular frontend and Spring Boot backend. We then proceeded to create a contract from the Angular frontend and verified that it abides the contract. We then verified the contract for the Spring boot backend.

In this guide we haven’t looked at Spring Cloud Contract, which is another framework to setup contract testing for Spring Boot applications. But it is not mutually exclusive since Spring Cloud Contract can convert contracts to Pact versions.

--

--