Skip to content

pact-foundation/pact-workshop-js

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pact JS workshop

Introduction

This workshop is aimed at demonstrating core features and benefits of contract testing with Pact.

Whilst contract testing can be applied retrospectively to systems, we will follow the consumer driven contracts approach in this workshop - where a new consumer and provider are created in parallel to evolve a service over time, especially where there is some uncertainty with what is to be built.

This workshop should take from 1 to 2 hours, depending on how deep you want to go into each topic.

Workshop outline:

NOTE: Each step is tied to, and must be run within, a git branch, allowing you to progress through each stage incrementally.

EG: Move to step 2:

git checkout step2

npm install


Learning objectives

If running this as a team workshop format, you may want to take a look through the learning objectives.

Requirements

Docker

Docker Compose

Node + NPM

Scenario

There are two components in scope for our workshop.

  1. Product Catalog website. It provides an interface to query the Product service for product information.
  2. Product Service (Provider). Provides useful things about products, such as listing all products and getting the details of an individual product.

Step 1 - Simple Consumer calling Provider

We need to first create an HTTP client to make the calls to our provider service:

Simple Consumer

The Consumer has implemented the product service client which has the following:

  • GET /products - Retrieve all products
  • GET /products/{id} - Retrieve a single product by ID

The diagram below highlights the interaction for retrieving a product with ID 10:

Sequence Diagram

You can see the client interface we created in consumer/src/api.js:

export class API {

    constructor(url) {
        if (url === undefined || url === "") {
            url = process.env.REACT_APP_API_BASE_URL;
        }
        if (url.endsWith("/")) {
            url = url.substr(0, url.length - 1)
        }
        this.url = url
    }

    withPath(path) {
        if (!path.startsWith("/")) {
            path = "/" + path
        }
        return `${this.url}${path}`
    }

    async getAllProducts() {
        return axios.get(this.withPath("/products"))
            .then(r => r.data);
    }

    async getProduct(id) {
        return axios.get(this.withPath("/products/" + id))
            .then(r => r.data);
    }
}

After forking or cloning the repository, we may want to install the dependencies npm install. We can run the client with npm start --prefix consumer - it should fail with the error below, because the Provider is not running.

Failed step1 page

Move on to step 2

Step 2 - Client Tested but integration fails

NOTE: Move to step 2:

git checkout step2

npm install


Now lets create a basic test for our API client. We're going to check 2 things:

  1. That our client code hits the expected endpoint
  2. That the response is marshalled into an object that is usable, with the correct ID

You can see the client interface test we created in consumer/src/api.spec.js:

import API from "./api";
import nock from "nock";

describe("API", () => {

    test("get all products", async () => {
        const products = [
            {
                "id": "9",
                "type": "CREDIT_CARD",
                "name": "GEM Visa",
                "version": "v2"
            },
            {
                "id": "10",
                "type": "CREDIT_CARD",
                "name": "28 Degrees",
                "version": "v1"
            }
        ];
        nock(API.url)
            .get('/products')
            .reply(200,
                products,
                {'Access-Control-Allow-Origin': '*'});
        const respProducts = await API.getAllProducts();
        expect(respProducts).toEqual(products);
    });

    test("get product ID 50", async () => {
        const product = {
            "id": "50",
            "type": "CREDIT_CARD",
            "name": "28 Degrees",
            "version": "v1"
        };
        nock(API.url)
            .get('/products/50')
            .reply(200, product, {'Access-Control-Allow-Origin': '*'});
        const respProduct = await API.getProduct("50");
        expect(respProduct).toEqual(product);
    });
});

Unit Test With Mocked Response

Let's run this test and see it all pass:

npm test --prefix consumer

PASS src/api.spec.js
  API
    ✓ get all products (15ms)
    ✓ get product ID 50 (3ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.03s
Ran all test suites.

If you encounter failing tests after running npm test --prefix consumer, make sure that the current branch is step2.

Meanwhile, our provider team has started building out their API in parallel. Let's run our website against our provider (you'll need two terminals to do this):

# Terminal 1npm start --prefix provider

Provider API listening on port 8080...
# Terminal 2
> npm start --prefix consumer

Compiled successfully!

You can now view pact-workshop-js in the browser.

  Local:            http://127.0.0.1:3000/
  On Your Network:  http://192.168.20.17:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.

You should now see a screen showing 3 different products. There is a See more! button which should display detailed product information.

Let's see what happens!

Failed page

Doh! We are getting 404 everytime we try to view detailed product information. On closer inspection, the provider only knows about /product/{id} and /products.

We need to have a conversation about what the endpoint should be, but first...

Move on to step 3

About

Pact JS workshop - learn Pact in 60 minutes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published