Skip to content

Instantly share code, notes, and snippets.

@valotvince
Last active January 9, 2023 14:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save valotvince/ef8f70e8a565fbd723a7a0c806709a55 to your computer and use it in GitHub Desktop.
Save valotvince/ef8f70e8a565fbd723a7a0c806709a55 to your computer and use it in GitHub Desktop.
XHR ES6 Proxy
import config from './config/xmlhttprequest.config';
const debug = require('debug')('app:xhr-mock');
const XMLHttpRequest = window.XMLHttpRequest;
/**
* Retrieve the mock corresponding to the method / url couple
*
* @param {string} method
* @param {string} url
* @returns {boolean|Object|string}
*/
const retrieveMock = (method, url) => {
for (let i = 0; i < config.length; i++) {
const mocked = config[i];
const matches = url.match(new RegExp(mocked.pattern));
if (new RegExp(mocked.pattern).test(url)) {
return mocked[method.toLowerCase()](matches, mocked.fixtures());
}
}
return false;
};
/**
* Proxy that overrides the XMLHttpRequest constructor
*
* /!\ Reflect native class doesn't work on host objects like XMLHttpRequest
* so we have to map get and set ourselves
*
* @param {Object|null} options
* @returns {Proxy}
*
* @constructor
*/
const XMLHttpRequestProxy = options => {
return new Proxy(
new XMLHttpRequest(options),
{
get: (target, name, trap) => {
if (typeof target[name] === 'function') {
return (...args) => {
switch (name) {
case 'open':
target.mock = retrieveMock(args[0], args[1]);
target.mock.responseUrl = args[1];
if (target.mock) {
window.xhrStore.push(args[1]);
debug({...target.mock, url: args[1], method: args[0], mocked: true});
} else if (args[1].indexOf('localhost') !== -1 && args[1].indexOf('127.0.0.1') !== -1) {
debug({url: args[1], method: args[0], mocked: false});
}
break;
case 'send':
if (target.mock) {
target.mock.readyState = XMLHttpRequest.LOADING;
if (typeof target.onreadystatechange === 'function') {
target.onreadystatechange();
}
setTimeout(() => {
target.mock.readyState = XMLHttpRequest.DONE;
target.mock.status = target.mock.code;
target.mock.statusText = JSON.stringify(target.mock.code);
target.mock.statusCode = target.mock.code;
target.mock.response = target.mock.body;
target.mock.responseText = JSON.stringify(target.mock.body);
target.mock.responseXML = null;
if (typeof target.onreadystatechange === 'function') {
target.onreadystatechange();
}
}, 50);
// We won't call original send method
return;
}
break;
case 'abort':
if (target.mock) {
target.mock.readyState = XMLHttpRequest.DONE;
target.mock.status = 0;
target.mock.statusText = '0';
if (typeof target.onreadystatechange === 'function') {
target.onreadystatechange();
}
// We won't call original abort method
return;
}
break;
default:
break;
}
return target[name].apply(target, args);
}
}
if (target.mock && target.mock.hasOwnProperty(name)) {
return target.mock[name];
}
return target[name];
},
set: (target, name, value) => {
target[name] = value;
return true;
}
}
)
};
// Register XMLHttpRequestProxy as global
global.XMLHttpRequest = window.XMLHttpRequest = XMLHttpRequestProxy;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment