fetch-mock
fetch-mock copied to clipboard
Better inspection APIs
There are two reasons to use fetch-mock
- you want to verify fetch has been called as expected
- you just want some responses to some fetch calls your application is making
... or some combination of those
The APIs serving use case 2. are, IMHO, far better than those for use case 1.
I'd be interested to hear thoughts from user about how 1. could be improved
👋
I've just been working on something that has touched on use case 1 in the last day!
I've got a library, data-mocks which leverages fetch-mock to mock fetch and XHR requests (REST and GraphQL) (along with a bunch of other stuff). I'm currently rewriting the unit tests for them (in this branch: https://github.com/grug/data-mocks/tree/update-fetch-mock) and as part of that, I want to be able to verify that a mocked request was responded to with a particular response.
My reasons for this:
data-mocks has the concept of "scenarios":
- A scenario is just a set of responses you want your application to have
- Every instance of data-mocks has a "default" scenario. This is usually just the happiest path
- You can then have different scenarios. For example, for a bank application, you might want to have a default scenario where the customer hits an
/accountsendpoint which responds with one account that is in credit. You might want a scenario to simulate the customer having an account in debt (maybe you call itoneAccountWithDebt. The test you'd want indata-mocksis that a default scenario responds with response X and a scenario responds with response Y.
For more context on the above point, this is what a set of scenarios might be defined as:
const scenarios = {
default: [
{
url: /accounts/,
method: 'GET',
response: { id: 1, balance: 100 }
}
],
oneAccountWithDebt: [
{
url: /accounts/,
method: 'GET',
response: { id: 1, balance: -123 }
}
]
};
I'd love to be able to write my unit tests kind of like this:
import { injectMocks } from 'data-mocks';
import fetchMock from 'fetch-mock';
test('this works', () => {
injectMocks(scenarios, 'default'); // Scenarios taken from previous code snippet.
await fetch('http://mybankapi.com/accounts');
expect(fetchMock.lastCall(/accounts/).response()).toEqual({ id: 1, balance: 123 });
});
Or maybe it doesn't need to be a function at all - it could just be a value on the response from lastCall(). Although you'd really want that response property to be available for a few other things (i.e. when you call calls).
Does this sound sane? I'd love to work with you on getting this feature into the library :)
-Dave
I guess you could also wrap it up into a helper function, lastResponse which takes a filter and options as arguments :)
Sorry for the slow response (no pun intended) - completely missed this message.
lastResponse() etc. works as an API for me. I guess where it gets tricky is in knowing what it should return. For flexibility I guess the raw Response object, but for ease of use maybe helpers to get at the body. await does however make the asynchonous native .json()/.text() methods easier to inline in a test, and any syntactic sugar we added aroudn these would a) still need to be asynchronous b) be another API for users to learn.
So, all things considered, how about:
- each call records it's response as a property on the item in the
_callsarray .lastReponse()helper too- would
.responses()(also accepting filters) be of use too?