vitest-mock-axios
Version:
Axios mock for Vitest
297 lines (292 loc) • 8.43 kB
JavaScript
// lib/mock-axios.ts
import { vi } from "vitest";
import { SynchronousPromise } from "synchronous-promise";
// lib/cancel/Cancel.ts
var Cancel = class {
constructor(message = "Cancel") {
this.message = message;
this.__CANCEL__ = true;
}
toString() {
return this.message;
}
};
var Cancel_default = Cancel;
// lib/cancel/CancelToken.ts
var CancelToken = class {
static source() {
let cancel;
const token = new CancelToken((c) => cancel = c);
return {
cancel,
token
};
}
constructor(executor) {
const token = this;
this.promise = new Promise((resolve) => {
token.resolvePromise = resolve;
});
executor(function cancel(message) {
if (token.reason || !token.resolvePromise) {
return;
}
token.reason = new Cancel(message);
token.resolvePromise(token.reason);
});
}
throwIfRequested() {
if (this.reason) {
throw this.reason;
}
}
};
// lib/mock-axios.ts
var _pending_requests = [];
var _responseInterceptors = [];
var _requestInterceptors = [];
var processInterceptors = (data, stack, type) => {
return stack.map(({ [type]: interceptor }) => interceptor).filter((interceptor) => !!interceptor).reduce((_result, next) => {
return next(_result);
}, data);
};
var _newReq = (config = {}, actualConfig = {}) => {
if (typeof config === "string") {
actualConfig.url = config;
config = actualConfig;
}
const method = config.method || "get";
const url = config.url;
const data = config.data;
const promise = SynchronousPromise.unresolved();
if (config.cancelToken) {
config.cancelToken.promise.then((cancel) => {
if (_pending_requests.find((x) => x.promise === promise)) {
MockAxios.mockError(cancel, promise);
}
});
}
const requestConfig = processInterceptors({
config,
data,
method,
promise,
url
}, _requestInterceptors, "onFulfilled");
_pending_requests.push(requestConfig);
return promise;
};
var _helperReq = (method, url, data, config) => {
const conf = data && config ? config : {};
return _newReq({
...conf,
data,
method,
url
});
};
var _helperReqNoData = (method, url, config) => {
return _helperReq(method, url, {}, config);
};
var MockAxios = vi.fn(_newReq);
MockAxios.get = vi.fn(_helperReqNoData.bind(null, "get"));
MockAxios.post = vi.fn(_helperReq.bind(null, "post"));
MockAxios.put = vi.fn(_helperReq.bind(null, "put"));
MockAxios.patch = vi.fn(_helperReq.bind(null, "patch"));
MockAxios.delete = vi.fn(_helperReqNoData.bind(null, "delete"));
MockAxios.request = vi.fn(_newReq);
MockAxios.all = vi.fn((values) => Promise.all(values));
MockAxios.head = vi.fn(_helperReqNoData.bind(null, "head"));
MockAxios.options = vi.fn(_helperReqNoData.bind(null, "options"));
MockAxios.create = vi.fn(() => MockAxios);
MockAxios.interceptors = {
request: {
use: vi.fn((onFulfilled, onRejected) => {
return _requestInterceptors.push({ onFulfilled, onRejected });
}),
eject: vi.fn((position) => {
_requestInterceptors.splice(position - 1, 1);
}),
clear: vi.fn(() => {
_requestInterceptors.length = 0;
})
},
response: {
use: vi.fn((onFulfilled, onRejected) => {
return _responseInterceptors.push({ onFulfilled, onRejected });
}),
eject: vi.fn((position) => {
_responseInterceptors.splice(position - 1, 1);
}),
clear: vi.fn(() => {
_responseInterceptors.length = 0;
})
}
};
MockAxios.defaults = {
headers: {
common: []
}
};
MockAxios.popPromise = (promise) => {
if (promise) {
for (let ix = 0; ix < _pending_requests.length; ix++) {
const req = _pending_requests[ix];
if (req.promise === promise) {
_pending_requests.splice(ix, 1);
return req.promise;
}
}
} else {
const req = _pending_requests.shift();
return req ? req.promise : void 0;
}
};
MockAxios.popRequest = (request) => {
if (request) {
const ix = _pending_requests.indexOf(request);
if (ix === -1) {
return void 0;
}
_pending_requests.splice(ix, 1);
return request;
} else {
return _pending_requests.shift();
}
};
var popQueueItem = (queueItem = null) => {
const request = MockAxios.popRequest(
queueItem
);
if (request) {
return request.promise;
} else {
return MockAxios.popPromise(queueItem);
}
};
MockAxios.mockResponse = (response, queueItem = null, silentMode = false) => {
response = Object.assign(
{
config: {},
data: {},
headers: {},
status: 200,
statusText: "OK"
},
response
);
let promise = popQueueItem(queueItem);
if (!promise && !silentMode) {
throw new Error("No request to respond to!");
} else if (!promise) {
return;
}
for (const interceptor of _responseInterceptors) {
promise = promise.then(interceptor.onFulfilled, interceptor.onRejected);
}
promise.resolve(response);
};
MockAxios.mockResponseFor = (criteria, response, silentMode = false) => {
if (typeof criteria === "string") {
criteria = { url: criteria };
}
const queueItem = MockAxios.getReqMatching(criteria);
if (!queueItem && !silentMode) {
throw new Error("No request to respond to!");
} else if (!queueItem) {
return;
}
MockAxios.mockResponse(response, queueItem, silentMode);
};
MockAxios.mockError = (error = {}, queueItem = null, silentMode = false) => {
let promise = popQueueItem(queueItem);
if (!promise && !silentMode) {
throw new Error("No request to respond to!");
} else if (!promise) {
return;
}
if (error && typeof error === "object" && error.isAxiosError === void 0) {
error.isAxiosError = true;
}
for (const interceptor of _responseInterceptors) {
promise = promise.then(interceptor.onFulfilled, interceptor.onRejected);
;
}
promise.reject(error);
};
MockAxios.isAxiosError = (payload) => typeof payload === "object" && payload.isAxiosError === true;
MockAxios.lastReqGet = () => {
return _pending_requests[_pending_requests.length - 1];
};
MockAxios.lastPromiseGet = () => {
const req = MockAxios.lastReqGet();
return req ? req.promise : void 0;
};
var _findReqByPredicate = (predicate) => {
return _pending_requests.slice().reverse().find(predicate);
};
var _checkCriteria = (item, criteria) => {
if (criteria.method !== void 0 && criteria.method.toLowerCase() !== item.method.toLowerCase()) {
return false;
}
if (criteria.url !== void 0 && criteria.url !== item.url) {
return false;
}
if (criteria.params !== void 0) {
if (item.config === void 0 || !item.config.params || typeof item.config.params !== "object") {
return false;
}
const paramsMatching = Object.entries(criteria.params).every(([key, value]) => item.config.params[key] === value);
if (!paramsMatching) {
return false;
}
}
return true;
};
MockAxios.getReqMatching = (criteria) => {
return _findReqByPredicate((x) => _checkCriteria(x, criteria));
};
MockAxios.getReqByUrl = (url) => {
return MockAxios.getReqMatching({ url });
};
MockAxios.getReqByMatchUrl = (url) => {
return _findReqByPredicate((x) => url.test(x.url));
};
MockAxios.getReqByRegex = (opts) => {
return _findReqByPredicate((x) => Object.entries(opts).every(([key, value]) => value.test(JSON.stringify(x[key]))));
};
MockAxios.queue = () => {
return _pending_requests;
};
MockAxios.reset = () => {
_pending_requests.splice(0, _pending_requests.length);
MockAxios.get.mockClear();
MockAxios.post.mockClear();
MockAxios.put.mockClear();
MockAxios.patch.mockClear();
MockAxios.delete.mockClear();
MockAxios.head.mockClear();
MockAxios.options.mockClear();
MockAxios.request.mockClear();
MockAxios.all.mockClear();
MockAxios.interceptors.request.clear();
MockAxios.interceptors.response.clear();
};
MockAxios.Cancel = Cancel_default;
MockAxios.CancelToken = CancelToken;
MockAxios.isCancel = (u) => {
return !!(u && u.__CANCEL__);
};
var mock_axios_default = MockAxios;
// lib/index.ts
var lib_default = mock_axios_default;
export {
lib_default as default
};
/**
* TypeScript version of Axios mock for unit testing with [Vitest](https://vitest.dev/).
* This file is based on https://gist.github.com/tux4/36006a1859323f779ab0
*
* @author jacksonGross <jackson.gross@gmail.com>
* @license @license MIT License, http://www.opensource.org/licenses/MIT
*/