Bringing together testing and development environment with Mock Service Worker
Tags: msw
Published: 2022-03-22 16:52:54

This post is a brief write-up about how [`Mock Service Worker`](https://mswjs.io/) radically improved testing experience and -surprisingly- overall development flow on a couple frontend projects I recently worked on.

## Testing: mock API to support test

I initially chose `Mock Service Worker` just as a [Fetch mock](https://github.com/wheresrhys/fetch-mock) replacement, for the only reason that it **intercepts network requests at the network layer** enabling mocking any requests including [Axios](https://axios-http.com/)'s `XMLHttpRequest` ones.

`msw` approach favors building API mocks in a centralized way so that all tests run against the same set of mocks. (Still, any test can extend `msw` mock handlers on the fly, when strictly necessary).

As the projects have scaled, `msw` mocks ended up **simplistically replicating most of the consumed API**. This opened to...

## Development: using the same mocks

Since `msw` handlers replicate most of API dependencies, I could run the same mocks used by tests in the browser to run the development environment. For free.

Running tests and development environment with the same mocks turned out to be a huge improvement for both testing and development.

### Debugging tests

Broken tests could be debugged more easily be replicating the  testing scenario in browser. Same mocks means same application state in tests and browser.

### Decouple local development from API

Developing in the browser using local mocks resulted in a faster and more flexible development flow: local mocks take almost no time to load but the keep the **exact same async flow** of real API responses.

Local mocks are easy to extend or change, therefore replicating a new API scenario is trivial.

I ended up using local mocks most of my development time and contacting the actual API in very rare cases.

### Storybook

In case you used Storybook, `msw` [integrates](https://storybook.js.org/addons/msw-storybook-addon) seamlessy with it, too.

## MSW inspector: asserting against mocked requests

`msw` encourages an [end-to-end testing approach](https://mswjs.io/docs/recipes/request-assertions), decoupled from code's implementation details, _which I also recommend_:

> Instead of asserting that a request was made, or had the correct data, test how your application reacted to that request.

Even though, I sometimes found it necessary asserting against a specific sent request. Like ensuring that a `post/put` request is issued with proper payload.

For this reason `msw` provides an API to [listen to intercepted requests](https://mswjs.io/docs/extensions/life-cycle-events#tracking-a-request).

[`msw-inspector`](https://github.com/toomuchdesign/msw-inspector) is a tiny utility I wrote to inspect `msw` intercepted requests and enable any testing framework to assert against them. It's open source and published as an npm package.

```js
expect(mswInspector.getRequests('http://my.url/path')).toHaveBeenCalledWith({
  method: 'POST',
  headers: {
    'my-header': 'value',
  },
  body: {
    'my-body': 'value',
  },
  query: {
    'my-query': 'value',
});
```