All Projects → pact-foundation → jest-pact

pact-foundation / jest-pact

Licence: MIT License
A Pact adaptor for to allow you to easily run tests with Jest

Programming Languages

typescript
32286 projects
shell
77523 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to jest-pact

README
Developer Relations @ Pact - Your map to the Pact landscape for all-comers (maintainers, contributors, users, newbies)
Stars: ✭ 35 (-39.66%)
Mutual labels:  pact, consumer-driven-contracts, pact-js
ContractTestingBoilerplate
Contract Testing Boilerplate for the microservices developed using Spring Boot and Kafka in a maven multi-module project.
Stars: ✭ 36 (-37.93%)
Mutual labels:  pact, consumer-driven-contracts
pact-example
Example project to demonstrate Contract Testing via Pact.
Stars: ✭ 58 (+0%)
Mutual labels:  pact, consumer-driven-contracts
awesome-contract-testing
Awesome resources for Consumer-Driven Contract Testing
Stars: ✭ 54 (-6.9%)
Mutual labels:  pact, consumer-driven-contracts
pact-js-core
Core binaries for pact-js, a Contract Testing Framework. NOTE: If you are looking to do Pact contract testing in node, you almost certainly want pact-js, not pact-node.
Stars: ✭ 140 (+141.38%)
Mutual labels:  pact, pact-js
jest-fuck
Play an audible 'fuck' whenever your tests fail
Stars: ✭ 44 (-24.14%)
Mutual labels:  jest, jest-plugin
WebDAVServerSamples
WebDAV, CalDAV & CardDAV server examples in C# and VB based on IT Hit WebDAV Server Engine for .NET
Stars: ✭ 39 (-32.76%)
Mutual labels:  examples
personal-blog
✍️ 个人技术博客
Stars: ✭ 79 (+36.21%)
Mutual labels:  jest
tropic
🍍 Test Runner Library
Stars: ✭ 29 (-50%)
Mutual labels:  jest
sPyNNaker
The SpiNNaker implementation of the PyNN neural networking language
Stars: ✭ 86 (+48.28%)
Mutual labels:  examples
ionic3-google-maps-examples
Some examples of how to use google maps javascript API on a Ionic application and use HTML5 geolocation.
Stars: ✭ 24 (-58.62%)
Mutual labels:  examples
Tesseract
A set of libraries for rapidly developing Pipeline driven micro/macroservices.
Stars: ✭ 20 (-65.52%)
Mutual labels:  examples
cookiecutter-flask-react
Cookiecutter for a Flask+React project
Stars: ✭ 22 (-62.07%)
Mutual labels:  jest
match-screenshot
A simple Jest or Chai matcher to compare screenshots, using Applitools Eyes
Stars: ✭ 14 (-75.86%)
Mutual labels:  jest
awesome-address-book
This project shows a basic address book built with ReactJS, Redux Toolkit and Typescript 📖
Stars: ✭ 20 (-65.52%)
Mutual labels:  jest
node-backend-template
A template for NodeJS backend projects
Stars: ✭ 19 (-67.24%)
Mutual labels:  jest
reducer-tester
Utilities for testing redux reducers
Stars: ✭ 19 (-67.24%)
Mutual labels:  jest
Examples Gtkmm
Shows how to use Gtkmm controls by programming code (c++17).
Stars: ✭ 23 (-60.34%)
Mutual labels:  examples
walrus
🎉 Cli development framework.
Stars: ✭ 17 (-70.69%)
Mutual labels:  jest
FairyGUI-PixiJS-Example
Examples for FairyGUI-PixiJS
Stars: ✭ 21 (-63.79%)
Mutual labels:  examples

Jest-Pact

npm version npm TravisCI Maintainability Coverage Status Dependency Status devDependency Status

Jest Adaptor to help write Pact files with ease

Features

  • instantiates the PactOptions for you
  • Setups Pact mock service before and after hooks so you don’t have to
  • Set Jest timeout to 30 seconds preventing brittle tests in slow environments like Docker
  • Sensible defaults for the pact options that make sense with Jest
  • Supports both the main release of pact-js (9.x.x) and the beta 10.x.x for Pact spec V3

Jest-Pact Roadmap

  • Ensure that jest-pact plays well with jest's default of watch-mode
  • Ensure that pact failures print nice diffs (at the moment you have to go digging in the log files)
  • Add a setup hook for clearing out log and pact files

Adapter Installation

# For pact @ 9.x
npm install --save-dev jest-pact
yarn add jest-pact --dev

# For pact @ 10.0.0-beta.x
npm install --save-dev jest-pact@beta
yarn add jest-pact@beta --dev

If you have more than one file with pact tests for the same consumer/provider pair, you will also need to add --runInBand to your jest or react-scripts test command in your package.json. This avoids race conditions with the mock server writing to the pact file.

Usage

Say that your API layer looks something like this:

import axios from 'axios';

const defaultBaseUrl = 'http://your-api.example.com';

export const api = (baseUrl = defaultBaseUrl) => ({
  getHealth: () =>
    axios.get(`${baseUrl}/health`).then((response) => response.data.status),
  /* other endpoints here */
});

Then your test might look like:

import { pactWith } from 'jest-pact';
import { Matchers } from '@pact-foundation/pact';
import api from 'yourCode';

pactWith({ consumer: 'MyConsumer', provider: 'MyProvider' }, provider => {
  let client;

  beforeEach(() => {
    client = api(provider.mockService.baseUrl)
  });

  describe('health endpoint', () => {
    // Here we set up the interaction that the Pact
    // mock provider will expect.
    //
    // jest-pact takes care of validating and tearing
    // down the provider for you.
    beforeEach(() => // note the implicit return.
                     // addInteraction returns a promise.
                     // If you don't want to implict return,
                     // you will need to `await` the result
      provider.addInteraction({
        state: "Server is healthy",
        uponReceiving: 'A request for API health',
        willRespondWith: {
          status: 200,
          body: {
            status: Matchers.like('up'),
          },
        },
        withRequest: {
          method: 'GET',
          path: '/health',
        },
      })
    );

    // You also test that the API returns the correct
    // response to the data layer.
    //
    // Although Pact will ensure that the provider
    // returned the expected object, you need to test that
    // your code recieves the right object.
    //
    // This is often the same as the object that was
    // in the network response, but (as illustrated
    // here) not always.
    it('returns server health', () => // implicit return again
      client.getHealth().then(health => {
        expect(health).toEqual('up');
      }));
  });

V3 Pact spec with 10.0.0-beta.x

See the usage instructions here

Best practices

You can make your tests easier to read by extracting your request and responses:

/* pact.fixtures.js */
import { Matchers } from '@pact-foundation/pact';

export const healthRequest = {
  uponReceiving: 'A request for API health',
  withRequest: {
    method: 'GET',
    path: '/health',
  },
};

export const healthyResponse = {
  status: 200,
  body: {
    status: Matchers.like('up'),
  },
};
import { pactWith } from 'jest-pact';
import { healthRequest, healthyResponse } from "./pact.fixtures";

import api from 'yourCode';

pactWith({ consumer: 'MyConsumer', provider: 'MyProvider' }, provider => {
  let client;

  beforeEach(() => {
    client = api(provider.mockService.baseUrl)
  });

  describe('health endpoint', () => {

    beforeEach(() =>
      provider.addInteraction({
        state: "Server is healthy",
        ...healthRequest,
        willRespondWith: healthyResponse
      })
    );

    it('returns server health', () =>
      client.getHealth().then(health => {
        expect(health).toEqual('up');
      }));
  });

Common gotchas

  • Forgetting to wait for the promise from addInteraction in beforeEach. You can return the promise, or use async/await. If you forget this, your interaction may not be set up before the test runs.
  • Forgetting to wait for the promise of your API call in it. You can return the promise, or use async/await. If you forget this, your test may pass before the expect assertion runs, causing a potentially false success.
  • Not running jest with --runInBand. If you have multiple test files that write to the same contract, you will need this to avoid intermittent failures when writing the contract file.
  • It's a good idea to specify a different log file for each invocation of pactWith, otherwise the logs will get overwritten when other specs start. If you provide an explicit port, then the default mockserver log filename includes the port number.

API Documentation

Jest-Pact has two primary functions:

  • pactWith(JestPactOptions, (providerMock) => { /* tests go here */ }): a wrapper that sets up a pact mock provider, applies sensible default options, and applies the setup and verification hooks so you don't have to
  • messagePactWith(JestMessageConsumerOptions, (messagePact) => { /* tests go here */ }): a wrapper that sets up a message pact instance and applies sensible default options

Additionally, pactWith.only / fpactWith, pactWith.skip / xpactWith, messagePactWith.only / fmessagePactWith and messagePactWith.skip / xmessagePactWith behave as you would expect from Jest.

There are two types exported:

  • JestProvidedPactFn: This is the type of the second argument to pactWith, ie: (provider: Pact) => void
  • JestPactOptions: An extended version of PactOptions that has some additional convienience options (see below).

Configuration

You can use all the usual PactOptions from pact-js, plus a timeout for telling jest to wait a bit longer for pact to start and run.

pactWith(JestPactOptions, (provider) => {
  // regular http pact tests go here
});
messagePactWith(JestMessageConsumerOptions, (messagePact) => {
  // regular message pact tests go here
});

interface ExtraOptions {
  timeout?: number; // Timeout for pact service start/teardown, expressed in milliseconds
  // Default is 30000 milliseconds (30 seconds).
  logDir?: string; // path for the log file
  logFileName?: string; // filename for the log file
}

type JestPactOptions = PactOptions & ExtraOptions;

type JestMessageConsumerOptions = MessageConsumerOptions & ExtraOptions;

Defaults

Jest-Pact sets some helpful default PactOptions for you. You can override any of these by explicitly setting corresponding option. Here are the defaults:

  • log is set so that log files are written to /pact/logs, and named <consumer>-<provider>-mockserver-interaction.log. If you provided an explicit port, then the log file name is <consumer>-<provider>-mockserver-interaction-port-<portNumber>.log
  • dir is set so that pact files are written to /pact/pacts
  • logLevel is set to warn
  • timeout is 30,000 milliseconds (30 seconds)
  • pactfileWriteMode is set to "update"

Most of the time you won't need to change these.

A common use case for log is to change only the filename or the path for logging. To help with this, Jest-Pact provides convienience options logDir and logFileName. These allow you to set the path or the filename independently. In case you're wondering, if you specify log, logDir and logFileName, the convienience options are ignored and log takes precidence.

Jest Watch Mode

By default Jest will watch all your files for changes, which means it will run in an infinite loop as your pact tests will generate json pact files and log files.

You can get around this by using the following watchPathIgnorePatterns: ["pact/logs/*","pact/pacts/*"] in your jest.config.js

Example

module.exports = {
  testMatch: ['**/*.test.(ts|js)', '**/*.it.(ts|js)', '**/*.pacttest.(ts|js)'],
  watchPathIgnorePatterns: ['pact/logs/*', 'pact/pacts/*'],
};

You can now run your tests with jest --watch and when you change a pact file, or your source code, your pact tests will run

Examples of usage of jest-pact

See Jest-Pact-Typescript which showcases a full consumer workflow written in Typescript with Jest, using this adaptor

  • Example pact tests
    • AWS v4 Signed API Gateway Provider
    • Soap API provider
    • File upload API provider
    • JSON API provider

Examples Installation

  • clone repository [email protected]:YOU54F/jest-pact-typescript.git
  • Run yarn install
  • Run yarn run pact-test

Generated pacts will be output in pact/pacts Log files will be output in pact/logs

Credits

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].