Skip to content
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

How to use with axios on Node? #15

Closed
d9k opened this issue Jul 28, 2021 · 7 comments
Closed

How to use with axios on Node? #15

d9k opened this issue Jul 28, 2021 · 7 comments

Comments

@d9k
Copy link

d9k commented Jul 28, 2021

global.fetch = require('node-fetch');
global.Headers = fetch.Headers;
MR = require('mock-requests');
global.axios = require('axios');

MR.setMockUrlResponse('http://localhost:1111/t', {
  mockExample: 1
});

fetch('http://localhost:1111/t').then((response) => response.json()).then(data => console.log(data));

axios.get('http://localhost:1111/t').then(resp => console.log(resp));
// request fails
@d9k
Copy link
Author

d9k commented Jul 28, 2021

As MockRequests doc says:

Full support for use along with third-party libraries, including Axios and jest, so they function as normal while still giving you the mocks you want.

axios on Node uses http and https

https://github.com/axios/axios/blob/e9965bfafc82d8b42765705061b9ebe2d5532493/lib/defaults.js#L17-L27

As far as I can understand MockRequests don't patch these node APIs.

@d9k
Copy link
Author

d9k commented Jul 28, 2021

Tried dirty workaround with https://www.npmjs.com/package/xmlhttprequest

global.fetch = require('node-fetch');
global.Headers = fetch.Headers;
global.XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
MR = require('mock-requests');
global.axios = require('axios');

MR.setMockUrlResponse('http://localhost:1111/t', {
  mockExample: 1
});

axios.get('http://localhost:1111/t').then(resp => console.log(resp));
// Error "Cannot read property 'headers' of undefined"
// at exports.XMLHttpRequest.getAllResponseHeaders at node_modules/xmlhttprequest/lib/XMLHttpRequest.js:239`

@d9k
Copy link
Author

d9k commented Jul 29, 2021

Had more luck with msw on Node.js out of the box:

msw = require('msw');
msw_node = require('msw/node');
axios = require('axios');

server = msw_node.setupServer(
  msw.rest.get(
    'http://localhost:1111/t',
    (req, res, ctx) => {
      return res(ctx.json({ firstName: 'John' }))
    }
  )
);

server.listen();

axios.get('http://localhost:1111/t').then(resp => console.log(resp));

// server.close();

@D-Pow
Copy link
Owner

D-Pow commented Jul 29, 2021

Interesting find! After doing a quick deep-dive, there seems to be two factors at play here:

  1. Node doesn't support fetch nor XMLHttpRequest.
  2. Axios never uses fetch, it only ever uses XMLHttpRequest or http(s).

For (1), using the polyfills directly seems to work relatively well, as you've shown with node-fetch.

For (2), Axios is supported for any environment that has fetch/XMLHttpRequest defined either natively or with a completely accurate polyfill. node-fetch seems to have a correct implementation of fetch in that the fields, classes, etc. are properly defined and default values properly filled in. However, the node-XMLHttpRequest implementation (a wrapper around url) seems to have a slight deviation in underlying implementation than the native, "normal" XMLHttpRequest. That deviation seems to be what's causing that error you see above -- some of the fields aren't being properly populated/defaulted so it's propagating the error upwards.

This would be a relatively simple fix so I'll try to push one up soon. Thanks for bringing this up, it will help create a better product!

@d9k
Copy link
Author

d9k commented Aug 2, 2021

@D-Pow, thanks for the answer!

I made pull request driverdan/node-XMLHttpRequest#191 for node-XMLHttpRequest which solves my error.

@D-Pow
Copy link
Owner

D-Pow commented Aug 2, 2021

Nice! If it's any help, the main thing I noticed that caused this issue was more that the response.headers was never defaulted like it is in native XMLHttpRequest.

Specifically, consider a case like this:

// Comments are console output.
/*** Native ***/
let xhr = new XMLHttpRequest();
// undefined
xhr.open('GET', '');
// undefined
xhr.getAllResponseHeaders()
// ""

Here, xhr has an internal default value of headers = {} so getAllResponseHeaders() would be the equivalent of return Object.entries(headers).reduce((str, [ headerKey, headerVal ]) => ..., ''); and wouldn't fail even if headers were empty.

So the key point I meant in my first reply is that they:

  1. Don't set default values on the response object, nor on headers and other response-based fields, i.e.
var headers = {};

var response = {
  // values from the response object that are copied over to their middle-man response object.
  // e.g.
  headers: headers,
  status: null, // or 1
  // ... other keys with default values
};
  1. Copy the default values to their middle-man response if they don't exist, i.e.
// First, applies defaults from original `response` in (1).
// Second, overwrites `response` fields from (1) if they're present in the actual response, `resp`.
response = Object.assign({}, response, resp);

If both (1) and (2) were addressed, there wouldn't be any other edge cases with other fields that you and I haven't figured out yet.

D-Pow added a commit that referenced this issue Nov 10, 2021
# Enhance XMLHttpRequest docs and implementation

This PR fixes issues [#14](#14), [#15](#15), and [#16](#16).

Primary changes:

* Add handlers for both `onload` and `onloadend` events in addition to `readystatechange` in order to support `axios@>=0.22.2`.
* Support both `on[event]` and `addEventListener(event)` methods for `XMLHttpRequest`.
* Add shim for usage in back-end/NodeJS scripts using `axios` with `XMLHttpRequest` polyfills.
* Add extensive documentation in the ReadMe for how to use MockRequests in the back-end/NodeJS scripts.

Secondary changes:

* Update both MockRequests and its demo to use `node@>=14` for better dependency resolution.
    - Requires replacing `node-sass` with `sass` and fixing the incorrect re-defining of `vendor` in both `entry` and `optimization` within webpack.config.js.
* Make homepage redirect to JSDoc website.
* Ensure Jest DOM is defined by changing setup files from `setupFiles` to `setupFilesAfterEnv`.
* Fix ReadMe links to work on npmjs.com (they already worked perfectly on GitHub, but npmjs.com is too primitive to understand renamed hyperlinks via `<a name="X"/>`).
* Simplify wrapper overriding logic.
* Add tests for all sorts of `addEventListener()` usages.
@D-Pow
Copy link
Owner

D-Pow commented Nov 10, 2021

This should be fixed in PR #17. Please let me know if you still encounter any issues!

@D-Pow D-Pow closed this as completed Nov 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants