Request assertions
When testing, it may be tempting to write assertions against a dispatched request. Examples of such assertions can include:
- Check that the tested code has dispatched a request;
- Check that a request was issued with the correct URL/parameters/body/etc;
- Check that a specific request handler was called.
Adding such assertions, however, is implementation details testing and is highly discouraged. Asserting requests in such way is testing how your application is written, instead of what it does.
Mock Service Worker gives you a guarantee over network communication.
Your application fetches data for a reason, so prefer testing that reason as the outcome of the request. If a request's method, headers, or body are invalid, your application is likely to get an invalid response back. Below we are going to take a look at some recommended strategies to request testing.
Special cases
There are, however, some special cases where asserting on network requests is the only option. These include, for example, polling, where no other side effect can be asserted upon.
For such cases, Mock Service Worker allows tracking of network requests through the Life-cycle events API.
Include failure scenarios
Validity of the response often, if not always, depends on the validity of the request. Include any necessary validation and utilize conditional mocking to reflect a request's integrity in your response resolvers.
For example, your application is making a GET /search?type=ABC
request where the type
parameter represents a search type, and should be either product
or user
. That query parameter value validation is a business logic, so reflect it in your response resolver to ensure your mocks respect that logic.
1import { rest } from 'msw'23rest.get('/search', (req, res, ctx) => {4 const searchType = req.url.searchParams.get('type')56 // Successful response in case the "type" query parameter7 // passes the value validation.8 if (['product', 'user'].includes(searchType)) {9 return res(10 ctx.json({11 results: [1, 2, 3],12 }),13 )14 }1516 // A failure scenario that ensures our mocks don't tolerate17 // unknown "type" query parameter values.18 return res(19 ctx.status(400),20 ctx.json({ message: `Unknown search type: ${searchType}` }),21 )22})
By accounting on the failure scenario, you can rely on your application's output in your tests being a reflection of the request's validity.
Remember that mocks execute next to the rest of your application. Import validation utilities, constants, and other useful data to reduce the amount of repetition in your mocking setup and keep it aligned with your application's logic.
Including partial representation of the business logic is also beneficial, as it helps mocks to represent the state of an API in a point of time, making mocks useful when reasoning about API's behavior.
Treat unhandled requests
To ensure that your application doesn't perform any requests rather than the ones defined in your handlers, consider using onUnhandledRequest
option. This option allows to warn or throw an error whenever an unknown request is dispatched.