diff --git a/TestMasterUI/src/components/ServerManager.jsx b/TestMasterUI/src/components/ServerManager.jsx
index e69e20b..476e1ec 100644
--- a/TestMasterUI/src/components/ServerManager.jsx
+++ b/TestMasterUI/src/components/ServerManager.jsx
@@ -15,7 +15,6 @@ const ServerManager = ({ onServerChange = () => {} }) => {
if (!initialized.current) {
initialized.current = true;
await loadServers();
- console.log(servers);
}
};
diff --git a/TestMasterUI/src/components/client-views/HTTPClientView.jsx b/TestMasterUI/src/components/client-views/HTTPClientView.jsx
index 66a6757..c417407 100644
--- a/TestMasterUI/src/components/client-views/HTTPClientView.jsx
+++ b/TestMasterUI/src/components/client-views/HTTPClientView.jsx
@@ -10,7 +10,7 @@ import ServerManager from '@/components/ServerManager.jsx';
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table.jsx';
import {useAPI} from '@/providers/APIProvider';
import MonacoEditor from '@/components/shared/MonacoEditor';
-// import MonacoVariableEditor from './MonacoVariableEditor'; // Import the new component
+import APIClient from '@/services/APIClient.js';
const HTTP_METHODS = [
'POST', 'GET', 'PUT', 'DELETE', 'CONNECT',
@@ -18,7 +18,9 @@ const HTTP_METHODS = [
];
export const HTTPClientView = ({model, index}) => {
+ const apiClient = new APIClient();
const {getServer} = useAPI();
+ const [isLoading, setIsLoading] = useState(false);
const [currentModel, setCurrentModel] = useState(model);
const [basePath, setBasePath] = useState('');
const [currentTab, setCurrentTab] = useState('body');
@@ -32,8 +34,8 @@ export const HTTPClientView = ({model, index}) => {
const [editorContents, setEditorContents] = useState({
requestBody: currentModel.requestBody || '',
- responseBody: currentModel.responseBody || '',
- console: '',
+ responseBody: '',
+ consoleLog: '',
preRequestScript: currentModel.preRequestScript || '',
postRequestScript: currentModel.postRequestScript || ''
});
@@ -101,6 +103,55 @@ export const HTTPClientView = ({model, index}) => {
);
+ const handleSendRequest = async () => {
+ if (isLoading) return;
+
+ setIsLoading(true);
+ setEditorContents(prev => ({...prev, consoleLog: ''}));
+
+ try {
+ const response = await apiClient.sendAPIRequest(
+ currentModel,
+ (log) => setEditorContents(prev => ({
+ ...prev,
+ consoleLog: prev.consoleLog + log + '\n'
+ }))
+ );
+
+ const headerArray = Array.isArray(response.headers)
+ ? response.headers
+ : Object.entries(response.headers).map(([key, value]) => ({
+ name: key,
+ value: value
+ }));
+
+ setResponseData({
+ headers: headerArray,
+ status: `Status: ${response.status}`,
+ time: `${response.time}ms`,
+ size: `Size: ${response.size}`
+ });
+
+ console.log(responseData);
+
+ setEditorContents(prev => ({
+ ...prev,
+ responseBody: response.body
+ }));
+
+ console.log(editorContents.responseBody);
+
+ } catch (error) {
+ console.error(error);
+ setEditorContents(prev => ({
+ ...prev,
+ consoleLog: prev.consoleLog + `Error: ${error.message}\n`
+ }));
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
const renderResponseHeaders = () => (
@@ -162,7 +213,12 @@ export const HTTPClientView = ({model, index}) => {
className="flex-1"
/>
-
+
@@ -185,18 +241,7 @@ export const HTTPClientView = ({model, index}) => {
-
+
{
-
handlePropertyChange(index, 'key', e.target.value)
@@ -96,7 +97,7 @@ const PropertyTable = ({
/>
-
handlePropertyChange(index, 'value', e.target.value)
diff --git a/TestMasterUI/src/services/APIClient.js b/TestMasterUI/src/services/APIClient.js
index 6e25926..c16a6a7 100644
--- a/TestMasterUI/src/services/APIClient.js
+++ b/TestMasterUI/src/services/APIClient.js
@@ -18,16 +18,36 @@ class APIClient {
async sendAPIRequest(model, onLog = () => {}) {
try {
- onLog(`Request: ${model.method} ${model.path}`);
+ let variables = {};
+ const processedModel = await this.executePreRequestScript(model, variables, onLog);
+ const processedRequest = this.replacePlaceholdersWithVariables(processedModel, variables);
+
+ onLog(`Request: ${processedRequest.method} ${processedRequest.path}`);
+
const response = await this.makeRequest(model);
const formattedResponse = this.formatResponse(response);
- return formattedResponse;
+ onLog(formattedResponse);
+
+ const finalResponse = await this.executePostRequestScript(
+ model.postRequestScript,
+ variables,
+ processedRequest,
+ formattedResponse,
+ onLog
+ );
+
+
+ return finalResponse;
+
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request was cancelled');
}
- throw new Error(`API Error: ${error.message}`);
+ const errorMessage = error.message || 'Unknown error';
+ onLog(`Error: ${errorMessage}`);
+ throw new Error(`API Error: ${errorMessage}`);
+
} finally {
this.abortController = null;
}
@@ -66,6 +86,139 @@ class APIClient {
getClientUrl() {
return this.contextPath + this.CLIENT_URL;
}
+
+ replacePlaceholdersWithVariables(original, variables) {
+ const request = JSON.parse(JSON.stringify(original));
+ const mergedVariables = { ...this.globals, ...variables };
+
+ Object.entries(mergedVariables).forEach(([key, value]) => {
+ const placeholder = new RegExp(`{{${key}}}`, 'g');
+
+ request.path = request.path?.replace(placeholder, value);
+ request.requestBody = request.requestBody?.replace(placeholder, value);
+
+ if (request.headers) {
+ const headersStr = JSON.stringify(request.headers).replace(placeholder, value);
+ request.headers = JSON.parse(headersStr);
+ }
+
+ if (request.queryParams) {
+ const paramsStr = JSON.stringify(request.queryParams).replace(placeholder, value);
+ request.queryParams = JSON.parse(paramsStr);
+ }
+ });
+
+ return request;
+ }
+
+ async executePreRequestScript(model, variables, onLog) {
+ return new Promise((resolve, reject) => {
+ // Create sandbox iframe if not exists
+ let sandbox = document.getElementById('preRequest');
+ if (!sandbox) {
+ sandbox = document.createElement('iframe');
+ sandbox.id = 'preRequest';
+ sandbox.style.display = 'none';
+ document.body.appendChild(sandbox);
+ }
+
+ // Setup communication channel
+ window.preRequestComplete = (updatedModel, error) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(updatedModel);
+ }
+ };
+
+ // Setup context
+ window.temp_variable = variables;
+ window.currentRequest = model;
+ window.consoleOutput = onLog;
+
+ // Create sandbox content
+ const sandboxContent = `
+
+ `;
+
+ sandbox.srcdoc = sandboxContent;
+ });
+ }
+
+ async executePostRequestScript(script, variables, request, response, onLog) {
+ return new Promise((resolve, reject) => {
+ // Create sandbox iframe if not exists
+ let sandbox = document.getElementById('postRequest');
+ if (!sandbox) {
+ sandbox = document.createElement('iframe');
+ sandbox.id = 'postRequest';
+ sandbox.style.display = 'none';
+ document.body.appendChild(sandbox);
+ }
+
+ // Setup communication channel
+ window.postRequestComplete = (updatedResponse, error) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(updatedResponse);
+ }
+ };
+
+ // Setup context
+ window.request = request;
+ window.response = response;
+ window.temp_variable = variables;
+ window.consoleOutput = onLog;
+
+ // Create sandbox content
+ const sandboxContent = `
+
+ `;
+
+ sandbox.srcdoc = sandboxContent;
+ });
+ }
+
}
export default APIClient;