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