@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.
Files changed (2) hide show
  1. package/htmlTemplate.js +32 -26
  2. 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
- '<input type="text" id="param-' + p.name + '" placeholder="' + p.placeholder + '" />' +
175
- '</div>';
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
- '<input type="text" id="field-' + f.name + '" value=\'{"key": "value"}\' />' +
186
- '</div>';
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
- '</div>';
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(' Parameter ' + p.label + ' required'); return; }
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('Malformed JSON Body structure provided.');
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
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; t.classList.add('show');
289
+ t.textContent = msg;
290
+ t.classList.add('show');
285
291
  setTimeout(() => t.classList.remove('show'), 2500);
286
292
  }
287
293
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aimeloic/monkey-tester",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Embedded interactive API testing UI for Node.js backends",
5
5
  "main": "index.js",
6
6
  "type":"module",