viberadar 0.3.209 → 0.3.211
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/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +110 -25
- package/dist/server/index.js.map +1 -1
- package/dist/ui/dashboard.html +99 -6
- package/package.json +1 -1
package/dist/ui/dashboard.html
CHANGED
|
@@ -1784,6 +1784,11 @@ let loadScriptNameDraft = ''; // save name input draft
|
|
|
1784
1784
|
let loadBaseUrlDraft = 'http://localhost:5000';
|
|
1785
1785
|
let loadVusDraft = 10;
|
|
1786
1786
|
let loadDurationDraft = '30s';
|
|
1787
|
+
let loadDataDirDraft = '';
|
|
1788
|
+
let loadResultDirDraft = '';
|
|
1789
|
+
let loadExecutionModeDraft = 'auto';
|
|
1790
|
+
let loadVusEnvNameDraft = 'SMOKE_VUS';
|
|
1791
|
+
let loadDurationEnvNameDraft = 'SMOKE_DURATION';
|
|
1787
1792
|
let loadView = 'library'; // 'library' | 'editor'
|
|
1788
1793
|
|
|
1789
1794
|
function toggleObsHint(id) {
|
|
@@ -7759,12 +7764,27 @@ function applyLoadConfigToFields(cfg) {
|
|
|
7759
7764
|
loadBaseUrlDraft = cfg.baseUrl || loadBaseUrlDraft;
|
|
7760
7765
|
loadVusDraft = cfg.vus || loadVusDraft;
|
|
7761
7766
|
loadDurationDraft = cfg.duration || loadDurationDraft;
|
|
7767
|
+
loadDataDirDraft = cfg.dataDir || loadDataDirDraft;
|
|
7768
|
+
loadResultDirDraft = cfg.resultDir || loadResultDirDraft;
|
|
7769
|
+
loadExecutionModeDraft = cfg.executionMode || loadExecutionModeDraft;
|
|
7770
|
+
loadVusEnvNameDraft = cfg.vusEnvName || loadVusEnvNameDraft;
|
|
7771
|
+
loadDurationEnvNameDraft = cfg.durationEnvName || loadDurationEnvNameDraft;
|
|
7762
7772
|
const baseEl = document.getElementById('loadBaseUrl');
|
|
7763
7773
|
const vusEl = document.getElementById('loadVus');
|
|
7764
7774
|
const durEl = document.getElementById('loadDuration');
|
|
7775
|
+
const dataEl = document.getElementById('loadDataDir');
|
|
7776
|
+
const resultEl = document.getElementById('loadResultDir');
|
|
7777
|
+
const modeEl = document.getElementById('loadExecutionMode');
|
|
7778
|
+
const vusEnvEl = document.getElementById('loadVusEnvName');
|
|
7779
|
+
const durationEnvEl = document.getElementById('loadDurationEnvName');
|
|
7765
7780
|
if (baseEl) baseEl.value = loadBaseUrlDraft;
|
|
7766
7781
|
if (vusEl) vusEl.value = loadVusDraft;
|
|
7767
7782
|
if (durEl) durEl.value = loadDurationDraft;
|
|
7783
|
+
if (dataEl) dataEl.value = loadDataDirDraft;
|
|
7784
|
+
if (resultEl) resultEl.value = loadResultDirDraft;
|
|
7785
|
+
if (modeEl) modeEl.value = loadExecutionModeDraft;
|
|
7786
|
+
if (vusEnvEl) vusEnvEl.value = loadVusEnvNameDraft;
|
|
7787
|
+
if (durationEnvEl) durationEnvEl.value = loadDurationEnvNameDraft;
|
|
7768
7788
|
}
|
|
7769
7789
|
|
|
7770
7790
|
function renderLoad(c) {
|
|
@@ -7810,7 +7830,7 @@ function renderLoad(c) {
|
|
|
7810
7830
|
<div class="load-run-name">${escapeHtml(r.scriptName || 'Без названия')}</div>
|
|
7811
7831
|
<div class="load-run-meta">${formatLoadRunDate(r.createdAt || r.startTime)} · ${cfg.vus || '—'} VU · ${escapeHtml(cfg.duration || '—')} · ${loadStatusLabel(r.status)}</div>
|
|
7812
7832
|
</div>
|
|
7813
|
-
<div class="load-run-kpi">${summary.rps != null ? Number(summary.rps || 0).toFixed(1) : '—'} RPS</div>
|
|
7833
|
+
<div class="load-run-kpi" title="${escapeHtml(cfg.resultPath || '')}">${summary.rps != null ? Number(summary.rps || 0).toFixed(1) : '—'} RPS</div>
|
|
7814
7834
|
<div class="load-run-kpi">p95 ${summary.p95Duration != null ? Math.round(summary.p95Duration || 0) + 'ms' : '—'}</div>
|
|
7815
7835
|
<div class="load-run-kpi" style="color:${Number(summary.errorPct || 0) > 5 ? 'var(--red)' : 'var(--muted)'}">${err}</div>
|
|
7816
7836
|
</div>`;
|
|
@@ -7894,6 +7914,36 @@ function renderLoad(c) {
|
|
|
7894
7914
|
</div>
|
|
7895
7915
|
</div>
|
|
7896
7916
|
<div class="load-config-hint">VUs и Duration применяются через CLI k6 и переопределяют значения из <code>export const options</code>. Base URL доступен в скрипте как <code>__ENV.BASE_URL</code>.</div>
|
|
7917
|
+
<div class="load-config-row" style="margin-top:8px">
|
|
7918
|
+
<div class="load-config-field">
|
|
7919
|
+
<label>Execution</label>
|
|
7920
|
+
<select id="loadExecutionMode" style="width:150px">
|
|
7921
|
+
<option value="auto" ${loadExecutionModeDraft === 'auto' ? 'selected' : ''}>Auto</option>
|
|
7922
|
+
<option value="cli" ${loadExecutionModeDraft === 'cli' ? 'selected' : ''}>CLI override</option>
|
|
7923
|
+
<option value="script" ${loadExecutionModeDraft === 'script' ? 'selected' : ''}>Script scenarios</option>
|
|
7924
|
+
</select>
|
|
7925
|
+
</div>
|
|
7926
|
+
<div class="load-config-field">
|
|
7927
|
+
<label>VUs env</label>
|
|
7928
|
+
<input id="loadVusEnvName" type="text" value="${escapeHtml(loadVusEnvNameDraft)}" style="width:130px" placeholder="SMOKE_VUS" />
|
|
7929
|
+
</div>
|
|
7930
|
+
<div class="load-config-field">
|
|
7931
|
+
<label>Duration env</label>
|
|
7932
|
+
<input id="loadDurationEnvName" type="text" value="${escapeHtml(loadDurationEnvNameDraft)}" style="width:150px" placeholder="SMOKE_DURATION" />
|
|
7933
|
+
</div>
|
|
7934
|
+
</div>
|
|
7935
|
+
<div class="load-config-hint">Auto: если скрипт содержит <code>options.scenarios</code>, VibeRadar не передаёт <code>--vus/--duration</code>, а кладёт значения в env-переменные, например <code>SMOKE_VUS</code> и <code>SMOKE_DURATION</code>.</div>
|
|
7936
|
+
<div class="load-config-row" style="margin-top:8px">
|
|
7937
|
+
<div class="load-config-field" style="flex:1;min-width:260px">
|
|
7938
|
+
<label>Data dir / file <span style="color:var(--dim);font-weight:400">(для <code>open('./users.csv')</code> и локальных lib)</span></label>
|
|
7939
|
+
<input id="loadDataDir" type="text" value="${escapeHtml(loadDataDirDraft)}" placeholder="load-tests/k6 или C:\\path\\to\\k6-data" />
|
|
7940
|
+
</div>
|
|
7941
|
+
<div class="load-config-field" style="flex:1;min-width:260px">
|
|
7942
|
+
<label>Results dir <span style="color:var(--dim);font-weight:400">(необязательно)</span></label>
|
|
7943
|
+
<input id="loadResultDir" type="text" value="${escapeHtml(loadResultDirDraft)}" placeholder=".viberadar/load-runs или C:\\path\\to\\results" />
|
|
7944
|
+
</div>
|
|
7945
|
+
</div>
|
|
7946
|
+
<div class="load-config-hint">Если указать Data dir, VibeRadar скопирует его содержимое рядом со скриптом перед запуском. Результаты сохраняются в <code>results/<runId></code>: summary.json, metrics.ndjson, k6.log, config.json.</div>
|
|
7897
7947
|
<div class="load-config-row" style="margin-top:8px">
|
|
7898
7948
|
<div class="load-config-field" style="flex:1;min-width:300px">
|
|
7899
7949
|
<label>Bearer Token <span style="color:var(--dim);font-weight:400;font-size:11px">(→ <code style="background:var(--bg2);padding:1px 4px;border-radius:3px">__ENV.TOKEN</code>)</span></label>
|
|
@@ -7983,9 +8033,19 @@ function renderLoad(c) {
|
|
|
7983
8033
|
const baseInput = document.getElementById('loadBaseUrl');
|
|
7984
8034
|
const vusInput = document.getElementById('loadVus');
|
|
7985
8035
|
const durationInput = document.getElementById('loadDuration');
|
|
8036
|
+
const dataInput = document.getElementById('loadDataDir');
|
|
8037
|
+
const resultInput = document.getElementById('loadResultDir');
|
|
8038
|
+
const modeInput = document.getElementById('loadExecutionMode');
|
|
8039
|
+
const vusEnvInput = document.getElementById('loadVusEnvName');
|
|
8040
|
+
const durationEnvInput = document.getElementById('loadDurationEnvName');
|
|
7986
8041
|
if (baseInput) baseInput.addEventListener('input', () => { loadBaseUrlDraft = baseInput.value || 'http://localhost:5000'; });
|
|
7987
8042
|
if (vusInput) vusInput.addEventListener('input', () => { loadVusDraft = parseInt(vusInput.value || '10', 10) || 10; });
|
|
7988
8043
|
if (durationInput) durationInput.addEventListener('input', () => { loadDurationDraft = durationInput.value || '30s'; });
|
|
8044
|
+
if (dataInput) dataInput.addEventListener('input', () => { loadDataDirDraft = dataInput.value || ''; });
|
|
8045
|
+
if (resultInput) resultInput.addEventListener('input', () => { loadResultDirDraft = resultInput.value || ''; });
|
|
8046
|
+
if (modeInput) modeInput.addEventListener('change', () => { loadExecutionModeDraft = modeInput.value || 'auto'; });
|
|
8047
|
+
if (vusEnvInput) vusEnvInput.addEventListener('input', () => { loadVusEnvNameDraft = vusEnvInput.value || 'SMOKE_VUS'; });
|
|
8048
|
+
if (durationEnvInput) durationEnvInput.addEventListener('input', () => { loadDurationEnvNameDraft = durationEnvInput.value || 'SMOKE_DURATION'; });
|
|
7989
8049
|
|
|
7990
8050
|
// Feature selector auto-generates script
|
|
7991
8051
|
const featSel = document.getElementById('loadFeature');
|
|
@@ -8023,6 +8083,11 @@ function loadOpenScript(name) {
|
|
|
8023
8083
|
if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
|
|
8024
8084
|
if (s.vus) loadVusDraft = s.vus;
|
|
8025
8085
|
if (s.duration) loadDurationDraft = s.duration;
|
|
8086
|
+
loadDataDirDraft = s.dataDir || loadDataDirDraft;
|
|
8087
|
+
loadResultDirDraft = s.resultDir || loadResultDirDraft;
|
|
8088
|
+
loadExecutionModeDraft = s.executionMode || loadExecutionModeDraft;
|
|
8089
|
+
loadVusEnvNameDraft = s.vusEnvName || loadVusEnvNameDraft;
|
|
8090
|
+
loadDurationEnvNameDraft = s.durationEnvName || loadDurationEnvNameDraft;
|
|
8026
8091
|
loadView = 'editor';
|
|
8027
8092
|
renderContent();
|
|
8028
8093
|
}
|
|
@@ -8051,10 +8116,21 @@ async function runLoadTest() {
|
|
|
8051
8116
|
const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
|
|
8052
8117
|
const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
|
|
8053
8118
|
const scriptName = (document.getElementById('loadScriptName')?.value || loadScriptNameDraft || 'Новый тест').trim();
|
|
8119
|
+
const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
|
|
8120
|
+
const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
|
|
8121
|
+
const executionModeRaw = (document.getElementById('loadExecutionMode')?.value || loadExecutionModeDraft || 'auto').trim();
|
|
8122
|
+
const executionMode = executionModeRaw === 'auto' ? undefined : executionModeRaw;
|
|
8123
|
+
const vusEnvName = (document.getElementById('loadVusEnvName')?.value || loadVusEnvNameDraft || 'SMOKE_VUS').trim();
|
|
8124
|
+
const durationEnvName = (document.getElementById('loadDurationEnvName')?.value || loadDurationEnvNameDraft || 'SMOKE_DURATION').trim();
|
|
8054
8125
|
loadBaseUrlDraft = baseUrl;
|
|
8055
8126
|
loadVusDraft = vus;
|
|
8056
8127
|
loadDurationDraft = duration;
|
|
8057
8128
|
loadScriptNameDraft = scriptName;
|
|
8129
|
+
loadDataDirDraft = dataDir;
|
|
8130
|
+
loadResultDirDraft = resultDir;
|
|
8131
|
+
loadExecutionModeDraft = executionModeRaw;
|
|
8132
|
+
loadVusEnvNameDraft = vusEnvName;
|
|
8133
|
+
loadDurationEnvNameDraft = durationEnvName;
|
|
8058
8134
|
|
|
8059
8135
|
loadLogLines = [];
|
|
8060
8136
|
loadBuckets = [];
|
|
@@ -8066,7 +8142,7 @@ async function runLoadTest() {
|
|
|
8066
8142
|
const r = await fetch('/api/load/run', {
|
|
8067
8143
|
method: 'POST',
|
|
8068
8144
|
headers: { 'Content-Type': 'application/json' },
|
|
8069
|
-
body: JSON.stringify({ script, vus, duration, baseUrl, scriptName, envVars }),
|
|
8145
|
+
body: JSON.stringify({ script, vus, duration, baseUrl, scriptName, dataDir, resultDir, executionMode, vusEnvName, durationEnvName, envVars }),
|
|
8070
8146
|
});
|
|
8071
8147
|
const d = await r.json();
|
|
8072
8148
|
if (!r.ok) { alert('Ошибка запуска: ' + (d.error || r.status)); return; }
|
|
@@ -8147,13 +8223,15 @@ ${featureList || '(нет данных)'}
|
|
|
8147
8223
|
**Шаг 2 — составь k6 скрипт.**
|
|
8148
8224
|
Требования:
|
|
8149
8225
|
1. Валидный JavaScript для k6 (import from 'k6/http', 'k6', 'k6/data')
|
|
8150
|
-
2.
|
|
8226
|
+
2. Можно использовать \`options.scenarios\`; тогда VibeRadar в Auto-режиме не будет передавать \`--vus/--duration\`, а прокинет значения UI в \`__ENV.SMOKE_VUS\` и \`__ENV.SMOKE_DURATION\`
|
|
8151
8227
|
3. \`export default function() { ... }\` с проверками \`check()\`
|
|
8152
8228
|
4. Base URL бери из \`__ENV.BASE_URL || '${baseUrl}'\`
|
|
8153
8229
|
5. Если нужна авторизация — добавь заголовок Authorization (Bearer-токен как переменную __ENV.TOKEN)
|
|
8154
8230
|
6. Если нужна загрузка файла — используй \`http.file()\` и \`open()\`
|
|
8155
|
-
7.
|
|
8156
|
-
8.
|
|
8231
|
+
7. Если нужны CSV/JSON/локальные helper-модули, используй относительные пути от Data dir: \`open('./users.csv')\`, \`import './lib/helper.js'\`
|
|
8232
|
+
8. Не добавляй \`handleSummary\` и не пиши результаты сам: VibeRadar сохраняет summary.json, metrics.ndjson, k6.log
|
|
8233
|
+
9. Добавь \`sleep(1)\` между запросами
|
|
8234
|
+
10. Добавь комментарий в начале: что тестируется и какой эндпоинт
|
|
8157
8235
|
|
|
8158
8236
|
**Шаг 3 — сохрани ТОЛЬКО скрипт в файл.**
|
|
8159
8237
|
Запиши итоговый JavaScript-код в файл: \`.viberadar/load-script-generated.js\`
|
|
@@ -8264,15 +8342,25 @@ async function loadSaveScript() {
|
|
|
8264
8342
|
const baseUrl = (document.getElementById('loadBaseUrl')?.value || loadBaseUrlDraft || 'http://localhost:5000').trim();
|
|
8265
8343
|
const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
|
|
8266
8344
|
const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
|
|
8345
|
+
const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
|
|
8346
|
+
const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
|
|
8347
|
+
const executionMode = (document.getElementById('loadExecutionMode')?.value || loadExecutionModeDraft || 'auto').trim();
|
|
8348
|
+
const vusEnvName = (document.getElementById('loadVusEnvName')?.value || loadVusEnvNameDraft || 'SMOKE_VUS').trim();
|
|
8349
|
+
const durationEnvName = (document.getElementById('loadDurationEnvName')?.value || loadDurationEnvNameDraft || 'SMOKE_DURATION').trim();
|
|
8267
8350
|
loadScriptNameDraft = name;
|
|
8268
8351
|
loadBaseUrlDraft = baseUrl;
|
|
8269
8352
|
loadVusDraft = vus;
|
|
8270
8353
|
loadDurationDraft = duration;
|
|
8354
|
+
loadDataDirDraft = dataDir;
|
|
8355
|
+
loadResultDirDraft = resultDir;
|
|
8356
|
+
loadExecutionModeDraft = executionMode;
|
|
8357
|
+
loadVusEnvNameDraft = vusEnvName;
|
|
8358
|
+
loadDurationEnvNameDraft = durationEnvName;
|
|
8271
8359
|
try {
|
|
8272
8360
|
const r = await fetch('/api/load/scripts', {
|
|
8273
8361
|
method: 'POST',
|
|
8274
8362
|
headers: { 'Content-Type': 'application/json' },
|
|
8275
|
-
body: JSON.stringify({ name, script, baseUrl, vus, duration }),
|
|
8363
|
+
body: JSON.stringify({ name, script, baseUrl, vus, duration, dataDir, resultDir, executionMode, vusEnvName, durationEnvName }),
|
|
8276
8364
|
});
|
|
8277
8365
|
if (!r.ok) { const d = await r.json().catch(() => ({})); alert('Ошибка: ' + (d.error || r.status)); return; }
|
|
8278
8366
|
await loadRefreshScripts();
|
|
@@ -8290,6 +8378,11 @@ async function loadLoadScript(name) {
|
|
|
8290
8378
|
if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
|
|
8291
8379
|
if (s.vus) loadVusDraft = s.vus;
|
|
8292
8380
|
if (s.duration) loadDurationDraft = s.duration;
|
|
8381
|
+
loadDataDirDraft = s.dataDir || loadDataDirDraft;
|
|
8382
|
+
loadResultDirDraft = s.resultDir || loadResultDirDraft;
|
|
8383
|
+
loadExecutionModeDraft = s.executionMode || loadExecutionModeDraft;
|
|
8384
|
+
loadVusEnvNameDraft = s.vusEnvName || loadVusEnvNameDraft;
|
|
8385
|
+
loadDurationEnvNameDraft = s.durationEnvName || loadDurationEnvNameDraft;
|
|
8293
8386
|
const ta = document.getElementById('loadScriptEditor');
|
|
8294
8387
|
if (ta) { ta.value = s.script; ta.style.borderColor = 'var(--blue)'; setTimeout(() => { ta.style.borderColor = ''; }, 1500); }
|
|
8295
8388
|
const nameEl = document.getElementById('loadScriptName');
|