const fs = require("fs"); const path = require("path"); const vm = require("vm"); const rootDir = path.resolve(__dirname, ".."); const servicesDir = path.join(rootDir, "actions", "services"); const createAxiosMock = () => { const axios = (config) => axios.request(config); axios.calls = []; axios.requestHandler = async () => { throw new Error("No axios.request handler configured"); }; axios.getHandler = async () => { throw new Error("No axios.get handler configured"); }; axios.postHandler = async () => { throw new Error("No axios.post handler configured"); }; axios.request = (config) => { axios.calls.push({ type: "request", config }); return axios.requestHandler(config); }; axios.get = (url, config) => { axios.calls.push({ type: "get", url, config }); return axios.getHandler(url, config); }; axios.post = (url, data, config) => { axios.calls.push({ type: "post", url, data, config }); return axios.postHandler(url, data, config); }; return axios; }; const createLoggerMock = () => { const calls = []; const consoleLogger = (error) => { calls.push(error); }; return { consoleLogger, calls }; }; const createAxiosError = (status = 500, statusText = "Server Error") => { return { response: { status, statusText, data: {} }, config: { url: "/mock-url" } }; }; const loadServiceModule = (fileName, injected = {}) => { const filePath = path.join(servicesDir, fileName); let source = fs.readFileSync(filePath, "utf8"); source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, ""); const exportNames = Array.from( source.matchAll(/export const\s+(\w+)\s*=/g) ).map((match) => match[1]); source = source.replace(/export const\s+/g, "const "); source += `\nmodule.exports = { ${exportNames.join(", ")} };\n`; const defaultGetJson = (url, config) => { if (!injected.axios || !injected.axios.get) { throw new Error("Missing axios.get for default getJson mock"); } return injected.axios .get(url, config) .then((response) => response.data); }; const defaultRequestJson = (config) => { if (!injected.axios) { throw new Error("Missing axios for default requestJson mock"); } return injected.axios(config).then((response) => response.data); }; const defaultGetFileJson = (url) => { return defaultGetJson(url); }; const defaultBuildHashedQueryUrl = async (queryUrl) => { if (!injected.axios || !injected.axios.get) { throw new Error( "Missing axios.get for default buildHashedQueryUrl mock" ); } const hashResponse = await injected.axios.get( "/api/endpoint/gethash_api?path=" + encodeURIComponent(queryUrl) ); return queryUrl + hashResponse.data.hash; }; const defaultGetSignedFileJson = async (queryUrl) => { const hashedUrl = await ( injected.buildHashedQueryUrl || defaultBuildHashedQueryUrl )(queryUrl); return (injected.requestJson || defaultRequestJson)({ method: "get", url: hashedUrl }); }; const defaultDownloadFileBlob = (url) => { return (injected.requestJson || defaultRequestJson)({ method: "get", url, responseType: "blob" }); }; const defaultDeleteSignedJson = async (queryUrl, config = {}) => { const hashedUrl = await ( injected.buildHashedQueryUrl || defaultBuildHashedQueryUrl )(queryUrl); return (injected.requestJson || defaultRequestJson)({ method: "delete", url: hashedUrl, ...config }); }; const defaultBuildFileQuery = (pathValue, params = {}, options = {}) => { const { encode = false } = options; const entries = Object.entries(params).filter(([, value]) => { return value !== undefined && value !== null; }); if (entries.length === 0) { return pathValue; } const query = entries .map(([key, value]) => { if (!encode) { return `${key}=${String(value)}`; } return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`; }) .join("&"); return `${pathValue}?${query}`; }; const defaultWithBaseUrl = (baseUrl, route) => `${baseUrl}${route}`; const defaultAppendQuerySuffix = (route, suffix = "") => `${route}${suffix}`; const context = { module: { exports: {} }, exports: {}, require, URLSearchParams, encodeURIComponent, FormData: global.FormData, console: { log: () => {}, info: () => {}, warn: () => {}, error: () => {} }, getJson: injected.getJson || defaultGetJson, requestJson: injected.requestJson || defaultRequestJson, getFileJson: injected.getFileJson || defaultGetFileJson, getSignedFileJson: injected.getSignedFileJson || defaultGetSignedFileJson, downloadFileBlob: injected.downloadFileBlob || defaultDownloadFileBlob, deleteSignedJson: injected.deleteSignedJson || defaultDeleteSignedJson, buildHashedQueryUrl: injected.buildHashedQueryUrl || defaultBuildHashedQueryUrl, buildFileQuery: injected.buildFileQuery || defaultBuildFileQuery, withBaseUrl: injected.withBaseUrl || defaultWithBaseUrl, appendQuerySuffix: injected.appendQuerySuffix || defaultAppendQuerySuffix, ...injected }; vm.runInNewContext(source, context, { filename: filePath }); return context.module.exports; }; const normalize = (value) => { if (value === undefined || value === null) { return value; } return JSON.parse(JSON.stringify(value)); }; module.exports = { createAxiosMock, createLoggerMock, createAxiosError, loadServiceModule, normalize };