0.7.1 โ€ข Published 5 months ago

@matthieug/shm v0.7.1

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

yarn add --dev @matthieug/shm
PlatformStatusNotes
node / jestโœ…node>=18 required
node / jest / jsdomโœ…Polyfills required
node / vitestโœ…node>=18 required
bun with bun testโš ๏ธtest won't fail with afterEach(expectRequestsToMatchHandlers)
expoโœ…Install react-native-url-polyfill if using SDK < 50
react-nativeโœ…Install react-native-url-polyfill
browserโœ…

Basic usage

// Some setup/global file
import { installInterceptor } from "@matthieug/shm";

installInterceptor();

// `mockServer.ts` or equivalent
import { createMockServer } from "@matthieug/shm";

export const mockServer = createMockServer("https://test.com");

// Mock a request -- short syntax for the 90% case
mockServer.get<BodyType>("some-route", body);

// Or full syntax for more control
mockServer.get<BodyType>("item/:id", {
  request: { // a request must contain **at least** the specified items to match
    pathParams: { id: "12" } // match path params
    searchParams: { lang: "fr" } // match search params
    headers: { Authorization: "Bearer some-token" } // match headers
  },
  response: {
    body: { message: "here is your mock" }, // specify a json or string body
    status: 418 // specify a status code, default is 200
  }
});

// All usual http methods are available

Have a look at the type definitions for more details.

Important notes:

  • Handlers will by default only respond to ONE matching request. After that, they will be "consumed"
  • Handlers are used in a first_in_first_out order

Usage in tests

Setup

// `jest-setupAfterEnv.js` or equivalent
import { installInterceptor, expectRequestsToMatchHandlers } from "@matthieug/shm";

// Prevent all outgoing requests -- Unhandled requests will be responded to with a 404
installInterceptor();

// Fail tests when there are unhandled requests or unused handlers, and clear handlers
afterEach(expectRequestsToMatchHandlers);
// `mockServer.ts` or equivalent
import { createMockServer } from "@matthieug/shm";

export const mockServer = createMockServer("https://test.com");

Ensure good DX with expectRequestsToMatchHandlers

Using it in your tests will:

  • keep tests isolated, by resetting the mock handlers
  • enforce removal of the unused handlers that could creep up as your code evolves, by throwing an error if a handler was not called
  • ensure your tests do not pass "by coincidence" and help with debugging issues, by throwing an error if a request was not handled
import { expectRequestsToMatchHandlers } from "@matthieug/shm";

afterEach(expectRequestsToMatchHandlers);

test("some test", async () => {
  mockServer.get("hello", body);
  await fetch("https://test.com/hallo");
});

// SHM: Received requests did not match defined handlers
//   UNHANDLED REQUEST: GET https://test.com/hello
//       --> handler GET https://test.com/hallo -> url /hallo !== /hello

Check that an API call was made with mockHandler.wasCalled

expect(mockHandler.wasCalled()).toBe(true);

This can be useful even if you're using the recommended setup with expectRequestsToMatchHandlers, eg to:

  • make the expectation explicit ("when user clicks this, my app should save that to the backend")
  • wait for the call to have been made
  • check that the call was made at the right time in a multi-step tests

Check that the correct request body was sent with mockHandler.getSentBody

test("my test", async () => {
  const mockHandler = mockServer.post("item", "here is your mock");

  await fetch("https://test.com/item", { method: "POST", body: "here's my request" });

  expect(await mockHandler.getSentBody()).toEqual("here's my request");
});

What's different from other http mocking libraries?

There are great alternatives out there, like msw or nock. By the way this package is using @mswjs/interceptors under the hood in node and the browser.

We want to promote a certain way to define and use api mocks in tests, and provide a very simple API.

  • Enforce maintenance of API mocks, by failing tests on unhandled requests and unused handlers
  • No way to write complex request matchers. Tests should avoid conditionnals, and this principle includes your mock definitions (otherwise you should write tests for your tests ๐Ÿค”)
  • Check that your code is sending the correct request through assertions, instead of by coincidentally definining the right handler
  • Prefer specifying the necessary mocks for each test, so that you know at a glance what APIs your feature/component needs

Usage in an app

All the basic APIs are available, but there are a few specific options that you may want to use in this case:

import {
  installInterceptor,
  createMockServer,
  uninstallInterceptor,
  passthrough,
} from "@matthieug/shm";

// Start intercepting -- let unhandled requests passthrough
installInterceptor({ onUnhandled: passthrough });

const mockServer = createMockServer("https://test.com", {
  // options specified here will apply to all handlers
  delayMs: 500, // view your loading states
  persistent: true, // allow handlers to respond to multiple matching requests
});

// When you want to make real requests again
uninstallInterceptor();

Future plans

I don't plan to add lots of features, but I strive for very high quality. Don't hesitate to open an issue if you find a bug, or if the docs are unclear, or if an error message is not helpful.

0.7.1

5 months ago

0.7.0

7 months ago

0.6.3

9 months ago

0.6.2

10 months ago

0.6.1

10 months ago

0.6.0

11 months ago

0.5.2

11 months ago

0.5.0

11 months ago

0.4.0

11 months ago

0.5.1

11 months ago

0.3.1

12 months ago

0.3.0

1 year ago

0.2.0

1 year ago

0.1.0

1 year ago