@aimeloic/monkey-tester 3.0.2 → 3.0.4

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 CHANGED
@@ -183,15 +183,14 @@ function getHtmlTemplate(endpoints) {
183
183
  <div id="toast"></div>
184
184
 
185
185
  <script>
186
- const ENDPOINTS = JSON.parse(atob(document.getElementById('__monkey_data__').getAttribute('data-payload')));
187
- let currentKey = null;
186
+ var ENDPOINTS = JSON.parse(atob(document.getElementById('__monkey_data__').getAttribute('data-payload')));
187
+ var currentKey = null;
188
188
 
189
189
  document.getElementById('base-url').value = window.location.origin;
190
190
 
191
- // ── Sidebar ────────────────────────────────────────────────────────────────
192
191
  function buildSidebar() {
193
- const sidebar = document.getElementById('sidebar-nav');
194
- const keys = Object.keys(ENDPOINTS);
192
+ var sidebar = document.getElementById('sidebar-nav');
193
+ var keys = Object.keys(ENDPOINTS);
195
194
 
196
195
  if (keys.length === 0) {
197
196
  sidebar.innerHTML += '<div style="padding:18px;color:var(--text-dim);font-size:12px">No endpoints discovered.</div>';
@@ -199,16 +198,16 @@ function getHtmlTemplate(endpoints) {
199
198
  return;
200
199
  }
201
200
 
202
- keys.forEach((key, i) => {
203
- const ep = ENDPOINTS[key];
204
- const item = document.createElement('div');
201
+ keys.forEach(function(key, i) {
202
+ var ep = ENDPOINTS[key];
203
+ var item = document.createElement('div');
205
204
  item.className = 'nav-item' + (i === 0 ? ' active' : '');
206
205
  item.setAttribute('data-key', key);
207
206
  item.innerHTML =
208
207
  '<span class="method-badge ' + ep.method + '">' + ep.method + '</span>' +
209
208
  '<span class="nav-label">' + ep.path + '</span>';
210
- item.addEventListener('click', () => {
211
- document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
209
+ item.addEventListener('click', function() {
210
+ document.querySelectorAll('.nav-item').forEach(function(n) { n.classList.remove('active'); });
212
211
  item.classList.add('active');
213
212
  clearResponse();
214
213
  renderPanel(key);
@@ -219,20 +218,18 @@ function getHtmlTemplate(endpoints) {
219
218
  renderPanel(keys[0]);
220
219
  }
221
220
 
222
- // ── Panel ──────────────────────────────────────────────────────────────────
223
221
  function renderPanel(key) {
224
222
  currentKey = key;
225
- const ep = ENDPOINTS[key];
226
- const main = document.getElementById('main-panel');
223
+ var ep = ENDPOINTS[key];
224
+ var main = document.getElementById('main-panel');
227
225
  if (!ep) return;
228
226
 
229
- let html =
227
+ var html =
230
228
  '<div class="endpoint-title">' + ep.title + '</div>' +
231
229
  '<div class="endpoint-path"><span class="method-badge ' + ep.method + '">' + ep.method + '</span>' +
232
230
  '<span>' + ep.path + '</span></div>' +
233
231
  '<div class="endpoint-desc">' + ep.desc + '</div>';
234
232
 
235
- // Path params
236
233
  if (ep.params && ep.params.length) {
237
234
  html += '<div class="form-section"><div class="form-section-title">Path Parameters</div>';
238
235
  ep.params.forEach(function(p) {
@@ -245,7 +242,6 @@ function getHtmlTemplate(endpoints) {
245
242
  html += '</div>';
246
243
  }
247
244
 
248
- // Body fields
249
245
  if (ep.fields && ep.fields.length) {
250
246
  html += '<div class="form-section"><div class="form-section-title">Request Body</div>';
251
247
  ep.fields.forEach(function(f) {
@@ -274,35 +270,35 @@ function getHtmlTemplate(endpoints) {
274
270
  '<p>Make sure <code>app.use(endtesterExpress())</code> is added after your routes.</p></div>';
275
271
  }
276
272
 
277
- // ── Request ────────────────────────────────────────────────────────────────
278
273
  async function sendRequest() {
279
- const ep = ENDPOINTS[currentKey];
280
- let path = ep.path;
274
+ var ep = ENDPOINTS[currentKey];
275
+ var path = ep.path;
281
276
 
282
277
  if (ep.params && ep.params.length) {
283
- for (const p of ep.params) {
284
- const val = (document.getElementById('param-' + p.name) || {}).value || '';
278
+ for (var i = 0; i < ep.params.length; i++) {
279
+ var p = ep.params[i];
280
+ var val = (document.getElementById('param-' + p.name) || {}).value || '';
285
281
  if (!val.trim()) { showToast('⚠ Path param "' + p.label + '" is required'); return; }
286
282
  path = path.replace(':' + p.name, encodeURIComponent(val.trim()));
287
283
  }
288
284
  }
289
285
 
290
- const baseUrl = document.getElementById('base-url').value.replace(/\/+$/, '');
291
- const url = baseUrl + path;
292
- const headers = { 'Content-Type': 'application/json' };
293
- const jwt = document.getElementById('jwt-input').value.trim();
286
+ var baseUrl = document.getElementById('base-url').value.replace(/\/+$/, '');
287
+ var url = baseUrl + path;
288
+ var headers = { 'Content-Type': 'application/json' };
289
+ var jwt = document.getElementById('jwt-input').value.trim();
294
290
  if (jwt) headers['Authorization'] = 'Bearer ' + jwt;
295
291
 
296
- let body = undefined;
292
+ var body = undefined;
297
293
  if (['POST', 'PUT', 'PATCH'].includes(ep.method) && ep.fields && ep.fields.length) {
298
- const payload = {};
299
- let hasData = false;
294
+ var payload = {};
295
+ var hasData = false;
300
296
 
301
297
  ep.fields.forEach(function(f) {
302
- const el = document.getElementById('field-' + f.name);
298
+ var el = document.getElementById('field-' + f.name);
303
299
  if (!el) return;
304
- let v = el.value.trim();
305
- if (v === '') return; // Avoid submitting empty strings for unfilled fields
300
+ var v = el.value.trim();
301
+ if (v === '') return;
306
302
 
307
303
  if (f.type === 'number') v = Number(v);
308
304
  payload[f.name] = v;
@@ -313,24 +309,23 @@ function getHtmlTemplate(endpoints) {
313
309
  }
314
310
 
315
311
  setResponse(null, 'loading');
316
- const t0 = Date.now();
312
+ var t0 = Date.now();
317
313
 
318
314
  try {
319
- const res = await fetch(url, { method: ep.method, headers, body });
320
- const ms = Date.now() - t0;
321
- const text = await res.text();
322
- let data;
323
- try { data = JSON.parse(text); } catch { data = text; }
315
+ var res = await fetch(url, { method: ep.method, headers: headers, body: body });
316
+ var ms = Date.now() - t0;
317
+ var text = await res.text();
318
+ var data;
319
+ try { data = JSON.parse(text); } catch(e) { data = text; }
324
320
  setResponse(data, res.ok ? 'ok' : 'err', res.status, ms);
325
321
  } catch (err) {
326
322
  setResponse({ error: err.message }, 'err', 'FAIL', 0);
327
323
  }
328
324
  }
329
325
 
330
- // ── Response ───────────────────────────────────────────────────────────────
331
326
  function setResponse(data, state, status, ms) {
332
- const badge = document.getElementById('status-badge');
333
- const body = document.getElementById('response-body');
327
+ var badge = document.getElementById('status-badge');
328
+ var body = document.getElementById('response-body');
334
329
 
335
330
  if (state === 'loading') {
336
331
  badge.className = 'status-badge status-idle';
@@ -343,14 +338,14 @@ function getHtmlTemplate(endpoints) {
343
338
  badge.className = 'status-badge ' + (state === 'ok' ? 'status-ok' : 'status-err');
344
339
  badge.textContent = status + ' · ' + ms + 'ms';
345
340
  body.className = 'response-body';
346
- const str = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
341
+ var str = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
347
342
  body.innerHTML = '<pre class="json-render-block">' + highlight(str) + '</pre>';
348
343
  }
349
344
 
350
345
  function clearResponse() {
351
346
  document.getElementById('status-badge').className = 'status-badge status-idle';
352
347
  document.getElementById('status-badge').textContent = '—';
353
- const body = document.getElementById('response-body');
348
+ var body = document.getElementById('response-body');
354
349
  body.className = 'response-body empty';
355
350
  body.textContent = 'Execute a request to see the response';
356
351
  }
@@ -369,10 +364,10 @@ function getHtmlTemplate(endpoints) {
369
364
  }
370
365
 
371
366
  function showToast(msg) {
372
- const t = document.getElementById('toast');
367
+ var t = document.getElementById('toast');
373
368
  t.textContent = msg;
374
369
  t.classList.add('show');
375
- setTimeout(() => t.classList.remove('show'), 2500);
370
+ setTimeout(function() { t.classList.remove('show'); }, 2500);
376
371
  }
377
372
 
378
373
  buildSidebar();
package/monkey.js CHANGED
@@ -173,13 +173,19 @@ function parseStack(stack, detectedEndpoints, prefix = '') {
173
173
  }
174
174
 
175
175
  // ─── Middleware ───────────────────────────────────────────────────────────────
176
+ // ─── Middleware in monkey.js ──────────────────────────────────────────────────
176
177
  function endtesterExpress() {
177
178
  return function monkeyTesterMiddleware(req, res, next) {
178
- if (req.path !== '/api/tester' && req.path !== '/api/tester/') {
179
+ // Standard structural path cleaning
180
+ const normalPath = req.path.replace(/\/$/, ''); // removes trailing slash
181
+
182
+ if (normalPath !== '/api/tester') {
179
183
  return next();
180
184
  }
181
185
 
182
186
  const app = req.app;
187
+
188
+ // CRITICAL FIX: Reset the detected endpoints on each call to prevent stale empty states
183
189
  const detectedEndpoints = {};
184
190
 
185
191
  const rootStack =
@@ -187,8 +193,10 @@ function endtesterExpress() {
187
193
  (app.router && app.router.stack) || // Express 5
188
194
  [];
189
195
 
196
+ // Scan the live compiled routing stack
190
197
  parseStack(rootStack, detectedEndpoints);
191
198
 
199
+ // Render page template
192
200
  const html = getHtmlTemplate(detectedEndpoints);
193
201
  res.setHeader('Content-Type', 'text/html');
194
202
  return res.send(html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aimeloic/monkey-tester",
3
- "version": "3.0.2",
3
+ "version": "3.0.4",
4
4
  "description": "Auto route scanning visual runner dashboard.",
5
5
  "main": "index.js",
6
6
  "type": "module",