wheresrhys / fetch-mock Goto Github PK
View Code? Open in Web Editor NEWMock http requests made using fetch
Home Page: http://www.wheresrhys.co.uk/fetch-mock/
License: MIT License
Mock http requests made using fetch
Home Page: http://www.wheresrhys.co.uk/fetch-mock/
License: MIT License
Here is a minimal repo to reproduce the issue (there is an npm test
task). I just can't intercept the request. The example is almost the same as the first one from README. Here is the karma ouput:
START:
Hash: 8344a6c0a9b3c44a5636
Version: webpack 1.12.9
Time: 10ms
webpack: bundle is now VALID.
webpack: bundle is now INVALID.
Hash: 205e381c2cff60ba2ea2
Version: webpack 1.12.9
Time: 431ms
Asset Size Chunks Chunk Names
tests/index.js 164 kB 0 [emitted] tests/index.js
chunk {0} tests/index.js (tests/index.js) 57.8 kB [rendered]
[0] ./tests/index.js 398 bytes {0} [built]
[1] ./tests/framework/fetch.test.js 611 bytes {0} [optional] [built]
[2] ./tests/framework/plugins.test.js 559 bytes {0} [optional] [built]
[3] ./~/es6-promise/dist/es6-promise.js 32.3 kB {0} [built]
[4] ./~/fetch-mock/es5/client.js 215 bytes {0} [built]
[5] ./~/fetch-mock/es5/fetch-mock.js 10.8 kB {0} [built]
[6] ./~/isomorphic-fetch/fetch-npm-browserify.js 233 bytes {0} [built]
[7] ./~/process/browser.js 2.06 kB {0} [built]
[8] (webpack)/buildin/amd-define.js 85 bytes {0} [built]
[9] (webpack)/buildin/module.js 251 bytes {0} [built]
[10] ./~/whatwg-fetch/fetch.js 9.93 kB {0} [built]
[11] ./src ^.+\.jsx?$ 160 bytes {0} [built]
[12] ./tests .+\.test\.jsx?$ 222 bytes {0} [built]
[13] vertx (ignored) 15 bytes {0} [optional]
webpack: bundle is now VALID.
09 12 2015 00:08:05.365:INFO [karma]: Karma v0.13.15 server started at http://localhost:9876/
09 12 2015 00:08:05.371:INFO [launcher]: Starting browser PhantomJS
09 12 2015 00:08:07.449:INFO [PhantomJS 1.9.8 (Mac OS X 0.0.0)]: Connected on socket l6IlGACQCBhgBzfKAAAA with id 12541479
fetch-mock
✖ mocks simplest http get request (slow: 2.002 secs)
karma plugins
✔ exposes "expect" globally
✔ exposes "should" globally
✔ has chai-as-promised helpers
Finished in 2.031 secs / 2.005 secs
SUMMARY:
✔ 3 tests completed
⚠ 1 test slow
✖ 1 test failed
FAILED TESTS:
fetch-mock
✖ mocks simplest http get request (slow: 2.002 secs)
PhantomJS 1.9.8 (Mac OS X 0.0.0)
timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
npm ERR! Test failed. See above for more details.
The normalizeRequest()
function in fetch-mock.js is supposed to check if it is called with a URL string or a Request object. This is failing, and falling back to the string case when fetch() is invoked with a Request object.
Here's an example:
let req = new Request('http://www.example.com', { method: 'GET' });
let p = fetch(req);
The following implementation works for me, but may be too simplistic of a fix:
function normalizeRequest (url, options) {
if (typeof url === 'string') {
return {
url: url,
method: options && options.method || 'GET'
};
} else {
return {
url: url.url,
method: url.method
};
}
}
Hey guys, thanks for this is great !!
It would be nice to add some extra param in response object for eg: statusText, etc... Fetch Response
What do you think ?
Tks !
I am using FetchMock with Mockery as Node 4 module, hence I need to get a handle on the mocked fetch() function.
Registering the node-fetch mock with myMock.getMock()
as shown below leads to an undefined fetch function in the code under test.
'use strict';
var fetchMock = require('fetch-mock');
var mockery = require('mockery');
describe('fetch mockery', function () {
beforeEach(function () {
mockery.enable({useCleanCache: true});
var myMock = fetchMock
.mock('http://auth.service.com/user', '{"foo": 1}');
mockery.registerMock('node-fetch', myMock.getMock()); <-- undefined
});
afterEach(function () {
fetchMock.restore();
mockery.deregisterMock('node-fetch');
mockery.disable();
});
it('should mock a request', function () {
var goFetch = require('../lib/fetchsample'); // just a call to fetch in a separate module
return goFetch('http://auth.service.com/user').then(function (response) {
return response.json();
}).then(function (json) {
console.log(json);
});
});
});
As a workaround, the necessary fetch function mock is availabe as myMock.mockedContext.fetch
:
mockery.registerMock('node-fetch', myMock.mockedContext.fetch);
Maybe the fix would be to change getMock()
in fetch-mock.js like so:
/**
* getMock
* Returns a reference to the stub function used to mock fetch
* @return {Function}
*/
getMock () {
return this.mockedContext.fetch;
}
Or am I using fetch-mock incorrectly here?
I am actually unable to get anything to work as Chrome throws Illegal Invocation error. At the following line:
Line 329 in f0e1132
I'm assuming it's a binding context issue similar to this: typicode/fetchival#1
Or quite possibly I'm not using the library correctly.
I'm just using a basic example and I get the error:
import fetchMock from 'fetch-mock'
fetchMock.mock('http://www.example.com', 200);
I setup the mockery
and fetch-mock
as following code:
import mockery from 'mockery'
import fetch from 'node-fetch'
import fetchMock from 'fetch-mock'
import MyModule from './MyModule'
fetchMock.useNonGlobalFetch(fetch)
// ...
beforeEach(() => {
mockery.enable({ useCleanCache: true })
mockery.registerMock('node-fetch', fetchMock.mock(pattern, 'POST', 200).getMock())
})
afterEach(() => {
mockery.deregisterMock('node-fetch')
mockery.disable()
})
And during the test, I found the request doesn't get mocked as expected, all request hit the real server and fetchMock.called()
returns false
Did I missed something or what should I do?!?!
https://github.com/github/fetch/blob/master/fetch.js#L128
Will need to run test suite in latest chrome
Thank you for your lib! I tried to mock 204 status, but got the error:
Uncaught (in promise) TypeError: Failed to construct 'Response': Response with null body status cannot have body
at TypeError (native)
at mockResponse ...
with that line return _Promise.resolve(new Response(body, opts));
I suppose it couldn't mock 204 status as far as it hasn't response body.
I have the following routes:
fetchMock.mock({
routes: [{
name: 'route3',
method: 'DELETE',
matcher: 'path/to/my/api',
response: 204,
}]
});
Should I change the response config? Thanks in advance!
var debug = require('debug')('fetch-mock');
I'm trying to use fetch-mock
to against environments which do not have Promise
implemented natively.
I'm using isomorphic-fetch
and replacing its Promise implementation with bluebird, so it works in these environments in my production code.
I'm using it something like this:
import 'isomorphic-fetch'
import Promise from 'bluebird'
fetch.Promise = Promise
It would be cool if fetch-mock
used a similar mechanism, or (perhaps even better?) looked into the original fetch
and used its .Promise
property if it exists.
Let me know if you want me to try to PR this (I assume it would be pretty quick and self-evident how to do this)
This is one of the two related issues that led me to submit #83 (the other is #88).
calls
, called
, lastCall
, lastUrl
. lastOptions
are all documented as taking a matcher
argument. This argument can only meaningfully be a string
naming an existing route, and thus it differs subtly from the meaning of matcher
in what's probably the most visible API, mock()
:
matcher
[required]: Condition for selecting which requests to mock Accepts any of the following
*string
: ...
*RegExp
: ...
*Function(url, opts)
: ...
Here is a case where my (incorrect) reading of the docs led to surprising behavior:
fetchMock.mock('^http://example.com/');
fetch('http://example.com/one/two').then(() => {
fetchMock.called('^http://example.com/'); // true
fetchMock.called('^http://example.com/one'); // false (surprising to me)
fetchMock.called(/one\/two$/); // false (surprising to me)
});
Hello!
Thanks for putting together this handy package!
One thing I'd like to be able to do is run tests in node as well as in the browser without having separate import/require statements (require('fetch-mock')
vs require('fetch-mock/src/server')
).
Have you considered leveraging the browser
key in package.json
?
Something like this should do it:
"main": "src/server.js",
"browser": "es5/client.js"
This should allow require('fetch-mock')
to work for both browser and server (well, at least node v4 😄)
Have you explored this at all?
The following statement on the README is not accurate:
Environment doesn't support requiring fetch-mock?
If your client-side code or tests do not use a loader that respects the browser field of package.json use require('fetch-mock/es5/client'). This can also be loaded directly in a script tag as ./node_modules/fetch-mock/es5/client.js (Disclaimer: I haven't actually tried this, but it should work)
es5/client.js
is just a babel compiled version of src/client.js
, which still attempts to use require. We need another folder (perhaps browser/
) that contains a browserify-compiled version of src/client.js
.
Using browserify + fetch-mock, attempts to get a reference to the mock via .getMock()
always seems to return undefined
.
A glance at the code indicates that getMock
just returns this.fetch
which doesn't seem to be set anywhere.
Can probably stop calls to mock, when already mocked, throwing an error without a major release
Because Sinon does not really work well with Webpack, using Karma-webpack with this lib will produce error on load. In order to make karma-webpack work with Sinon, plugin with karma-sinon
is always required. I think this lib can be provided as a Karma plugin.
edit: I did not notice there was browserify instruction. But requiring fetch-mock/client
does not work either.
I want to mock multiple calls to the same route - e.g.
fetchMock.mock('http://test.com', 500)
.mock('http://test.com', {valid: 'response', after: 'error'}
.getMock()
// code that calls a url multiple times depending on the response
Right now, the first defined route that matches always answers. Any way around that?
similar shorthand behaviour to setting body string
File this under random question:
Noticed that the version numbers are incrementing without any actual code changes, is there a reason for that? With semantic versioning they should increase based on functionality changes rather than documentation, am I missing something?
I'm in the process of updating the fetch-mock
and our tests broke from the jump from 2.2.8
to 2.2.9
. Could you please consider introducing a changelog to ease the pain of upgrades.
Does fetch-mock
adhere to semver? I'm surprised things broke on a patch update.
Currently I'm just returning { sendAsJson: false, body: myArrayBuffer }
, but I always wind up with:
TypeError: Invalid non-string/buffer chunk
at chunkInvalid (_stream_readable.js:399:10)
at readableAddChunk (_stream_readable.js:144:12)
at Readable.push (_stream_readable.js:130:10)
at mockResponse (node_modules/fetch-mock/src/fetch-mock.js:59:6)
at FetchMock.fetchMock (node_modules/fetch-mock/src/fetch-mock.js:253:12)
I'm able to hack around this by wrapping it in a Buffer: { sendAsJSON: false, body: Buffer.from(myArrayBuffer) }
, but that's not documented. Is that the intended use?
so that e.g. afterEach(fetchMock.restore)
is possible
bower install fetch-mock
can install fetch-mock now, but it is not the build version, not generated folder es5.
npm package (2.1.0) contains not transpiled ES6 code which cases an error for me:
> [email protected] mocha:base /Users/sapegin/izumi/kao
> mocha --compilers js:babel/register --require mochasetup "./test"
/Users/sapegin/izumi/kao/node_modules/fetch-mock/server.js:3
const Response = require('node-fetch').Response;
^^^^^
SyntaxError: Use of const in strict mode.
at exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:443:25)
at Module._extensions..js (module.js:478:10)
at Object.require.extensions.(anonymous function) [as .js] (/Users/sapegin/izumi/kao/node_modules/babel-core/lib/api/register/node.js:214:7)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object.<anonymous> (/Users/sapegin/izumi/kao/mochasetup.js:6:31)
at Module._compile (module.js:460:26)
at normalLoader (/Users/sapegin/izumi/kao/node_modules/babel-core/lib/api/register/node.js:199:5)
at Object.require.extensions.(anonymous function) [as .js] (/Users/sapegin/izumi/kao/node_modules/babel-core/lib/api/register/node.js:216:7)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at /Users/sapegin/izumi/kao/node_modules/mocha/bin/_mocha:304:3
at Array.forEach (native)
at Object.<anonymous> (/Users/sapegin/izumi/kao/node_modules/mocha/bin/_mocha:303:10)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
node v0.12.7
npm v3.3.6
It would be handy to be able to specify an asynchronous resolve for the mock response for dealing with testing cancellation and other potential race conditions in an application.
This could be done by response
accepting a promise.
As detailed more extensively on my blog I believe in sharing the ownership of open source projects that others depend on. If you'd like to co-own this repo, and can demonstrate reasonable experience of contributing/owning other open source projects, please get in touch. @wheresrhys
Like the library. Can you add LICENSE? MIT preferably...
Thanks
This is one of the two related issues that led me to submit #83.
I propose an API that applies a matcher
(string|RegExp|function(url, opts)
) to the whole list of calls, regardless of any configured routes or their names. I consider this behavior useful in composing assertions that aren't possible with calls(routeName)
or called(routeName)
, such as:
// Assuming a new method: fetchMock.testCalls
fetchMock.mock('^http://example.com/');
fetch('http://example.com/?arg1=123').then(() => {
// called() would return false for each of the following
fetchMock.testCalls('http://example.com/?arg1=123'); // true
fetchMock.testCalls('^http://example.com/?arg1='); // true
fetchMock.testCalls(/arg1=\d+$/); // true
});
So basically, it would do what I had the impression called()
and calls()
should do, as described in #87.
#83 contains a proposed implementation in the form of callsMatching()
and calledMatching()
filterCalls()
and testCalls()
.
As of v3.0.4, mocking a relative URL results in an Error
being thrown from the dependency module node-fetch
:
Error: only absolute urls are supported
at new Request (node_modules/fetch-mock/node_modules/node-fetch/lib/request.js:34:9)
at toRequest (node_modules/fetch-mock/src/fetch-mock.js:65:13)
at Object.route.matcher (node_modules/fetch-mock/src/fetch-mock.js:111:15)
at node_modules/fetch-mock/src/fetch-mock.js:233:15
at Array.some (native)
at routes.forEach.routes.forEach.routes.some (node_modules/fetch-mock/src/fetch-mock.js:231:11)
at mock (node_modules/fetch-mock/src/fetch-mock.js:329:21)
....
In my use case, I am writing tests for a Redux application which uses fetch
to grab some i18n data defined in a JSON file. The code I am testing looks like this:
fetch(`public/i18n/${locale}.json`)
.then(/* ...snip... */)
The tests are written in mocha
and are executed through Node.js, so I use isomorphic-fetch
assigned to the global
object inside the test, to fill in for the browser's fetch
function, and use fetch-mock
to mock the response:
import fetchMock from 'fetch-mock'
import fetch from 'isomorphic-fetch'
global.fetch = fetch
/* ...snip... */
fetchMock.mock(`public/i18n/${locale}.json`, { /* fixture i18n data */ })
This code worked fine in v3.0.3 as fetch-mock
wasn't using Request
from node-fetch
, which sets the absolute URL limitation (LIMITS.md in node-fetch
repository).
Related issue in node-fetch
: node-fetch/node-fetch#43
I encountered an issue with GLOBAL using fetch-mock to test a React app. It is the same error as the one posted here: http://stackoverflow.com/questions/35633044/fetch-mock-global-is-not-defined. I used their suggested workaround and it worked for my use-case.
Something as simple as replacing global
here https://github.com/wheresrhys/fetch-mock/blob/master/src/server.js#L11 with GLOBAL || global
would allow this to work on client as well as server.
I am able to get fetch-mock to work great with jsdom by using global.fetch = require('node-fetch');
, but unable to get it to work with Karma/PhantomJS/Chrome. I am sure there is something small I am missing (hopefully).
Here is the error I am getting:
PhantomJS 2.1.1 (Mac OS X 0.0.0)
Chrome 49.0.2623 (Mac OS X 10.11.3)
Error: Not Found
at /Users/chris/github/frontend/tests.webpack.js:65225:22 <- webpack:///src/pages/actions.js:49:20
karma.js:
...
plugins: [
// https://gist.github.com/Couto/b29676dd1ab8714a818f#gistcomment-1584602
new webpack.ProvidePlugin({
fetch: 'exports?self.fetch!whatwg-fetch',
}),
...
test.js:
...
afterEach(() => {
fetchMock.restore();
});
it('create - success', function () {
fetchMock.mock('/api/v1/new', {
status: 200,
body: { responseCode: 100 },
});...
...
fetch('/api/v1/new', {
method: 'post',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
...
If you have any thoughts please let me know.
Can make mocking multiple routes more onerous to set up, so would like to fallback to use matcher.toString()
as the route name. If the user wants to access a particular route's calls they can specify a name for it as a convenience
calls()
should probably always return an array of all fetch-mock calls in order, but this would be a breaking change.New method allCalls()
/orderedCalls()
? Or v3?
I'm testing the same url route in a few different tests, i.e one test to see if a 200 response is handled correctly another to check that 400 response is handled correctly. fetch-mock seems to remember the mocked routes between tests and this obviously causes issues when you need the mocked url to return a different response. I'm currently setting the routes array to an empty array before each test. Is there a better way? reset() seems to only clear calls, matched call etc. Thanks
Mainly around require('debug')
Need to investigate best solution
be good
also maybe lastUrl()
and lastOptions()
Consider behaviour when fetch called with a Request
Look at the sinon spy API and consider which methods would be really useful to port over
2 use cases
Hi,
I'm trying to use fetch-mock in my mocha tess. The tests are put through webpack and then run via the mocha
command in terminal. When I do this however, I get the following error related to requiring fetch-mock:
/built/bundle.js:8147
theGlobal: window,
^
ReferenceError: window is not defined
at Object.i (/Users/fabioberger/Projects/js/dali-client/tests/built/bundle.js:8147:14)
It seems that window
is not defined when running the webpack generated bundle.js outside of the browser. Is there a work around to this?
Thanks!
Is there any way to delay a response for a certain amount of time?
Are there plans to support node-fetch's .json()
method? If not, is there a workaround I'm missing?
I tried to mock server delays and I needed a Promise to be created at a time when a request is made to a mocked url, not at a time when we define how to mock a response.
The current implementation does not currently handle a case when the response is mocked as a function returning a Promise. To fix it for my needs I added one line to fetchMock function, like this:
fetchMock (url, opts) {
const response = this.router(url, opts);
if (typeof response === 'function') response = response(url, opts); // <-- the new line
It moves evaluating the "mocking function" from mockResponse to fetchMock because fetchMock has proper logic (using "response.then") for Promises.
Hi,
Sorry if this isn't the right place to put this however im really struggling to get this working. Ive explained the issue I'm having here http://stackoverflow.com/questions/34574682/unable-to-get-fetch-mock-working-with-webpack-and-redux-react.
Im not sure if I am doing something completely wrong but ive tried so many different things and this is my last resort. Any help would be appreciated.
Thanks
I have a strange error happening in 1.9 PhantomJS and latest Safari environments
TypeError: undefined is not an object (evaluating 'Request.prototype')
pointing me to
Line 78 in b0ca36c
I use it in my test like this
import fetchMock from 'fetch-mock'
//...
fetchMock.mock('http://my.api.url/v1/example', [{ ... }])
In Chrome, Firefox everything seems to work well.
Why could it happen and are there any advices how to debug it properly?
Apologies for copying everyone in. I want to know if anyone's using the advanced features of this module https://github.com/wheresrhys/fetch-mock#advanced-usage? I'm planning on removing them in v4 and instead just documenting a few examples of how to achieve similar behaviour using beforeEach()
blocks and .mock()
chaining.
Speak now or forever hold your peace! (And happy New Year)
@meabed @dannynelson @choonkending @jwarby @JamesLuoau @developit @dominictobias @vbauerster @jfairbank @vyorkin @yagudaev @enricomarino @Rastopyr @danawoodman @noisecapella @goblindegook @vagusX @LucaColonnello @akatebi @pwalsh @albburtsev @sapegin @voy @badenkov @NOX73 @maksad @bs1180 @kaid @troybetz @yanivtal @mathieumg @sairion @christopherscott @s-shin
This library rejects the promise when you set promise config.greed = bad
(ref), but the fetch specification states:
The Promise returned from fetch() won't reject on HTTP error status even if the response is a HTTP 404 or 500. Instead, it will resolve normally, and it will only reject on network failure, or if anything prevented the request from completing.
https://github.com/github/fetch#caveats
We should just resolve as normal here.
DELETE ME PLEASE
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.