wheresrhys / fetch-mock-jest Goto Github PK
View Code? Open in Web Editor NEWJest wrapper for fetch-mock, a comprehensive stub for fetch
Home Page: http://www.wheresrhys.co.uk/fetch-mock/
License: MIT License
Jest wrapper for fetch-mock, a comprehensive stub for fetch
Home Page: http://www.wheresrhys.co.uk/fetch-mock/
License: MIT License
What am I missing here?
const fetch = require("node-fetch");
jest.mock("node-fetch", () => require("fetch-mock-jest").sandbox());
const fetchMock = require("fetch-mock-jest");
describe("bug", () => {
it("should work!", async () => {
fetchMock.get("/foo", { bar: "buz" });
const response = await fetch("/foo").to((r) => r.json());
expect(response).toEqual({ bar: "buz" });
});
});
dsandbox@sse-sandbox-twf31:/sandbox$ yarn test
yarn run v1.22.10
warning package.json: No license field
$ jest
FAIL src/bug.test.js
bug
✕ should work! (19 ms)
● bug › should work!
fetch-mock: No fallback response defined for GET to /foo
7 | fetchMock.get("/foo", { bar: "buz" });
8 |
> 9 | const response = await fetch("/foo").to((r) => r.json());
| ^
10 |
11 | expect(response).toEqual({ bar: "buz" });
12 | });
at Function.Object.<anonymous>.FetchMock.executeRouter (node_modules/fetch-mock/cjs/lib/fetch-handler.js:230:9)
at Function.Object.<anonymous>.FetchMock._fetchHandler (node_modules/fetch-mock/cjs/lib/fetch-handler.js:144:34)
at Function.Object.<anonymous>.FetchMock.fetchHandler (node_modules/fetch-mock/cjs/lib/fetch-handler.js:135:14)
at Function.jestifiedInstance.fetchHandler (node_modules/fetch-mock-jest/jestify.js:27:18)
at fetch (node_modules/fetch-mock/cjs/lib/index.js:52:51)
at Object.<anonymous> (src/bug.test.js:9:28)
console.warn
Unmatched GET to /foo
7 | fetchMock.get("/foo", { bar: "buz" });
8 |
> 9 | const response = await fetch("/foo").to((r) => r.json());
| ^
10 |
11 | expect(response).toEqual({ bar: "buz" });
12 | });
at Function.Object.<anonymous>.FetchMock.executeRouter (node_modules/fetch-mock/cjs/lib/fetch-handler.js:221:11)
at Function.Object.<anonymous>.FetchMock._fetchHandler (node_modules/fetch-mock/cjs/lib/fetch-handler.js:144:34)
at Function.Object.<anonymous>.FetchMock.fetchHandler (node_modules/fetch-mock/cjs/lib/fetch-handler.js:135:14)
at Function.jestifiedInstance.fetchHandler (node_modules/fetch-mock-jest/jestify.js:27:18)
at fetch (node_modules/fetch-mock/cjs/lib/index.js:52:51)
at Object.<anonymous> (src/bug.test.js:9:28)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.827 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
sandbox@sse-sandbox-twf31:/sandbox$ ^C
https://codesandbox.io/s/bitter-violet-twf31?file=/src/bug.test.js:0-374
It seems the Typescript types are well defined for the fetch-mock library. However, I can't seem to find typings for this wrapper library anywhere. Could you please point me in the right direction?
similar signature to existing jest extensions
If an unexpected call occurs to the mock, I want my tests to fail.
It would be great if there was some MockBehavior.Strict mode, that does not do console.warn but throws an error instead.
e.g. toHavePosted, toHaveGot...
Hi,
I found that fetchMock.mock
is a function instead of an object with keys like calls
and results
. I have found that fetchMock.fetchHandler.mock
is what I expected.
fetchMock.mock
looks like this
function(...args) {
setDebugPhase('setup');
if (args.length) {
this.addRoute(args);
}
return this._mock();
}
I was wondering this is expected.
Thanks for your help.
The obove methods can have Fetched replaced by any of the following verbs to scope to a particular method: + Got + Posted + Put + Deleted + FetchedHead + Patched
The adobe methods are not exposed in the Typescript interface.
I am using ts-jest & want to mock fetch responses (for browser code).
First of all, after installing fetch-mock-jest, in jest setup file I should write
global.fetchMock = require('fetch-mock-jest');
is it right or it should be global.fetch = require('fetch-mock-jest').sandbox();
?
In ts tests I can't write global.fetchMock or fetchMock without global declaring
or default importing import fetchMock from 'fetch-mock-jest';
But if I am doing such things, why I need to make changes in jest setup script?
Moreover, If I import fetchMock in test, eslint show me suggestion:
Could not find a declaration file for module 'fetch-mock-jest'. ... implicitly has an 'any' type
Try `npm install @types/fetch-mock-jest` if it exists or add a new declaration (.d.ts) file containing `declare module 'fetch-mock-jest'; (ts7016)
Can you provide d.ts file for using typed fetchMock methods?
sandbox()
has a type from FetchMockJest
, but also has a more-restrictive type from FetchMockStatic
. Typescript calculates the intersection of these types, which causes the return type to drop the jest.MockInstance<Response, MockCall>
designation.
The README says:
All the built in jest function inspection assertions can be used, e.g.
expect(fetchMock).toHaveBeenCalledWith('http://example.com')
.
But that doesn't work, indeed it looks like the mock always receives undefined
as the second argument, and as a result this fails.
I have a spec that looks something like this
expect(fetchMock).toHaveFetched(`/my/cool/api`, {
method: 'POST',
body: { message: 'this is incorrect', rating: 'thumbs_up' },
});
Where the body is incorrect - so the test correctly fails, but the error message when I ran the tests output this:
fetch should have been called with /my/cool/api
Implying the API was not even called - however, this is not the case, as when I fixed the body to match the actual output, the test started passing immediately
I was trying to introduce a "delay" on the processing for the response so I used the { delay }
option. But noticed my timings are getting randomized.
Upon closer inspection it seemed that there was a real delay once I increased the amount of time I was processing. So it is not respecting the modern jest.useFakeTimers
Ideally I was hoping it will use the setTimeout
that is provided by jest so I can control the behaviour, but it is using the real thing.
As the fetch mock is made up of a jest.fn() married to our own implementation, resetAllMocks has the effect of unset half the mock, or something like that. Not quite clear what's going on , but it's annoying and makes the library confusing and almost unusable
Currently fetch-mock and jest are quite convolutedly entwined in this implementation. It could potentially be simplified with the following approach
requireActual
usage (which now lives in fetch-mock
anyway)jest.mock('node-fetch', jest.fn())
const fetch = require('node-fetch');
const fetchMock = require('fetch-mock-jest').sandbox();
fetch.mockImplementation(fetchMock)
fetch-mock-jest
still adds extensions to jest, but that check to see if the mockImplementation is a fetch-mock instance, and error if not.Trying this out and i've found that jest is always resolving fetch-mock to the CJS server entry, and not the browser one, which results in the global fetch not being polyfilled. Is there a config i'm missing?
For some reason if i attempt to do this...
const fetchCall = fetchMock.lastCall('path:/2/account/settings');
await waitFor(() => {
expect(fetchCall).toEqual([
'https://api.whenidev.net/2/account/settings',
{
method: 'POST',
headers: mockHeaders(),
body: JSON.stringify({
...settings,
clockin: {
...settings.clockin,
work: {
...settings.clockin.work,
enabled: true, // the important bit
},
},
payroll: {
type: 3, // the other important bit
is_onboarded: true,
},
payroll_date: '2015-08-31T12:00:00.000Z', // another important bit
attendance_alert_employee: 5,
attendance_alert_manager: 15,
}),
}],
);
});
I get
Expected: ["https://api.whenidev.net/2/account/settings", {"body": "{\"clockin\":{\"window\":15,\"mobile\":{\"enabled\":false,\"strict\":false,\"strictOut\":false,\"radius\":100},\"work\":{\"enabled\":true,\"strict\":false,\"strictOut\":false,\"radius\":100}},\"payroll\":{\"type\":3,\"is_onboarded\":true},\"payroll_date\":\"2015-08-31T12:00:00.000Z\",\"attendance_alert_employee\":5,\"attendance_alert_manager\":15}", "headers": {"W-Date-Format": "iso", "W-Token": undefined, "W-UserId": NaN}, "method": "POST"}]
Received: serializes to the same string
and it's driving me mad, has anyone else figured a way to do this sanely?
I have a fetch method in our production code that creates new FormData()
I suspect this is the reason I keep getting Unmatched POST to [url]
error.
How do I ignore the body? I've tried matchPartialBody: true
in the options, but that does not work.
I am having serious trouble making fetch-mock-jest work within my typescript project. Maybe somebody can point me to what I am doing wrong?
After the imports I have the following:
import type { FetchMockStatic } from 'fetch-mock';
import fetch from 'node-fetch';
import 'fetch-mock-jest';
jest.mock('node-fetch', () => {
return require('fetch-mock-jest').sandbox();
});
const fetchMock = fetch as unknown as FetchMockStatic;
When running the tests I am getting the following error: "TypeError: require(...).sandbox is not a function". What am I doing wrong?
So i made a simple jest test :
import fetchMock from 'fetch-mock-jest';
test('Toto', async () => {
fetchMock.mock('https://toto.com', 200);
await fetch('https://toto.com');
expect(fetchMock).toHaveBeenCalled();
});
This test fails, I've tried without asyn/await too. Did I miss something ?
toHaveRespondedWith(object | status | string )
(using fetch-mock internals to convert to a response config, then use jest objectMatching)
Hello I noticed that when using toHaveFetched(url, { headers: {} })
, it will always pass no matter what headers are passed but it should pass only if no headers are passed
fetchMock.get('/api', { body: {} })
// custom wrapper around fetch
await api.get('2')
expect(fetchMock).toHaveFetched('/api/2', {
headers: {
// no Accept
Accept: 'application/json'
// 'Content-Type': 'application/json',
},
})
I've used fetch-mock
before but just installed fetch-mock-jest
to try it out and provide some feedback :)
I'm doing this sort of thing in my tests:
expect(fetchMock).toHaveLastFetched({
url: "/ownerships",
body: {
paint_id: "V76-517",
quantity: 1
}
})
I was expecting this to pass, but it didn't. The failure message I get is:
Last call to fetch should have had a URL of [object Object]
This made it quite tricky to work out what was actually going on, I had to use console.log(fetchMock.calls())
to see the call that was made and discovered that the wrong quantity was being sent:
[
[
'/ownerships',
{
method: 'POST',
body: '{"paint_id":"V76-517","quantity":1}',
credentials: 'same-origin',
headers: [Object]
},
request: undefined,
identifier: '/ownerships',
isUnmatched: undefined
]
]
I think it would be really great if the toHaveLastFetched
matcher could inspect the arguments it received and then respond with a corresponding output.
For example:
expect(fetchMock).toHaveLastFetched("/ownerships")
# Fails with
Last call to fetch should have had a URL of "/ownerships" but was "/owner_ships"
If toHaveLastFetched
is called with an object literal, maybe the corresponding keys could be pulled from the resulting request and then nicely diffed so the user knows exactly what went wrong.
I'm going to keep playing, thanks for listening and for all of your hard work on fetch-mock
:)
e.g. calling fetch.restore()
shodul also call mockReset()
on the jest mock
I'm trying to use fetch-mock-jest
on a project I'm working on but as soon as I import it I get the error TypeError: Cannot read property 'bind' of undefined
with the following stacktrace:
at jestify (node_modules/fetch-mock-jest/jestify.js:22:62)
at jestify (node_modules/fetch-mock-jest/jestify.js:114:33)
at Object.<anonymous> (node_modules/fetch-mock-jest/browser.js:4:18)
at config/jest.setup.ts:5:36
at Object.<anonymous> (config/jest.setup.ts:1:1)
Anyone that could help with this problem?
First of all thanks for your awesome library. It makes life much easier when testing my react components that perform API calls.
While experimenting with asserting one question came up. Would it be possible to let fetchMock.mock()
return a new mock that only tracks fetch calls where the given filter
and options
apply so I can assert like that? :
// arrange
const customerAPIMock = fetchMock.mock('path:/customer/');
const productAPIMock = fetchMock.mock('path:/product/');
// act
// Do something that only hits the customer api
// Do something that POST's to the product api
// assert
expect(customerAPIMock).toHaveFetchedTimes(1);
expect(productAPIMock).not.toHaveFetched();
expect(productAPIMock).toHavePostedWith({body: {name: 'Unicorn Milk', price: '$42.00'}});
As far as I understood this can currently be achieved like that using a name
...
// arrange
fetchMock.mock({url: 'path:/customer/', name: 'customerAPI'});
fetchMock.mock({url: 'path:/product/', name: 'productAPI'});
// act
// Do something that only hits the customer api
// Do something that POST's to the product api
// assert
expect(fetchMock).toHaveFetchedTimes(1, {name: 'customerAPI'});
expect(fetchMock).not.toHaveFetched({name: 'productAPI'});
expect(productAPIMock).toHavePostedWith({name: 'productAPI'}, {body: {name: 'Unicorn Milk', price: '$42.00'}});
...but it doesn't feel as natural to me as I need to use strings to reference a certain fetch calls. Also this is error prone and can make my tests fail because of typos in the name
or accidentally reusing a name
and it is lacking auto-completion.
What do you think about the proposed api and do you think it is hard to implement?
My code is
import request from 'supertest';
import {app} from '../app';
jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox());
const fetchMock = require('node-fetch');
test('demo created successfully', async () => {
beforeEach(() => {
fetchMock.get('*', {
status: 200
})
error:
Unmatched GET to https://example.com
After upgrading our codebase to jest 26 and this library to 1.5.1, our tests that used the .toHaveBeenCalled
assertions stopped working. It appears that the .mock
property is never updated with the calls to the spy.
I tried digging into the code a bit, and it seems like this wrapper does the Object.assign(jestifiedInstance.mock, spy.mock)
only once, so those aren't kept in sync. Unfortunately fetchMock.mock
is also a method, so we can't just assign jestifiedInstance.mock = spy.mock
.
I tinkered around with the code locally and got something working by handling the fetchHandler
and mock
inside the proxy. It seems to run on our codebase without issue. I'd be happy to spin up a PR if you're interested!
We have been using fetch-mock-jest to test that our client library is being called - and being called the right number of times with the expected parameters.
It was working perfectly when our client library, which contains rate limiting, was using the p-ratelimit
library.
However, when we move to the bottleneck
rate limiting library we see testing errors.
Previously when we ran the following test we would see that the url
had been called:
mockFetch.patch(url, 200);
lockPatch(type, code, payload, query);
expect(mockFetch.called(url)).toBe(true);
Now, when bottleneck
is being used we get a false
response to the called(url)
check.
Further. inspection of the mockFetch
results - by using the calls()
function - indicates that p-ratelimit
allows a full set of expected url calls to be recorded whereas bottleneck
causes the url list to be empty.
We have included logging commands in our current library and can confirm both p-ratelimit
and bottleneck
DO both run the same set url fetch requests.
Here is my code:
await new Promise(resolve => setTimeout(resolve, 1000));
console.log("CALLS", fetchMock.mock.calls, fetchMock.mock.calls[1][1].method);
expect(fetchMock).toHaveFetchedTimes(3);
expect(fetchMock).toHaveNthPosted(
1,
`${API_HOST}/workouts`,
);
The last assertion is giving me the error "1th call to fetch should have had a URL of http://localhost:1111/workouts but was undefined":
The output from console.log:
CALLS [
[
'http://localhost:1111/workouts',
{ credentials: 'same-origin', headers: [Object], method: 'GET' }
],
[
'http://localhost:1111/workouts/',
{
credentials: 'same-origin',
headers: [Object],
method: 'POST',
body: '{"id":1,"secondId":1}'
}
],
[
'http://localhost:1111/workouts/1',
{
credentials: 'same-origin',
headers: [Object],
method: 'PATCH',
body: '{"name":"sample name"}'
}
]
] POST
I'm trying to spin up a React project with fetch-mock-jest, and having some strange issues! Specifically I'm seeing that the imported object is undefined!
Versions:
├─┬ [email protected]
│ └── [email protected]
├── [email protected]
└── [email protected]
Basically all the errors are:
TypeError: Cannot read property 'post' of undefined
29 |
30 | test('with failed response', async () => {
> 31 | fetchMock.post('https://kitsu.io/api/oauth/token', {
| ^
32 | status: 401,
33 | body: {
34 | error: 'invalid_grant',
at Object.<anonymous> (src/actions/loginWithAssertion.test.ts:31:15)
And an excerpt of the code is:
import fetchMock from 'fetch-mock';
afterEach(() => fetchMock.reset());
jest.mock('app/constants/config');
import { LoginFailed, NetworkError } from 'app/errors';
import loginWithAssertion from './loginWithAssertion';
describe('loginWithAssertion', () => {
test('with successful response', async () => {
fetchMock.post('https://kitsu.io/api/oauth/token', {
status: 200,
...
It's not wrong, either, I dropped into a debugger and it's all undefined 🤷♀️ I don't have any __mocks__
which could be doing this, it's a brand-new project I'm bootstrapping
For further details:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.