-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add proxy handler to original XHR #18
Conversation
Seems checks failed due to old node 0.10 (one of modules uses arrow functions)? Is it ok to have such old node? :) |
Also I have idea, why do not put dist into package also? User by default will not build package. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @AlehVasilyeu. Thanks for your PR!
Unless we need to bump the major version kets keep supporting the same versions of node, and support for arrow functions in the browser isn't quite there I believe so unless we add a transpilation step I don't think we can use arrow functions.
Yep sure, create a UMD build.
// otherwise assume the url is a string | ||
return url === reqUrl; | ||
function match(string, pattern) { | ||
return new RegExp(pattern).test(string); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking change and I don't think it is quite correct because this code will turn everything into a RegExp
XXXGETXXX
will be match GET
.
Adding the ability to use RegExp
to match the method is a great idea 👍 , but like the previous version of the code, please make the RegExp
opt-in.
e.g.
function match(string, pattern) {
if (pattern instanceof RegExp) {
return pattern.test(string);
} else {
return string === pattern;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will fix it.
var real = window.XMLHttpRequest; | ||
var mock = MockXMLHttpRequest; | ||
|
||
window.xhrMockProxyHandler = require('./lib/xhr-mock-proxy-handler'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was meaning this could be its own npm package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure what you mentioned in issue. So I agree it's better, let's create a separate NPM package for this. Could we refer to it in README after it will be created?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also maybe do you have ideas how this package should look like? Should it use browserify as well?
And how will it integrated with your package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user is using browserify/webpack they'll just be able to require
/import
it.
const xhrMock = require('xhr-mock');
const xhrMockProxyHandler = require('xhr-mock-proxy-handler');
If the user is using the library directly in the browser without browserify/webpack we'll need to use browserify/webpack/rollup to generate a UMD.
<script src="path/to/xhr-mock/dist/xhr-mock.min.js"></script>
<script src="path/to/xhr-mock-proxy-handler/dist/xhr-mock-proxy-handler.min.js"></script>
<script>
window.XHRMock;
window.XHRMockProxyHandler
</script>
Feel free to keep developing the handler as part of this PR so I can review it, then you can move it to its own package right before I merge the PR.
@@ -158,40 +159,45 @@ MockXMLHttpRequest.prototype.send = function(data) { | |||
|
|||
var response = MockXMLHttpRequest.handle(new MockRequest(self)); | |||
|
|||
if (response && response instanceof MockResponse) { | |||
Promise.resolve(response).then(function(response) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that this will handle the case where a promise has been returned by a handler without a response i.e. the handler did something async but still couldn't handle the response.
Should it handle that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I think if request wasn't handled by promise it should be rejected. In other case this promise will be resolved, when passed promise resolved as well.
I tried to do postponed call in xhr-mock-proxy-handler
using setTimeout with 5 seconds awaiting. And run written tests, tests passed.
If I incorrectly understood you, please correct me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the current implementation of MockXMLHttpRequest.handle
, handlers must return a falsey
value in order to signify they don't want to handle the request.
That means if any of the handlers returns a Promise
(which is truthy
), and the Promise
does not resolve
to a response, the MockXMLHttpRequest.handle
method won't continue to loop through the other handlers and the xhr-mock
will error because no response was returned, even if there was another handler that would have returned a response.
e.g.
function handler(req, res) {
return new Promise(function(resolve, reject) {
//resolving without a response if we decided to not handle the request
setTimeout(resolve, 100);
});
}
This feels like an edge case (creating a handler that asynchronously decides not to return a response) but a bug none-the-less. I wonder if we should handle this in the MockXMLHttpRequest.handle
method?
e.g.
//untested code:
MockXMLHttpRequest.handle = function(request) {
var promise = Promise.resolve();
for (var i=0; i<MockXMLHttpRequest.handlers.length; ++i) {
promise = promise.then(function(response) {
//if one of the previous handlers has already returned a response, use that
if (response) {
return response;
}
return Promise.resolve(MockXMLHttpRequest.handlers[i](request, new MockResponse()));
});
}
return promise;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jameslnewell Interesting point but i'm not sure that we need this.
Let's look on this:
/**
* Mock a request
* @param {string} [method]
* @param {string} [url]
* @param {Function} fn
* @returns {exports}
*/
mock: function(method, url, fn) {
var handler, matcher;
if (arguments.length === 3) {
function match(string, pattern) {
return new RegExp(pattern).test(string);
}
handler = function(req, res) {
if (match(req.method(), method)
&& match(req.url(), url)) {
return fn(req, res);
}
return false;
};
} else {
handler = method;
}
MockXMLHttpRequest.addHandler(handler);
},
We already return false in case if request doesn't match. This doesn't matter what is Response (MockResponse or Promise) and our send()
should handle this correctly, trigger error event.
Another case, we have mapping for ANY response with just handler as you mentioned above
function handler(req, res) {
return new Promise(function(resolve, reject) {
//resolving without a response if we decided to not handle the request
setTimeout(resolve, 100);
});
}
Yes it will return no response and this will trigger error event as well, what is correct for me.
But in my opinion is not correct if XHR MOCK will try to return response from another request handler that was able fulfill it, it's weird.
I think Developer who use this tool should be careful when specifies mocked requests
What if he has mocked several requests for ANY requests but one responses with timeout and another returns immediately. Which one should response to him? First or second? Or maybe developer should be accurate and clean old mocks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think should be used first matched handler, and if it returns no response this is responsibility of developer to write correct one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway I guess current implementation of handlers could be improved, it iterates across all handler to find suitable. What if use Object instead Array? What do you think?
@@ -19,17 +19,22 @@ | |||
"url": "git://github.com/jameslnewell/xhr-mock.git" | |||
}, | |||
"dependencies": { | |||
"browserify": "^11.0.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can browserify and uglify be moved to the dev dependencies please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, i will try to do build into dist before publish. So move dependencies to dev again.
"example.build": "mkdir -p build && browserify -r superagent -r ./index.js:xhr-mock -o build/build.js" | ||
"build": "mkdir -p dist && browserify -r lie -r ./index.js:xhr-mock -o dist/xhr-mock.js", | ||
"build:example": "browserify -r lie -r superagent -r ./index.js:xhr-mock -o example/xhr-mock.js", | ||
"minify": "uglifyjs dist/xhr-mock.js --output dist/xhr-mock.min.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you including this lib via a script tag in the browser? how are you including and requiring it? can you make it spit out a UMD build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use selenium, so I inject script into page. I would like to minify it, so it will speedup.
I think superagent required only for examples, not for everyone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I more meant, how are you require
ing the script on the page? same as the xhr-mock
examples?
We should probably generate a UMD (browserify --standalone
option).
|
||
module.exports = function(req, res) { | ||
return new Promise(function(resolve, reject) { | ||
var xhr = new realXMLHttpRequest(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How portable is directly relying on XMLHttpRequest? Isn't there a reason there's so many wrappers (browser support)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't unable to use axios
as you recommended, because it access window.XmlHttpRequest, which can be hidden by xhr-mock. I'm afraid that some else wrapper libraries could do same thing :(
This should be enough portable, maybe some old IE could cause problems. But as I understand you mock XMLHttpRequest as well, not some ActiveX objects from old IEs.
If you mean portability on NodeJS there is xmlhttprequest https://www.npmjs.com/package/xmlhttprequest that behaves like regular XMLHttpRequest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points! Lets leave this as-is.
"build": "mkdir -p dist && browserify -r lie -r ./index.js:xhr-mock -o dist/xhr-mock.js", | ||
"build:example": "browserify -r lie -r superagent -r ./index.js:xhr-mock -o example/xhr-mock.js", | ||
"minify": "uglifyjs dist/xhr-mock.js --output dist/xhr-mock.min.js", | ||
"postinstall": "npm run build && npm run minify" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prepublish
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool idea!
@@ -98,9 +98,13 @@ Register a factory function to create mock responses for each PATCH request to a | |||
|
|||
Register a factory function to create mock responses for each DELETE request to a specific URL. | |||
|
|||
#### .mock(method, url | regex, fn) | |||
#### .any(fn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's your reasoning for creating a new fn (.mock()
will already take a fn)
(note: I like the name better than mock!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my fault i missed that .mock()
can configure MockXMLHttpRequest to handle any requests.
Because it's a little bit confusing how it was written (I'm not a Javascript adept). Maybe we can leave behavior you desined but create alias method if you like naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sorry, the docs probably aren't ideal here. Would this be clearer?
.mock(method: String|RegExp, url: String|RegExp, fn: Function)
.mock(fn: Function)
Lets leave out the alias for now (I like to avoid creating multiple ways of doing the same thing - I feel it makes it more difficult for the user to figure out which method to use).
I have read up on this thread. It comes at exactly the right time for me: I started looking for a mocked version of xhr last week and was not able to find exactly what I need. This package (xhr-mock) came closest, with just those things missing that are being handled in this PR: having a build/browserified version directly in the NPM package and the proxy functionality, where unmocked requests get forwarded to the real xhr object. If I may give my opinion on some topics addressed in this PR discussion:
If I can help out in any way, please let me know. |
Reposting my comment: 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 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? Alternatively, check if one is loaded before loading lie? Something like:
|
Hi, guys, sorry I tied up with work, so I had no time to finish PR. I hope to update it this weekend. @niekbosch I added Your solution about using existing Promise object instead requiring new is pretty good. I can add it, if you are ok with this solution. |
is there any movement on this? Our dev team is very keen to have this functionality. |
@continuata I've released |
|
@niekbosch Note: The UMD bundle isn't documented in |
Hi, here is pull requests that covers issue #11, also additionally slightly changed building.