UNPKG

vitest-mock-axios

Version:
297 lines (292 loc) 8.43 kB
// 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 */