Introduction
Mock Service Worker is an API mocking library that uses Service Worker API to intercept actual requests.
By bringing the ability of Service Workers to capture requests for the purpose of caching, Mock Service Worker enables API mocking on the highest level of the network communication chain. It is the closest thing to a mocking server without having to create one.
Since Service Worker is a standard API shipped by all modern browsers, integrating Mock Service Worker into your application, or testing setup, requires no extra configuration, but placing a worker file and declaring mocks.
Try Mock Service Worker in your application in under 10 minutes.
When to mock API?
Let's look at the most common reasons to mock an API.
Development
Software is often being developed in an agile, competitive environment: shifting deadlines, parallel implementations, continuous delivery. Sometimes waiting on the API to be done is simply not an option. Most likely you are using some sort of mocking already: static fixtures, hard-coded state, or a third-party library.
When introduced in a dedicated layer, mocking can become a seamless pleasant experience, with one hardly noticing a difference when the mocking is gone.
Debugging
Most of the client-side issues are related to data. Invalid API call, missing error handling, or receiving an unexpected response—such scenarios happen daily during both development and production.
API mocking allows developers to model an exact API interaction that causes an issue. It's efficient in both debugging and fixing the problem, as one can mock a successful scenario easily as well.
Experimenting
Let's be honest: Choices we make during development are not always the best ones. Technical debt and past architectural decisions may keep us from evolving our products, or trying brand-new technologies.
Mocks can help to see how the application would behave had it been written differently, without having to actually rewrite it, or committing to another ecosystem.
Why Service Workers?
Mock Service Worker leverages a standardized Service Worker API that is designed to intercept requests on the network level, making the mocking completely seamless. Not only does this guarantee identical application behavior with and without mocks, but it also does not require any changes to the application's code for the sake of mocking. Observe requests in the "Network" of your DevTools, forgetting the mocks are at place.
How does it work?
With Mock Service Worker, you use declarative request handlers to capture requests based on URL, RegExp, or custom criteria, and provide a response resolver function that returns a mocked response.
Here's an example of a mock definition file that mocks a POST /login
request:
1// src/mocks.js2import { setupWorker, rest } from 'msw'34const worker = setupWorker(5 rest.post('/login', (req, res, ctx) => {6 const isAuthenticated = sessionStorage.getItem('username')78 if (!isAuthenticated) {9 return res(10 ctx.status(403),11 ctx.json({12 errorMessage: 'Not authenticated',13 }),14 )15 }1617 return res(18 ctx.json({19 firstName: 'John',20 }),21 )22 }),23)2425// Register the Service Worker and enable the mocking26worker.start()
Then this mock definition file is imported conditionally in your application. Done.
Request flow diagram
Browser
This library registers a Service Worker that listens to the application's outgoing requests via the fetch
event, directs those requests to the client-side library, and sends a mocked response, if any, to the worker to respond with.
Here's a high-level overview of the Mock Service Worker request flow:
You are always welcome to dive into the library's source code on GitHub to explore how it works in more detail. Your involvement and help are highly appreciated!
Node
Since Service Workers cannot run in a non-browser environment, this library provides a designated API to reuse the same mock definitions in Node (for example for testing purposes).
Node support is achieved by extending native
http
,https
andXMLHttpRequest
modules usingnode-request-interceptor
library. Read more about Usage in Node.
Conventional mocking
Most mocking libraries operate by using one of the following approaches:
- Provide a dedicated mocking server to substitute a production server.
- Stub native
http
/https
/fetch
implementations to intercept requests.
Issues with a mocking server
A dedicated mocking server, although an actual server, may work differently compared to the production one, as each may have a different architecture, technologies, and infrastructure being used. Due to that, mocking and production servers are not fully interchangeable, creating a deviation in behavior that may affect your application.
Establishing a server implies having to run it and, thus, maintain it. This puts an extra effort into mocking that starts resembling an actual server implementation, rather than a quick and smooth development pattern. A mocking server also means a different server that your application needs to speak to in certain scenarios. This requires to adjust the application's code for the sake of mocking, which increases the maintenance cost of such a setup.
In short, using a mocking server tests your application against a different server, rather than the same production server that behaves differently.
Issues with stubbing native modules
Augmenting native request issuing modules is an efficient way to intercept requests while retaining the same application behavior. However, any change to the native code still creates a deviation between mocking and non-mocking environments. It is also not advisable to mutate things that you do not own.
Such an approach is an optimal compromise, yet will always have technical limitations due to the nature of stubs, giving you a partial assurance in the application's behavior. This may not be the best option for end-to-end testing.