npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mocha-pact

v0.10.1

Published

a pact adaptor for mocha

Downloads

124

Readme

Mocha-Pact

Build and test npm version npm Maintainability Coverage Status

Mocha Adaptor to help write Pact files with ease

Basically the same as jest-pact, but for mocha

Adaptor Installation

# npm
npm install --save-dev mocha-pact

# yarn
yarn add mocha-pact --dev

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 'mocha-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.
    //
    // mocha-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');
      }));
  });

Features

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

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 'mocha-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.

  • 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.

  • If you are using eslint-plugin-mocha with the recommended settings, you will need to disable the rule mocha/no-setup-in-describe:

    // .eslintrc.json
    "rules": {
      "mocha/no-setup-in-describe": "off",
      ...
    }

    This is because mocha-pact dynamically generates the test setup for you. Disabling this rule is the approach recommended in the eslint-plugin-mocha documentation for when you have dynamically generated tests.

API Documentation

Mocha-Pact has two primary functions:

  • pactWith(MochaPactOptions, (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(MochaMessageConsumerOptions, (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 Mocha.

There are two types exported:

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

Configuration

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

pactWith(MochaPactOptions, (provider) => {
  // regular http pact tests go here
});
messagePactWith(MochaMessageConsumerOptions, (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 MochaPactOptions = PactOptions & ExtraOptions;

type MochaMessageConsumerOptions = MessageConsumerOptions & ExtraOptions;

Defaults

Mocha-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, Mocha-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.

Credits