@aimeloic/monkey-tester 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/htmlTemplate.js +32 -26
- package/package.json +1 -1
package/htmlTemplate.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export function getHtmlTemplate(endpoints) {
|
|
2
|
-
// Safe stringification for HTML attribute encoding
|
|
3
2
|
const safeJsonString = Buffer.from(JSON.stringify(endpoints)).toString('base64');
|
|
4
3
|
|
|
5
4
|
return `
|
|
@@ -65,7 +64,7 @@ export function getHtmlTemplate(endpoints) {
|
|
|
65
64
|
.field-label { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text-dim); text-align: right; }
|
|
66
65
|
input[type=text], input[type=number], select { background: var(--surface2); border: 1px solid var(--border); color: var(--text); font-family: 'DM Mono', monospace; font-size: 12px; padding: 7px 10px; border-radius: var(--radius); width: 100%; outline: none; }
|
|
67
66
|
.btn { background: var(--accent); color: #0e0c09; border: none; padding: 10px 22px; border-radius: var(--radius); font-size: 13px; font-weight: 500; cursor: pointer; }
|
|
68
|
-
.btn-secondary { background: var(--surface2); color: var(--text-dim); border: 1px solid var(--border); margin-left: 8px;}
|
|
67
|
+
.btn-secondary { background: var(--surface2); color: var(--text-dim); border: 1px solid var(--border); margin-left: 8px; }
|
|
69
68
|
.response-panel { border-left: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; }
|
|
70
69
|
.response-header { padding: 14px 18px; border-bottom: 1px solid var(--border); display: flex; align-items: center; background: var(--surface); }
|
|
71
70
|
.response-header-title { font-size: 11px; font-family: 'DM Mono', monospace; color: var(--text-dim); text-transform: uppercase; }
|
|
@@ -102,9 +101,7 @@ export function getHtmlTemplate(endpoints) {
|
|
|
102
101
|
<aside id="sidebar-nav">
|
|
103
102
|
<div class="section-label">Discovered Endpoints</div>
|
|
104
103
|
</aside>
|
|
105
|
-
|
|
106
104
|
<main id="main-panel"></main>
|
|
107
|
-
|
|
108
105
|
<div class="response-panel">
|
|
109
106
|
<div class="response-header">
|
|
110
107
|
<span class="response-header-title">Response Output</span>
|
|
@@ -127,8 +124,8 @@ document.getElementById('base-url').value = window.location.origin;
|
|
|
127
124
|
function buildSidebar() {
|
|
128
125
|
const sidebar = document.getElementById('sidebar-nav');
|
|
129
126
|
const keys = Object.keys(ENDPOINTS);
|
|
130
|
-
|
|
131
|
-
if(keys.length === 0) {
|
|
127
|
+
|
|
128
|
+
if (keys.length === 0) {
|
|
132
129
|
sidebar.innerHTML += '<div style="padding:15px; color:var(--text-dim)">No active application endpoints discovered.</div>';
|
|
133
130
|
return;
|
|
134
131
|
}
|
|
@@ -139,25 +136,32 @@ function buildSidebar() {
|
|
|
139
136
|
div.className = index === 0 ? 'nav-item active' : 'nav-item';
|
|
140
137
|
div.setAttribute('data-ep', key);
|
|
141
138
|
div.innerHTML = '<span class="method-badge ' + ep.method + '">' + ep.method + '</span><span class="nav-label">' + ep.path + '</span>';
|
|
142
|
-
|
|
143
139
|
div.addEventListener('click', () => {
|
|
144
140
|
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
|
|
145
141
|
div.classList.add('active');
|
|
146
142
|
clearResponse();
|
|
147
143
|
renderPanel(key);
|
|
148
144
|
});
|
|
149
|
-
|
|
150
145
|
sidebar.appendChild(div);
|
|
151
146
|
});
|
|
152
|
-
|
|
153
|
-
if(keys.length > 0) renderPanel(keys[0]);
|
|
147
|
+
|
|
148
|
+
if (keys.length > 0) renderPanel(keys[0]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function makeInput(type, id, placeholder, defaultValue) {
|
|
152
|
+
var el = document.createElement('input');
|
|
153
|
+
el.type = type;
|
|
154
|
+
el.id = id;
|
|
155
|
+
if (placeholder) el.placeholder = placeholder;
|
|
156
|
+
if (defaultValue !== undefined) el.value = defaultValue;
|
|
157
|
+
return el.outerHTML;
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
function renderPanel(epKey) {
|
|
157
161
|
currentEp = epKey;
|
|
158
162
|
const ep = ENDPOINTS[epKey];
|
|
159
163
|
const main = document.getElementById('main-panel');
|
|
160
|
-
if(!ep) return;
|
|
164
|
+
if (!ep) return;
|
|
161
165
|
|
|
162
166
|
let html = '<div class="endpoint-title">' + ep.title + '</div>' +
|
|
163
167
|
'<div class="endpoint-path">' +
|
|
@@ -168,22 +172,22 @@ function renderPanel(epKey) {
|
|
|
168
172
|
|
|
169
173
|
if (ep.params && ep.params.length) {
|
|
170
174
|
html += '<div class="form-section"><div class="form-section-title">Path Parameters</div>';
|
|
171
|
-
ep.params.forEach(p
|
|
175
|
+
ep.params.forEach(function(p) {
|
|
172
176
|
html += '<div class="field-row">' +
|
|
173
177
|
'<label class="field-label">' + p.label + '</label>' +
|
|
174
|
-
'
|
|
175
|
-
|
|
178
|
+
makeInput('text', 'param-' + p.name, p.placeholder, '') +
|
|
179
|
+
'</div>';
|
|
176
180
|
});
|
|
177
181
|
html += '</div>';
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
if (ep.fields && ep.fields.length) {
|
|
181
185
|
html += '<div class="form-section"><div class="form-section-title">JSON Request Body Raw Payload</div>';
|
|
182
|
-
ep.fields.forEach(f
|
|
186
|
+
ep.fields.forEach(function(f) {
|
|
183
187
|
html += '<div class="field-row">' +
|
|
184
188
|
'<label class="field-label">' + f.label + '</label>' +
|
|
185
|
-
'
|
|
186
|
-
|
|
189
|
+
makeInput('text', 'field-' + f.name, '', '{"key": "value"}') +
|
|
190
|
+
'</div>';
|
|
187
191
|
});
|
|
188
192
|
html += '</div>';
|
|
189
193
|
}
|
|
@@ -191,7 +195,7 @@ function renderPanel(epKey) {
|
|
|
191
195
|
html += '<div class="btn-row">' +
|
|
192
196
|
'<button class="btn" onclick="sendRequest()">Execute Route</button>' +
|
|
193
197
|
'<button class="btn btn-secondary" onclick="clearResponse()">Clear Context</button>' +
|
|
194
|
-
|
|
198
|
+
'</div>';
|
|
195
199
|
|
|
196
200
|
main.innerHTML = html;
|
|
197
201
|
}
|
|
@@ -203,26 +207,26 @@ async function sendRequest() {
|
|
|
203
207
|
if (ep.params) {
|
|
204
208
|
for (const p of ep.params) {
|
|
205
209
|
const val = document.getElementById('param-' + p.name)?.value.trim();
|
|
206
|
-
if (!val) { showToast('
|
|
210
|
+
if (!val) { showToast('Warning: Parameter ' + p.label + ' is required'); return; }
|
|
207
211
|
path = path.replace(':' + p.name, encodeURIComponent(val));
|
|
208
212
|
}
|
|
209
213
|
}
|
|
210
214
|
|
|
211
|
-
const baseUrl = document.getElementById('base-url').value.replace(
|
|
215
|
+
const baseUrl = document.getElementById('base-url').value.replace(/\/+$/, '');
|
|
212
216
|
const url = baseUrl + path;
|
|
213
217
|
const headers = { 'Content-Type': 'application/json' };
|
|
214
|
-
|
|
218
|
+
|
|
215
219
|
const jwt = document.getElementById('jwt-input').value.trim();
|
|
216
220
|
if (jwt) headers['Authorization'] = 'Bearer ' + jwt;
|
|
217
221
|
|
|
218
222
|
let body = undefined;
|
|
219
|
-
if (ep.fields && ep.fields.length && ['POST','PUT','PATCH'].includes(ep.method)) {
|
|
223
|
+
if (ep.fields && ep.fields.length && ['POST', 'PUT', 'PATCH'].includes(ep.method)) {
|
|
220
224
|
const rawVal = document.getElementById('field-' + ep.fields[0].name).value.trim();
|
|
221
225
|
try {
|
|
222
226
|
JSON.parse(rawVal);
|
|
223
227
|
body = rawVal;
|
|
224
228
|
} catch(e) {
|
|
225
|
-
showToast('
|
|
229
|
+
showToast('Malformed JSON body structure provided.');
|
|
226
230
|
return;
|
|
227
231
|
}
|
|
228
232
|
}
|
|
@@ -248,13 +252,14 @@ function setResponse(data, state, status, ms) {
|
|
|
248
252
|
|
|
249
253
|
if (state === 'loading') {
|
|
250
254
|
badge.className = 'status-badge status-idle';
|
|
251
|
-
badge.textContent = '
|
|
255
|
+
badge.textContent = '...';
|
|
252
256
|
body.innerHTML = 'Executing transmission...';
|
|
253
257
|
return;
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
badge.className = 'status-badge ' + (state === 'ok' ? 'status-ok' : 'status-err');
|
|
257
261
|
badge.textContent = status + ' · ' + ms + 'ms';
|
|
262
|
+
body.className = 'response-body';
|
|
258
263
|
body.innerHTML = highlightJson(typeof data === 'string' ? data : JSON.stringify(data, null, 2));
|
|
259
264
|
}
|
|
260
265
|
|
|
@@ -270,7 +275,7 @@ function clearResponse() {
|
|
|
270
275
|
function highlightJson(str) {
|
|
271
276
|
return str
|
|
272
277
|
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
273
|
-
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match
|
|
278
|
+
.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
|
|
274
279
|
if (/^"/.test(match)) {
|
|
275
280
|
if (/:$/.test(match)) return '<span class="json-key">' + match + '</span>';
|
|
276
281
|
return '<span class="json-str">' + match + '</span>';
|
|
@@ -281,7 +286,8 @@ function highlightJson(str) {
|
|
|
281
286
|
|
|
282
287
|
function showToast(msg) {
|
|
283
288
|
const t = document.getElementById('toast');
|
|
284
|
-
t.textContent = msg;
|
|
289
|
+
t.textContent = msg;
|
|
290
|
+
t.classList.add('show');
|
|
285
291
|
setTimeout(() => t.classList.remove('show'), 2500);
|
|
286
292
|
}
|
|
287
293
|
|