I recently had to set up Pact tests in an Angular application which I’m currently working on and it hasn’t been so easy as it looks. So I’ve decided to write my first article to describe each step and make it easier for you. As it’s my first time writing a blog post, please be indulgent 😌
To start with, let’s first succinctly define what’s a Pact and its purpose.
What is Pact?
Pact is a code-first tool for testing HTTP and message integrations using contract tests. Contract tests assert that inter-application messages conform to a shared understanding that is documented in a contract. Without contract testing, the only way to ensure that applications will work correctly together is by using expensive and brittle integration tests.
I recommend you to read the Pact official documentation as it’s well written and the concepts are well explained. 🤗
Why use Pact tests in an Angular application?
As the majority of our Angular applications depend on REST API, it’s important that the API keeps meeting our needs even when it changes, otherwise, our application will probably not work as expected.
The API can change, often in a minor way but sometimes in a major way. Consequently, it is important for the API provider to know the whole set of existing API consumers' expectations towards the API, before deploying any change which could potentially break any of those clients’ applications. That’s exactly where Pact tests intervene.
To sum up, a Pact consumer test is a contract between a provider (REST API) and a consumer (Angular application). Pact is a consumer-driven contract (CDC) testing tool, this means that the consumer needs to tell the provider what are his expectations.
Moreover, from the consumer side, the Pact test could be used as specification for his interactions with the provider API. On the other hand, from the provider’s side, the Pact test could be used as Test Driven Development (TDD) tool for the realization of the provider’s endpoints and also for non-regression tests.
How does it work?
The first step on a Pact test is to set up the mock server. The main purpose of this server is to mock the API you’re testing.
Then, you’ll define the interaction for the test. In other words, you’ll say to your mock server the request it will receive and how it has to respond.
The next step is to make the call against this mock server and assert that you got from the API is what you were expecting.
Then, you’ll need to check if the expected interactions have been exercised.
Finally, you’ll have to finalize the test. This step writes the Pact (the contract 📜), clears any interactions left behind and shutdown the mock server.
Through this article, I’ll explain step-by-step how to set up your first Pact test using an Angular service and Jest!
Enough theory 🤯! Let’s put all those pieces together and build a real Pact test with Angular & Jest! Obviously, you need an Angular application or a library using Jest as test framework.
If you want to start from scratch, I suggest you to create your brand new Angular application following the steps in this article :
How to architect epic Angular app in less than 10 minutes! ⏱️😅
In this article we are going to learn how to scaffold new Angular application with clean, maintainable and extendable…
Once this is done, you’ll need to set up Jest. To achieve this, you can follow the steps in this article :
Migrate your Angular library to Jest
A step by step guide on how to migrate a multi-project Angular workspace to Jest
Let’s create our first Pact test!
First thing, you’ll need the Pact dependency, to install it, simply run:
Once this is done, create a
jest.config.pact.js file near the
jest.config.js created when migrating your Angular application to Jest. This file will contain the configuration needed to run Pact tests with Jest such as the Glob pattern for your futures Pact tests or even the URL you’ll use to reach your mock Pact server.
Note: You can change the
testMatchto meet your needs, but be careful to not include the Pact test files in the scope of the
testMatchattribute of the “standard Jest config” because they will not run correctly.
Now, you need to create a script in our
package.json file to run the Pact tests. Moreover, I suggest appending your existing
"test” script with
&& npm run test:pact. This will run your Pact tests each time you’ll run your tests 😇
Great! You’re almost at the end of the configuration! 🥳
As I’m lazy and I don’t like to repeat myself when coding, I’ve created a Pact Wrapper class that you can use to avoid code duplication. This class basically will provide you some functions that you’ll use each time at the setup of the Pact test and for the tear-down too!
Don’t panic! All the code shown in this article is available on my GitHub repository. You don’t need to write it all !😉
As you can see, when creating our Pact object, you’ll need to give it some parameters. These parameters are the configuration of the mock server.
The most important parameter here is the port, it has to be the same as the one you set in the
jest.config.pact.js in the previous step.
Then you have the
log and the
dir parameters. It’s simply the path where you want Pact to write the logs and the contract file, which is the result of the test!
After that, you have the Pact specification version, I suggest using the third version as at the moment I’m writing this article, is the latest version available.
The next parameter is the log level of the tests, very useful when debugging 🙌🏻!
Last but not least, you have the
consumer and the
provider property. These should be an identifier of your Angular application (consumer) and an identifier of your API (provider). Once this object created, you’ve started the underlying Pact mock server and you’re ready to go! 🤓
To conclude the configuration step, I suggest committing the contract files to your version control. The reason for that is simple, if they’re tracked, you’ll see at commit time when one of them changes and you know that you’ve to send it to your provider 🤝! Therefore, you can only ignore the log files generated by Pact by modifying the
.gitignore file as below.
You’re now definitely over with the configuration of Pact framework in your Angular application! 👌
Creating a Pact example test
Let’s first create an Angular service using Angular schematics. This will create a
user service under core folder.
You’re now able to create a simple function in this service that uses
HttpClient to fetch data from an API.
You can now create the Pact test file near your service. Remember, the extension of this file must be
spec.pact.ts as you defined in the
As you already have the Pact Wrapper class, it’s now pretty simple to create the Pact test 💪🏻
As you can see, the only specific part of the test is inside the
describe('get()'... part. In the
beforeAll, you’re defining the behavior of your mock server. For this example, we’re telling Pact that when it’ll receive an
HTTP GET request on the
/api/user/1 path, it has to respond the defined body with an
HTTP STATUS 200 OK.
Note that you’re using
Matchers to define how the body should look like. This is extremely useful as we only want to assert that the object returned by the API contains an
id equal to 1, a
firstName attribute of string type and a
lastName attribute of string type as well. Finally, in the
it('...), you’re just asserting that the mock server answered what we want. 🙏
Launching our first Pact Test!
You’re now ready to finally run that Pact test with the help of the script you already set up in a previous step.
YES💪🏻! Our first Pact test successfully ran!
Our part of the job (as frontend developer 😄) is nearly finished.
The last but not the least step is to send the contract file to our provider. You’ll find this file at the root of your project, under the
pacts directory. The name of the file is:
identifierOfTheConsumer-identifierOfTheConsumer.json. As I already said, this file must be sent to the API provider. It has to be included in the test suite of the provider and run at each build. This way, the provider is going to know at build time if he’s breaking your application when releasing his new version. That’s why we call it a contract 🖋!
Note: Pact framework will create one contract file per provider you test, even if you’re testing multiple endpoints of it.
If you’re curious, you are free to explore this file to understand how the Pact framework translates your tests into a contract! It can even help you to write better Pact tests 😋
Tips & Best practices
- Never manually change the contract file generated by the PACT test ⚠️
- Every time the contract changes in the consumer, it should be updated in the provider.
- The provider can change its API only if it doesn’t break a consumer contract.
- Only define in the Pact test what you really need from the provider. Otherwise, you’ll create a strong dependency between the consumer and the provider. ⛓
Thank you Olivier von Dach for the fast feedback 🙂
Don’t hesitate if you have any questions or feedback regarding this article: @danymarques__