jameslnewell / xhr-mock Goto Github PK
View Code? Open in Web Editor NEWUtility for mocking XMLHttpRequest.
Utility for mocking XMLHttpRequest.
Thank you, this module is super useful!
making it really hard to debug when devs didn't actually intend to throw an error.
I think its happening in https://github.com/jameslnewell/xhr-mock/blob/master/packages/xhr-mock/src/MockXMLHttpRequest.ts#L523
Note: we probably don't want to log errors when they are intended (and fill up logs/false positives).
it('oops', async () => {
mock.post('/api/user', () => {
throw new Error('oops');
});
try {
const user = await createUser({name: 'John'});
} catch (error) {
// no idea what the user did wrong in their mock
expect(error).toMatch('A user named "John" already exists.');
}
})
๐ Hey ppl using xhr-mock
. Please let me know when you think v2 is stable enough to release on the masses!
It would be nice if XHRMock run normal request when someone open url that's not mocked.
As per spec, the XMLHttpRequest constructor should define the constants UNSENT = 0, OPENED = 1, HEADERS_RECEIVED = 2, LOADING = 3 and DONE = 4. Otherwise, the following snippet doesn't work as intended when using xhr-mock:
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
// ...
}
}
Using 'lie' as a Promise implementation gives me problems when using xhr-mock in an Angular 2 project. It does not work well with zone.js. Just removing the var Promise = require('lie');
lines, make it work nicely.
In node.js, there is a (native) implementation for promises. And most modern browsers seem to have one as well. Is there any particular reason why lie is used?
If not, would it be possible to leave it up to the user (of your library) to load a polyfill? Or, probably better (because backwards compatible), check if one is loaded before loading lie? Something like:
if (undefined === Promise) {
var Promise = require('lie');
}
Looks like this can be fixed by adding setter and getter in MockResponse and calling setter in proxy
I can make a PR if it's acceptable.
After upgrading to version 2.3.0 I get some of the following errors when running my tests:
console.error node_modules/xhr-mock/lib/MockXMLHttpRequest.js:673
xhr-mock: A handler errored:
Error: xhr-mock: No handler returned a response.
at /home/pacha/web/cerebral/auth-boilerplate/node_modules/xhr-mock/lib/handle.js:31:19
at <anonymous>
But the tests are still passing.
One example test which throws to console:
import mock from 'xhr-mock'
import { CerebralTest } from 'cerebral/test'
import app from '.'
beforeEach(() => {
mock.setup()
localStorage.removeItem('jwtHeader')
})
test('should refresh token when expired token and refresh allowed', async () => {
expect.assertions(2)
localStorage.setItem(
'jwtHeader',
JSON.stringify(authHeader.expiredRefreshableJwt)
)
let cerebral = CerebralTest(app({ flash: null, flashType: null }))
mock.get('/api/refresh', (req, res) => {
return res
.status(200)
.header('Content-Type', 'application/json')
.header('Authorization', authHeader.validJwt)
})
await cerebral
.runSignal('appMounted')
.then(({ state }) => [
expect(state.user.authenticated).toBe(true),
expect(state.user.nickname).toBe('Tester'),
])
})
I do not really understand why it throws this error.
e.g. cookie is frequently used
I am doing a sync xhr call with mocha-sinon and i am not able to run it properly. Any idea?
This error is very vague; I have no idea what feature is not implemented. :O
For reference, here is what I tried doing:
var xhrMock = require('xhr-mock')
xhrMock.setup()
xhrMock.post('http://localhost:4567/foo', function(req, res) {
return res
.status(201)
.header('Content-Type', 'application/json')
.body(JSON.stringify({
created: true
}))
})
var send = return new Promise( (resolve, reject) => {
var request = new XMLHttpRequest()
request.open('POST', 'http://localhost:4567/foo', true)
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
request.addEventListener('load', function onLoad(res) {
console.log('res', res)
resolve(JSON.parse(res.responseText))
})
request.addEventListener('error', function onXMLHttpRequestError(e) {
reject(e)
})
request.send(pkg)
})
send()
I figured it out, after some debugging, but it should be either changed or documented better.
EXAMPLE:
I have a myUrl
with some search params like this: https://developer.api.acmecorp.com/content/v1/contentsSearch?filter[contents][libraryId]=urn:acme.content:library:a0d5b7b4-85cb-46f1-8df5-294f16993702&filter[contents][entityType]=content&filter[contents][searchSkipCache]=True&filter[contents][query]=title:Ellipse&page[size]=50&page[number]=1
(Pardon the extra length, it could probably be trimmed a bit for a demo - I know!)
Then I prepare to receive the call like so:
mock.get(myUrl, (req, res) => {
...
});
And expect a call xhr.open('get', myUrl)
somewhere in the code to be handled by the mock. Instead I get an Error like this:
console.error node_modules\xhr-mock\lib\MockXMLHttpRequest.js:671
xhr-mock: No handler returned a response for the request.GET https://developer.api.acmecorp.com/content/v1/contentsSearch?filter%5Bcontents%5D%5BlibraryId%5D=urn%3Aacme.content%3Alibrary%3Aa0d5b7b4-85cb-46f1-8df5-294f16993702&filter%5Bcontents%5D%5BentityType%5D=content&filter%5Bcontents%5D%5BsearchSkipCache%5D=True&filter%5Bcontents%5D%5Bquery%5D=title%3AEllipse&page%5Bsize%5D=50&page%5Bnumber%5D=1 HTTP/1.1
content-type: application/vnd.api+json
accept: application/vnd.api+json
Of course, stuff has been encoded! But how exactly?! Something like encodeURI(myUrl)
gets me oh-so-close, but no thanks! It leaves the ':'-s intact, unlike the path displayed in the error above.
After some digging, it seems that xhr-mock's internally compares to something like this, during the lookup phase:
const encodedUrl = url.format( {...(url.parse(myUrl, true)), search: undefined} );
mock.get(encodedUrl, (req, res) => {
...
At least this works in my case!
I am not sure if this is a bug or not, but as a minimum it should be documented, if not fixed. The ideal fix being "One can use the same URLs for xhr.open()
and mock.xxx()
."
Very nice package - many thanks for the effort!
currently, req.body() always returns undefined. I think it's a simple adding of
this.body(xhr.data);
in the MockRequest constructor.
Hello, @jameslnewell .
I want to simulate a time gap to get the response. To achieve this goal I use
.timeout(timeout : bool|number)
function according to your spec. However the call of this function with any arguments throws the exception 'timeout of 0ms exceeded'
var mock = require('xhr-mock');
mock.setup();
mock.get(/(api\/users).*/, function(req, res) {
return res.timeout(1000).status(200).body('<h1>Google</h1>');
});
var axios = require('axios');
axios({url: 'api/users'}).then(
function(res) {
console.log('loaded', res.data);
},
function(error) {
console.log('ERROR', error);
}
);
In MockXMLHttpRequest.prototype.open function, on following line, 'self' needs to be replaced with 'this'.
self.readyState = MockXMLHttpRequest.STATE_OPENED;
When using RegEx, my request is not matching mock.
Request against 'https://localhost.fake/api/uploads/test/123456'.
For mock, I've tried
mock.mock('PUT', /.*\/uploads\/.*/,
(req, res) => res.status(200).body("")
);
and
mock.put(/.*\/uploads\/.*/,
(req, res) => res.status(200).body("")
);
It works fine when I use the actual url, but does not seem to match against various valid RegExs that I've tried. Am I formatting this incorrectly? Is it possible to use a wildcard?
It is not possible to set statusText like status e.g.
return res.status(201) --> works
return res.statusText("Unauthorized") --> not implemented?
Would you like to see it implemented?
In version 2.0.3
, trying to mock xhr requests for an AjaxObservable result in an empty response even if the response is a string, it does work in 2.0.0-preview.13
.
For example:
import { ajax } from 'rxjs/observable/dom/ajax';
import { map, retryWhen, scan, delay } from 'rxjs/operators';
import xhrMock from 'xhr-mock';
xhrMock.post('/some-url', {
body: JSON.stringify({data: 'mockdata'}),
});
ajax({
'/some-url',
body: {some: 'something'},
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
responseType: 'json',
}).subscribe((result) => console.log(result.response) ); // response is null here
However, it works in 2.0.0-preview.13
passing and object to xhr-mock:
xhrMock.post('/some-url', {
body: {data: 'mockdata'},
});
running in the browser (and node if supported by the package)
I think the behavior I am seeing is that when proxy.browser is used to proxy synchronous requests I get an error because, the proxy seems to always returns a Promise:
Which fails on this check sendSync:
Similar to the patch for XMLHttpRequest.addEventListener, there should be an opaque XMLHttpRequest.upload object for tracking progress of uploads.
I just made a silly error which took me all morning to find.
Browsers handle GET and POST case-insensitively but XHR-mock does not.
https://stackoverflow.com/questions/7790576/what-are-http-method-capitalization-best-practices
-- in line 90 of index.js for xhr-mock
post: function(url, fn) {
return this.mock('POST', url, fn);
}
this string is compared to the method sent from the code being tested, if your code sends lower case it will fail, (not sure if you want to str.toUpperCase() or just let it fail)
Obviously I think it's best practice to always capitalise http methods but this was a slip up which was not obvious (since the code worked but the test failed)
Hope it's useful to someone.
James
Suppose we have the following in onreadystatechange
:
let result = this.responseXML || this.responseText || this.response;
As responseXML
is not implemented, xhr-mock outputs the message This feature hasn't been implmented yet. Please submit an Issue or Pull Request on Github.
However, in the snippet above we have a workaround, as long as we're not expecting an XML Document
in our tests. Rather than just returning undefined
and making the code under test try responseText
, the mock just gives up.
in order to support matching query strings
Why does an error fire if we put a string in the send ()?
Is not it better to leave the body empty and follow?
Or maybe to put a flag that does not need to put a string
e.g. have to return a response - the response is passed just for convenience
fetch()
progress()
.send()
with async=false
browser
fieldHi
Seems that you support Regex in createMockFunction
but not in post
etc. TypeScript doesn't like it.
In my test case I'm expecting an HTTP error, so I mocked XHR response like this:
xhrmock.get('dummy.host/schemas', {
status: 500,
reason: 'Internal Server Error',
body: 'Internal Server Error',
})
How to avoid the follow message to be printed?
PASS tests/schemas.spec.js
Console
console.error node_modules/xhr-mock/lib/MockXMLHttpRequest.js:674
xhr-mock: No handler returned a response for the request.
GET dummy.host/schemas HTTP/1.1
https://github.com/jameslnewell/xhr-mock/blob/master/packages/xhr-mock/src/MockXMLHttpRequest.ts#L73
Great library!
However, I did not find a way to test my timeout handlers. Basically, I want the fake server to hang and not answer anything so that my timeout handler steps in.
See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout
From #32:
Currently only one type of error handling is implemented (and it doesn't call loadend
) and we don't have a way to tell xhr-mock
which type of error handling to execute. We need to implement a way for developers to indicate which error handling we should use.
Something like this could work???
import mock, {RequestError, ResponseError, EndOfBodyError} from 'xhr-mock';
mock.get('/', () => Promise.reject(new ResponseError()));
res.url().query
does not seem to work yet
I'd like to add a delay to every response (I'm doing some manual testing in the browser and want to simulate how a real server may feel). Is this possible to do? I don't see anything documented.
Thanks!
Bug Description
When making a proxied xhr request with application/x-www-form-urlencoded;charset=utf-8
data, the request body is not passed along to the real request.
Expected Behavior
Proxy passes the form data to the real request.
Proper API docs. A website instead of a gigantic readme?
Some of your examples actually have syntax errors, so it might be worth cleaning that up.
Do we can replace the global XMLHttpRequest only for one request? Right now, if you make .setup()
all others XMLHttpRequest, that doesn't have mocks, doesn't work.
Hey, thanks for this nice library.
It seems like when I tried to mock the post request and then make the request with a body, i got the following errors one after the other in MockXMLHttpRequest.js file.
Document is undefined
Blob is undefined
FormData is undefined
In order to make my post request work I had to do the following in my test file at the top.
import {JSDOM} from 'jsdom';
import {Blob} from 'blob-polyfill';
import FormData from 'form-data';
global.window = (new JSDOM()).window;
global.Document = window.Document;
global.Blob = Blob;
global.FormData = FormData;
My test environment is nodejs v8.9.1
Are you are missing these dependencies?
Blocked by Typescript (microsoft/TypeScript#19830).
(78d5094)
The errors is explained with Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
.
I tried .header('Access-Control-Allow-Origin', '*')
, but the error remains. Any idea what I could do next?
Hello, team.
I want to match the set of URLs, which are different with query parameters only. To achieve this goal, I pass regex instead of string to mock.get as the first parameter according to your specification
.get(url | regex, fn)
This approach misses the passed URL one time in a set of two requests if the regex value contains the global modifier (\g).
var mock = require('xhr-mock');
mock.setup();
mock.get(/(api\/users).*/g, function(req, res) {
return res.status(200).body('<h1>Google</h1>');
});
// ---------
var axios = require('axios');
setInterval(function() {
axios({url: 'api/users'}).then(
function(res) {
console.log('loaded', res.data);
},
function(error) {
console.log('ERROR', error);
}
);
}, 2000);
As the result, we will get the error at every second request. However, if we remove the global modifier from the regex, mock will start to work as expected.
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.