Giter Club home page Giter Club logo

shm's Introduction

shm

Simple http mocking, with good developer experience


yarn add --dev @matthieug/shm
Platform Status Notes
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.

shm's People

Contributors

matthieugicquel avatar

Stargazers

 avatar Fanny Tavart avatar Victor Perez avatar NicolasWagner avatar  avatar daniel carvalho avatar Raí Siqueira avatar Andrii Oriekhov avatar An Cao avatar Andrey avatar Florian Goße avatar Artem Zakharchenko avatar Hugo Duprat avatar  avatar Delphine Bugner avatar Andrei Xavier de Oliveira Calazans avatar Maël Giret avatar Michał Pierzchała avatar  avatar Cyril Bonaccini avatar Pierre Poupin avatar  avatar Antoine Doubovetzky avatar Mathieu Fedrigo avatar  avatar Eliott Gandiolle avatar  avatar Louis Dev avatar Antoine Cottineau avatar Julien Calixte avatar  avatar

Watchers

 avatar

shm's Issues

[React Native] – Error: Invalid response for blob

Hey @matthieugicquel, first of all, thanks for creating this library. I'm currently evaluating various mocking projects for a React Native project. Besides mocking for the unit tests, I'm looking for a developer-friendly way to mock the API responses during E2E testing and development.

So far, I've tested the MSW but without success – I could not find a polyfill good enough to make it work in the React Native scenario. That's when I've stumbled upon your projects and decided to give it a try :)

Unfortunately, after following the quick and nice React Native guide in the readme file, I'm facing the following issue:

BUNDLE  ./index.js 

 LOG  Running "MockRepro" with {"rootTag":1,"initialProps":{}}
 ERROR  [Error: Invalid response for blob: {"name":"Test","description":"Test Description"}]

If I don't add any handlers to the mockServer (or add one that's not matching the request I'm firing) the error message is slightly different, but still the main culprit is the Invalid response for blob:

 BUNDLE  ./index.js 

 LOG  Running "MockRepro" with {"rootTag":11,"initialProps":{}}
 ERROR  [Error: Invalid response for blob: {"message":"No matching handler"}]

I tried using iOS simulator and a real device as well, with the same results. I'm using react-query as the networking library. I created a minimal reproduction repo in case you'll find some time to help me with this issue. Here's the SHM configuration.

Please let me know if you need anything from me :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.