An attempt to create the simplest demo to describe a Consumer-Driven Contract Testing workflow with Pact

Overview

Let's Play with Pact

Abstract

This is an attempt to create the simplest demo to describe a Consumer-Driven Contract Testing workflow with Pact.

Prerequisites

This scenario has been developed on Windows.

This scenario is using node, curl and jq.

This scenario is also using pact-stub-server and pact_verifier_cli.

Node.js

node --version
v16.13.2

cURL

curl --version
curl 7.79.1 (Windows) libcurl/7.79.1 Schannel
Release-Date: 2021-09-22
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS HSTS IPv6 Kerberos Largefile NTLM SPNEGO SSL SSPI UnixSockets

jq

jq --version
jq-1.6

Standalone Pact Stub Server

pact-stub-server --version
pact-stub-server v0.4.4
pact stub server version  : v0.4.4
pact specification version: v3.0.0

Pact Verifier CLI

pact_verifier_cli --version
pact_verifier_cli 0.9.7
pact verifier version   : v0.9.7
pact specification      : v4.0
models version          : v0.2.7

Workflow

1. The consumer gets (typically via a developer portal) the OpenAPI (f.k.a. Swagger) document of an API. For this demo, we will use the "Thingies API", thingies-api.oas2.yaml.

2. The consumer wants to use the "Thingies API" with her/his own test data. For instance when she/he sends the request:

GET localhost:8000/thingies/123

she/he expects to receive the following response:

{
  "id": "123",
  "name": "stuff"
}

3. Therefore, the consumer creates a Pact file that follows her/his scenario/interaction, consumer.pact.json.

Warning. There is, of course, a risk that the consumer does not respect the actual behaviour of the API when defining her/his scenario/interaction, that's why there is a verification step afterwards.

4. And then, the consumer can start a Pact Stub Server using the pact-stub-server command with the Pact file:

pact-stub-server --file consumer.pact.json --port 8000

in order to run her/his test script, e.g.consumer.test.cmd:

consumer.test.cmd
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    27  100    27    0     0     27      0  0:00:01 --:--:--  0:00:01   114
  "name": "stuff"
Passed.

Remark. At this stage, this test will obviously work as it is the same consumer that decides, within the test script, what the response should be, but also decides, within the Pact file run by the Pact Stub Server, what the response will be. This test is like a self-fulfilling prophecy! Again, that's why there is a verification step afterwards, during which the provider will verify that the Pact file created by the consumer makes sense or not.

5. Now, the consumer passes her/his Pact file, consumer.pact.json, to the provider so she/he can verify it.

6. The provider runs her/his implementation of the "Thingies API", e.g. provider.app.v1.js:

node provider.app.v1
Provider service is running at localhost:3000...

7. The provider can then verify the consumer Pact file, consumer.pact.json, with the Pact Verifier CLI using the pact_verifier_cli command. This tool will read the Pact file the other way around: it will send the request of the interaction to the actual implementation of the "Thingies API" and check if the actual response corresponds to the response defined by the consumer in the Pact file.

pact_verifier_cli --file consumer.pact.json --hostname localhost --port 3000
Expected body Present(27 bytes) but was empty 1.2) has status code 200 expected 200 but was 404 1.3) includes header 'Content-Type' with value '"application/json; charset=utf-8"' Expected header 'Content-Type' to have value '"application/json; charset=utf-8"' but was '' There were 1 pact failures">
  Given has one thingy with '123' as an thingyId
    WARNING: State Change ignored as there is no state change URL provided
09:15:55 [WARN]

Please note:
We are tracking events anonymously to gather important usage statistics like Pact version and operating system. To disable tracking, set the 'PACT_DO_NOT_TRACK' environment variable to 'true'.



Verifying a pact between Thingies Consumer Example and Thingies Provider Example

  get one thingy
    returns a response which
      has status code 200 (FAILED)
      includes headers
        "Content-Type" with value "application/json; charset=utf-8" (FAILED)
      has a matching body (FAILED)


Failures:

1) Verifying a pact between Thingies Consumer Example and Thingies Provider Example Given has one thingy with '123' as an thingyId - get one thingy
    1.1) has a matching body
           / -> Expected body Present(27 bytes) but was empty
    1.2) has status code 200
           expected 200 but was 404
    1.3) includes header 'Content-Type' with value '"application/json; charset=utf-8"'
           Expected header 'Content-Type' to have value '"application/json; charset=utf-8"' but was ''

There were 1 pact failures

The verification obviously fails as the test data invented by the consumer does not match the test/real data used by the provider.

This is where the Provider States come to the rescue by "allowing you to set up data on the provider by injecting it straight into the data source before the interaction is run, so that it can make a response that matches what the consumer expects." But, how does this "injection" work? No magic, just before sending the request of an interaction the pact_verifier_cli sends the Provider State, i.e. the free text representing the Provider State, to the provider using a POST / endpoint with the following JSON structure:

{
  "action": "setup",
  "params": {},
  "state": "has one thingy with '123' as an thingyId"
}

So, it means that, as a provider you have to manually map (by writing some new specific code) this long string representing the Provider State invented by the consumer with the injection of some specific test data. Something like this, implemented in provider.app.v2.js:

app.post('/', (req, res) => {
  const providerState = req.body.state
  switch(providerState) {
    case "has one thingy with '123' as an thingyId":
      thingies.push({
        id: "123",
        name: "stuff"
      })
      break
    default:
      res.status(404).end()
      return
  }
  res.status(201).end()
})

Warning. This is not production-ready code ;-)

So, you can see that this technique can be error-prone and maybe difficult to scale when a provider has a lot of customers, but this effort needed must be put in perspective with the work needed to maintain and prepare "connected test environment(s)" in order to perform valuable end-to-end testing. As a reminder, the goal of Consumer-Driven Contract Testing with Pact is to remove the need of end-to-end testing!

Running the updated version of implementation of the "Thingies API", provider.app.v2.js:

node provider.app.v2

We can re-run the pact_verifier_cli command specifying the URL of the POST endpoing using the --state-change-url option:

pact_verifier_cli --file consumer.pact.json --hostname localhost --port 3000 --state-change-url http://localhost:3000
  Given has one thingy with '123' as an thingyId
09:18:15 [WARN]

Please note:
We are tracking events anonymously to gather important usage statistics like Pact version and operating system. To disable tracking, set the 'PACT_DO_NOT_TRACK' environment variable to 'true'.



Verifying a pact between Thingies Consumer Example and Thingies Provider Example

  get one thingy
    returns a response which
      has status code 200 (OK)
      includes headers
        "Content-Type" with value "application/json; charset=utf-8" (OK)
      has a matching body (OK)

Yeah!

You might also like...

An easy bot to create discord buttons easily.

Discord Buttons An easy bot to create discord buttons easily. Note: Node.js 16.6.0 or newer is required. Installation npm install You need to rename e

Aug 19, 2022

auto create and auto verif otp vconomics ! udah coid awkaowkaw

Vconomics Refferal Bot How to use : git clone https://github.com/dkmpostor/vconomics/ cd vconomics npm install node index.js Input refferal code Done

Jan 10, 2022

A module that helps you to create minigames with whatsapp-web.js.

wa-minigames A module that helps you to create minigames with whatsapp-web.js. Installation npm install whatsapp-web.js npm install wa-minigames Examp

May 13, 2022

QBCore - Create codes using discord bot to redeem items & cash in your server!

Things you should know: The code was built for Old QBCore, you can of course change it to new if you want. (If you need help feel free to ask) When yo

Dec 10, 2022

MusicPlayer-Javascript - How to create a custom music player with vanilla javascript

MusicPlayer-Javascript How to create a custom music player with vanilla javascri

Feb 8, 2022

create a bandcamp-style audio player for selling albums on itch.io

blamscamp Mmh, options, runnin' out of options, Mmh, options, used to have options bandcamp is great (at time of writing,) but it would be great to ha

Dec 21, 2022

Whatscode.js is a package to create Whatsapp bots easily and quickly

whatscode.js is a package to create Whatsapp bots easily and quickly, even coding experience is not needed...

Dec 30, 2022

Slack app to create an internal dictionary of terms.

Slack app to create an internal dictionary of terms.

tell-me-bot 社内用語辞典をいい感じに使うためのSlack Botです。 機能 用語の表示 完全一致する用語を tell-me-bot にメンションした場合は、即結果が表示されます。もし説明が間違っていた場合は、メッセージ記載のスプレッドシートから編集できます。 曖昧検索への対応 もし、完

Nov 16, 2022

About Discord bot draft that does not contain ready-made commands, compatible with discord.js v14. Create your own discord bot with this command handler.

discordJS-V14 About Discord bot draft that does not contain ready-made commands, compatible with discord.js v14. Create your own discord bot with this

Dec 28, 2022
Owner
Patrice Krakow
Patrice Krakow
A community driven project to make a game like phigros.

这是什么? 这是一款名为PhiCommunity的节奏游戏,它仿照Phigros制作。 APP已发布(测试版本) 请前往Actions - PhiCommunityAPP的最新构建下载Artifact,此构建为Debug构建,仅用于测试。 您也可以前往Releases - PhiCommunityA

Yuameshi 105 Jan 2, 2023
A community driven project to make a game like phigros.

A community driven project to make a game like phigros.

Yuameshi 103 Dec 28, 2022
Projeto 10° da Driven Education - TrackIt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Daniel Lucas Ederli 6 Jun 29, 2022
V2.0 🚀 AI Driven PancakeSwap Prediction Bot🔮

?? ?? PancakeSwap Prediction Bot (improved) v2.0 PancakeSwap Prediction Bot using AI recomendations. Folked and improved from this repository. ⭐ Pleas

null 368 Oct 22, 2022
A Node JS Express/Serverless demo application that creates a slideshow video using the Pexels image library and Shotstack video editing API.

Shotstack Pexels Slideshow Video Demo This project demonstrates how to use the Shotstack cloud video editing API to create a video using an HTML form

Shotstack 25 Dec 9, 2022
Heroku setup demo

heroku-demo A basic guide to setting up a project hosted on Heroku with a PostgreSQL database using Giovanna Aveiro's and OliverJam's tutorial for Fou

Safia 7 Mar 31, 2022
Saturn Stealer is a tool for create a server and the create malware, themalware is discord token straler/grabber.

Saturn-Stealer ⚠️ It is strictly forbidden to use this software for illegal purposes. This software was coded for educational purposes. The developer

ENDLEPH 13 Aug 28, 2022
:musical_score: ts-audio is an agnostic library that makes it easy to work with AudioContext and create audio playlists in the browser

ts-audio · ts-audio is an agnostic and easy-to-use library to work with the AudioContext API and create Playlists. Features Simple API that abstracts

Evandro Leopoldino Gonçalves 284 Dec 25, 2022
Create videos using React!

Reactive Videos are videos created using HTML and React components. This allows you to leverage the almost limitless possibilities of the web browser

Mikael Finstad 76 Dec 25, 2022
An simple package to create an Activity in Discord Voice Channel using Discord.js

discordjs-activity An simple package to create an Activity in Discord Voice Channel using Discord.js ?? | Installation npm install discordjs-activity

Sudhan 55 Nov 15, 2022