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 🙏

© 2026 – Pkg Stats / Ryan Hefner

wiremock-pact-writer

v0.1.1

Published

Write Pact V3 contract interactions as a side-effect of WireMock-backed integration tests — no separate consumer test files needed.

Downloads

298

Readme

wiremock-pact-writer

Write Pact V3 contract interactions as a side-effect of real WireMock-backed integration tests — no separate consumer test files, no extra frameworks.

The problem

Most Pact consumer libraries require you to write a second set of tests — the "consumer contract tests" — that replay your API calls against a mock driven by the Pact DSL. If you're already running WireMock integration tests against a real running service, this is duplicate work.

The pattern

┌─────────────────────────────────────────────────────────────────┐
│  Integration test (Jest / Vitest / Mocha / …)                   │
│                                                                 │
│  1. Register WireMock stub                                      │
│  2. Call your service under test                                │
│  3. Assert on the response                   ← same as before   │
│  4. writePactInteraction(…)   ← records the contract as JSON   │
└─────────────────────────────────────────────────────────────────┘

The pact JSON is written only when WRITE_PACTS=true (e.g. in CI), so local development stays fast with zero overhead.

Installation

npm install wiremock-pact-writer
# or
yarn add wiremock-pact-writer

No runtime dependencies — only Node.js built-ins (fs, path).

Usage

1. Define project-level constants

Keep consumer / provider names in one place in your project:

// pact/config.ts
export const CONSUMER = 'my-service';
export const PROVIDERS = {
  usersApi: 'users-api',
  notificationsApi: 'notifications-api',
} as const;

2. Return a writePact closure from stub functions

// wiremock/stubs/users/get-user.stub.ts
import { writePactInteraction } from 'wiremock-pact-writer';
import { CONSUMER, PROVIDERS } from '../../pact/config';

export async function stubGetUser(userId: string): Promise<() => Promise<void>> {
  const body = { id: userId, name: 'Alice', email: '[email protected]' };

  // Register your WireMock stub as usual …
  await wiremock.register({ method: 'GET', endpoint: `/users/${userId}` }, { status: 200, body });

  // Return the pact closure
  return () =>
    writePactInteraction({
      consumer: CONSUMER,
      provider: PROVIDERS.usersApi,
      description: 'GET /users/:id - 200 user found',
      providerState: 'user alice exists',
      request: { method: 'GET', path: `/users/${userId}` },
      response: { status: 200, headers: { 'Content-Type': 'application/json' }, body },
    });
}

3. Call writePact() after assertions

test('200 returns user', async () => {
  const writePact = await stubGetUser('user-123');

  const resp = await myService.getUser('user-123');

  expect(resp.status).toBe(200);
  expect(resp.body.name).toBe('Alice');

  await writePact(); // ← one line; no-op locally, writes pact in CI
});

Environment variables

| Variable | Default | Description | |----------|---------|-------------| | WRITE_PACTS | — | Set to "true" to enable writing. No-op otherwise. | | PACT_DIR | <cwd>/pacts | Directory where pact JSON files are written. |

Matching rules

writePactInteraction automatically infers Pact V3 matching rules from the body shape:

| Value type | Matching rule | |------------|--------------| | string, boolean | { match: 'type' } | | whole number | { match: 'integer' } | | float | { match: 'decimal' } | | array | { match: 'type', min: 1 } | | nested object | recurse into each key |

This means provider verification will check type correctness rather than exact values, which is the right default for most contracts.

You can also use inferBodyMatchingRules directly if you need the rules for another purpose:

import { inferBodyMatchingRules } from 'wiremock-pact-writer';

const rules = inferBodyMatchingRules({ id: 'abc', count: 42 });
// {
//   '$.id':    { matchers: [{ match: 'type' }] },
//   '$.count': { matchers: [{ match: 'integer' }] },
// }

API

writePactInteraction(opts: PactInteractionOpts): Promise<void>

Appends one interaction to <PACT_DIR>/<consumer>-<provider>.json. Creates the file if it does not exist.

inferBodyMatchingRules(body: unknown, jsonPath?: string): MatchingRules

Returns Pact V3 matching rules for the given body, rooted at jsonPath (default '$').

License

MIT