Merge upstream/master and resolve PR conflicts
This commit is contained in:
@@ -324,6 +324,10 @@ Cloudflare 模式下,插件不会再调用 Cloudflare API 创建路由。
|
||||
|
||||
支持多轮运行,运行次数由右上角数字框决定。
|
||||
|
||||
`延迟` 里的“启动前倒计时”只控制整轮 Auto 开始前要不要先倒计时多少分钟。
|
||||
|
||||
`步间随机` 控制 Auto 流程里**每一步真正执行前**的随机等待秒数,默认是 `12 ~ 18` 秒。这个设置只影响 Auto,不影响你手动单步点击执行。
|
||||
|
||||
如果当前面板里已经存在未完成进度,点击 `Auto` 时会弹出选择:
|
||||
|
||||
- `重新开始`:重置当前流程进度,从 Step 1 开始新一轮
|
||||
@@ -366,6 +370,7 @@ Cloudflare 模式下,插件不会再调用 Cloudflare API 创建路由。
|
||||
- Auto 的暂停状态会保存在会话状态中,重新打开侧边栏后仍可继续
|
||||
- 如果你在 Auto 暂停时改为手动点步骤或跳过步骤,面板会先确认并停止 Auto,再切回手动控制
|
||||
- 选择 `继续当前` 时,后台不会先做大而全的前置校验,而是从当前步骤状态直接继续;缺什么条件,就在运行到那一步时再报错或暂停
|
||||
- 除了现有的页面切换等待外,Auto 还会在每一步执行前额外随机等待一段时间;默认是 `12 ~ 18` 秒,可在侧边栏 `步间随机` 中改成你自己的范围
|
||||
|
||||
## 详细步骤说明
|
||||
|
||||
|
||||
+73
-2
@@ -41,6 +41,10 @@ const AUTO_RUN_DELAY_MIN_MINUTES = 1;
|
||||
const AUTO_RUN_DELAY_MAX_MINUTES = 1440;
|
||||
const AUTO_RUN_RETRY_DELAY_MS = 3000;
|
||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
||||
const AUTO_STEP_RANDOM_DELAY_MIN_ALLOWED_SECONDS = 0;
|
||||
const AUTO_STEP_RANDOM_DELAY_MAX_ALLOWED_SECONDS = 600;
|
||||
const AUTO_STEP_RANDOM_DELAY_DEFAULT_MIN_SECONDS = 12;
|
||||
const AUTO_STEP_RANDOM_DELAY_DEFAULT_MAX_SECONDS = 18;
|
||||
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
|
||||
|
||||
initializeSessionStorageAccess();
|
||||
@@ -62,6 +66,8 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
autoRunSkipFailures: true, // 保留旧字段兼容;自动运行遇错时默认重试当前轮。
|
||||
autoRunDelayEnabled: false, // 自动运行是否启用启动前倒计时。
|
||||
autoRunDelayMinutes: 30, // 自动运行倒计时分钟数。
|
||||
autoStepRandomDelayMinSeconds: AUTO_STEP_RANDOM_DELAY_DEFAULT_MIN_SECONDS, // 自动运行每一步执行前的最小随机等待秒数。
|
||||
autoStepRandomDelayMaxSeconds: AUTO_STEP_RANDOM_DELAY_DEFAULT_MAX_SECONDS, // 自动运行每一步执行前的最大随机等待秒数。
|
||||
mailProvider: '163', // 验证码邮箱来源(163 / 163-vip / qq / inbucket)。
|
||||
emailGenerator: 'duck', // 注册邮箱生成方式:duck / cloudflare。
|
||||
inbucketHost: '', // 仅当 mailProvider 为 inbucket 时填写 Inbucket 地址,其他情况保持为空。
|
||||
@@ -69,7 +75,6 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
cloudflareDomain: '', // 仅当 emailGenerator=cloudflare 时填写自定义域名。
|
||||
cloudflareDomains: [], // Cloudflare 可选域名列表。
|
||||
hotmailAccounts: [],
|
||||
autoRunDelayEnabled: false,
|
||||
};
|
||||
|
||||
const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
|
||||
@@ -122,6 +127,32 @@ function normalizeAutoRunDelayMinutes(value) {
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeAutoStepRandomDelaySeconds(value, fallback = AUTO_STEP_RANDOM_DELAY_DEFAULT_MIN_SECONDS) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) {
|
||||
return fallback;
|
||||
}
|
||||
return Math.min(
|
||||
AUTO_STEP_RANDOM_DELAY_MAX_ALLOWED_SECONDS,
|
||||
Math.max(AUTO_STEP_RANDOM_DELAY_MIN_ALLOWED_SECONDS, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeAutoStepRandomDelayRange(settings = {}) {
|
||||
const minSeconds = normalizeAutoStepRandomDelaySeconds(
|
||||
settings.autoStepRandomDelayMinSeconds,
|
||||
PERSISTED_SETTING_DEFAULTS.autoStepRandomDelayMinSeconds
|
||||
);
|
||||
const maxSeconds = Math.max(
|
||||
minSeconds,
|
||||
normalizeAutoStepRandomDelaySeconds(
|
||||
settings.autoStepRandomDelayMaxSeconds,
|
||||
PERSISTED_SETTING_DEFAULTS.autoStepRandomDelayMaxSeconds
|
||||
)
|
||||
);
|
||||
return { minSeconds, maxSeconds };
|
||||
}
|
||||
|
||||
function normalizeRunCount(value) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) {
|
||||
@@ -219,6 +250,16 @@ function normalizePersistentSettingValue(key, value) {
|
||||
return Boolean(value);
|
||||
case 'autoRunDelayMinutes':
|
||||
return normalizeAutoRunDelayMinutes(value);
|
||||
case 'autoStepRandomDelayMinSeconds':
|
||||
return normalizeAutoStepRandomDelaySeconds(
|
||||
value,
|
||||
PERSISTED_SETTING_DEFAULTS.autoStepRandomDelayMinSeconds
|
||||
);
|
||||
case 'autoStepRandomDelayMaxSeconds':
|
||||
return normalizeAutoStepRandomDelaySeconds(
|
||||
value,
|
||||
PERSISTED_SETTING_DEFAULTS.autoStepRandomDelayMaxSeconds
|
||||
);
|
||||
case 'mailProvider':
|
||||
return normalizeMailProvider(value);
|
||||
case 'emailGenerator':
|
||||
@@ -267,6 +308,15 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
||||
payload.cloudflareDomains = domains;
|
||||
}
|
||||
|
||||
if (payload.autoStepRandomDelayMinSeconds !== undefined || payload.autoStepRandomDelayMaxSeconds !== undefined) {
|
||||
const normalizedDelayRange = normalizeAutoStepRandomDelayRange({
|
||||
autoStepRandomDelayMinSeconds: payload.autoStepRandomDelayMinSeconds,
|
||||
autoStepRandomDelayMaxSeconds: payload.autoStepRandomDelayMaxSeconds,
|
||||
});
|
||||
payload.autoStepRandomDelayMinSeconds = normalizedDelayRange.minSeconds;
|
||||
payload.autoStepRandomDelayMaxSeconds = normalizedDelayRange.maxSeconds;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@@ -2425,6 +2475,12 @@ async function humanStepDelay(min = HUMAN_STEP_DELAY_MIN, max = HUMAN_STEP_DELAY
|
||||
await sleepWithStop(duration);
|
||||
}
|
||||
|
||||
function getAutoStepRandomDelayMs(min, max) {
|
||||
const normalizedMin = Math.max(0, Math.floor(Number(min) || 0));
|
||||
const normalizedMax = Math.max(normalizedMin, Math.floor(Number(max) || normalizedMin));
|
||||
return Math.floor(Math.random() * (normalizedMax - normalizedMin + 1)) + normalizedMin;
|
||||
}
|
||||
|
||||
async function clickWithDebugger(tabId, rect) {
|
||||
throwIfStopped();
|
||||
if (!tabId) {
|
||||
@@ -3031,6 +3087,19 @@ async function executeStep(step) {
|
||||
async function executeStepAndWait(step, delayAfter = 2000) {
|
||||
throwIfStopped();
|
||||
|
||||
const delaySettings = normalizeAutoStepRandomDelayRange(await getState());
|
||||
const randomDelayMs = getAutoStepRandomDelayMs(
|
||||
delaySettings.minSeconds * 1000,
|
||||
delaySettings.maxSeconds * 1000
|
||||
);
|
||||
if (randomDelayMs > 0) {
|
||||
await addLog(
|
||||
`自动运行:步骤 ${step} 执行前随机等待 ${delaySettings.minSeconds}-${delaySettings.maxSeconds} 秒,本次约 ${Math.round(randomDelayMs / 1000)} 秒,避免节奏过快。`,
|
||||
'info'
|
||||
);
|
||||
await sleepWithStop(randomDelayMs);
|
||||
}
|
||||
|
||||
if (AUTO_RUN_BACKGROUND_COMPLETED_STEPS.has(step)) {
|
||||
await addLog(`自动运行:步骤 ${step} 由后台流程负责收尾,执行函数返回后将直接进入下一步。`, 'info');
|
||||
await executeStep(step);
|
||||
@@ -3457,6 +3526,8 @@ async function autoRunLoop(totalRuns, options = {}) {
|
||||
autoRunSkipFailures: prevState.autoRunSkipFailures,
|
||||
autoRunDelayEnabled: prevState.autoRunDelayEnabled,
|
||||
autoRunDelayMinutes: prevState.autoRunDelayMinutes,
|
||||
autoStepRandomDelayMinSeconds: prevState.autoStepRandomDelayMinSeconds,
|
||||
autoStepRandomDelayMaxSeconds: prevState.autoStepRandomDelayMaxSeconds,
|
||||
mailProvider: prevState.mailProvider,
|
||||
emailGenerator: prevState.emailGenerator,
|
||||
inbucketHost: prevState.inbucketHost,
|
||||
@@ -4360,7 +4431,7 @@ let webNavListener = null;
|
||||
let webNavCommittedListener = null;
|
||||
let step8TabUpdatedListener = null;
|
||||
let step8PendingReject = null;
|
||||
const STEP8_CLICK_EFFECT_TIMEOUT_MS = 10000;
|
||||
const STEP8_CLICK_EFFECT_TIMEOUT_MS = 15000;
|
||||
const STEP8_CLICK_RETRY_DELAY_MS = 500;
|
||||
const STEP8_READY_WAIT_TIMEOUT_MS = 30000;
|
||||
const STEP8_MAX_ROUNDS = 5;
|
||||
|
||||
@@ -192,6 +192,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<span class="data-label">步间随机</span>
|
||||
<div class="data-inline auto-delay-inline">
|
||||
<div class="auto-delay-controls">
|
||||
<input type="number" id="input-auto-step-delay-min-seconds" class="data-input auto-delay-input" value="12" min="0"
|
||||
max="600" step="1" title="自动运行每一步执行前的最小随机等待秒数" />
|
||||
<span class="data-unit">~</span>
|
||||
<input type="number" id="input-auto-step-delay-max-seconds" class="data-input auto-delay-input" value="18" min="0"
|
||||
max="600" step="1" title="自动运行每一步执行前的最大随机等待秒数" />
|
||||
<span class="data-unit">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<span class="data-label">OAuth</span>
|
||||
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
|
||||
|
||||
@@ -85,6 +85,8 @@ const inputRunCount = document.getElementById('input-run-count');
|
||||
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
|
||||
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
|
||||
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
|
||||
const inputAutoStepDelayMinSeconds = document.getElementById('input-auto-step-delay-min-seconds');
|
||||
const inputAutoStepDelayMaxSeconds = document.getElementById('input-auto-step-delay-max-seconds');
|
||||
const autoStartModal = document.getElementById('auto-start-modal');
|
||||
const autoStartTitle = autoStartModal?.querySelector('.modal-title');
|
||||
const autoStartMessage = document.getElementById('auto-start-message');
|
||||
@@ -108,6 +110,10 @@ const SKIPPABLE_STEPS = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
const AUTO_DELAY_MIN_MINUTES = 1;
|
||||
const AUTO_DELAY_MAX_MINUTES = 1440;
|
||||
const AUTO_DELAY_DEFAULT_MINUTES = 30;
|
||||
const AUTO_STEP_DELAY_MIN_SECONDS = 0;
|
||||
const AUTO_STEP_DELAY_MAX_SECONDS = 600;
|
||||
const AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS = 12;
|
||||
const AUTO_STEP_DELAY_DEFAULT_MAX_SECONDS = 18;
|
||||
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
|
||||
|
||||
let latestState = null;
|
||||
@@ -447,6 +453,23 @@ function normalizeAutoDelayMinutes(value) {
|
||||
return Math.min(AUTO_DELAY_MAX_MINUTES, Math.max(AUTO_DELAY_MIN_MINUTES, Math.floor(numeric)));
|
||||
}
|
||||
|
||||
function normalizeAutoStepDelaySeconds(value, fallback = AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) {
|
||||
return fallback;
|
||||
}
|
||||
return Math.min(AUTO_STEP_DELAY_MAX_SECONDS, Math.max(AUTO_STEP_DELAY_MIN_SECONDS, Math.floor(numeric)));
|
||||
}
|
||||
|
||||
function normalizeAutoStepDelayRange(minValue, maxValue) {
|
||||
const minSeconds = normalizeAutoStepDelaySeconds(minValue, AUTO_STEP_DELAY_DEFAULT_MIN_SECONDS);
|
||||
const maxSeconds = Math.max(
|
||||
minSeconds,
|
||||
normalizeAutoStepDelaySeconds(maxValue, AUTO_STEP_DELAY_DEFAULT_MAX_SECONDS)
|
||||
);
|
||||
return { minSeconds, maxSeconds };
|
||||
}
|
||||
|
||||
function updateAutoDelayInputState() {
|
||||
const scheduled = isAutoRunScheduledPhase();
|
||||
inputAutoDelayEnabled.disabled = scheduled;
|
||||
@@ -598,6 +621,10 @@ function collectSettingsPayload() {
|
||||
const selectedCloudflareDomain = normalizeCloudflareDomainValue(
|
||||
!cloudflareDomainEditMode ? selectCfDomain.value : activeDomain
|
||||
) || activeDomain;
|
||||
const autoStepDelayRange = normalizeAutoStepDelayRange(
|
||||
inputAutoStepDelayMinSeconds.value,
|
||||
inputAutoStepDelayMaxSeconds.value
|
||||
);
|
||||
return {
|
||||
panelMode: selectPanelMode.value,
|
||||
vpsUrl: inputVpsUrl.value.trim(),
|
||||
@@ -617,6 +644,8 @@ function collectSettingsPayload() {
|
||||
autoRunSkipFailures: true,
|
||||
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
|
||||
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
|
||||
autoStepRandomDelayMinSeconds: autoStepDelayRange.minSeconds,
|
||||
autoStepRandomDelayMaxSeconds: autoStepDelayRange.maxSeconds,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -858,6 +887,12 @@ function applySettingsState(state) {
|
||||
inputAutoSkipFailures.checked = true;
|
||||
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
|
||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
|
||||
const autoStepDelayRange = normalizeAutoStepDelayRange(
|
||||
state?.autoStepRandomDelayMinSeconds,
|
||||
state?.autoStepRandomDelayMaxSeconds
|
||||
);
|
||||
inputAutoStepDelayMinSeconds.value = String(autoStepDelayRange.minSeconds);
|
||||
inputAutoStepDelayMaxSeconds.value = String(autoStepDelayRange.maxSeconds);
|
||||
if (state?.autoRunTotalRuns) {
|
||||
inputRunCount.value = String(state.autoRunTotalRuns);
|
||||
}
|
||||
@@ -2380,6 +2415,33 @@ inputAutoDelayMinutes.addEventListener('blur', () => {
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
function syncAutoStepDelayInputs() {
|
||||
const range = normalizeAutoStepDelayRange(
|
||||
inputAutoStepDelayMinSeconds.value,
|
||||
inputAutoStepDelayMaxSeconds.value
|
||||
);
|
||||
inputAutoStepDelayMinSeconds.value = String(range.minSeconds);
|
||||
inputAutoStepDelayMaxSeconds.value = String(range.maxSeconds);
|
||||
}
|
||||
|
||||
inputAutoStepDelayMinSeconds.addEventListener('input', () => {
|
||||
markSettingsDirty(true);
|
||||
scheduleSettingsAutoSave();
|
||||
});
|
||||
inputAutoStepDelayMinSeconds.addEventListener('blur', () => {
|
||||
syncAutoStepDelayInputs();
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
inputAutoStepDelayMaxSeconds.addEventListener('input', () => {
|
||||
markSettingsDirty(true);
|
||||
scheduleSettingsAutoSave();
|
||||
});
|
||||
inputAutoStepDelayMaxSeconds.addEventListener('blur', () => {
|
||||
syncAutoStepDelayInputs();
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// Listen for Background broadcasts
|
||||
// ============================================================
|
||||
@@ -2477,6 +2539,14 @@ chrome.runtime.onMessage.addListener((message) => {
|
||||
if (message.payload.autoRunDelayMinutes !== undefined) {
|
||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(message.payload.autoRunDelayMinutes));
|
||||
}
|
||||
if (message.payload.autoStepRandomDelayMinSeconds !== undefined || message.payload.autoStepRandomDelayMaxSeconds !== undefined) {
|
||||
const autoStepDelayRange = normalizeAutoStepDelayRange(
|
||||
message.payload.autoStepRandomDelayMinSeconds ?? inputAutoStepDelayMinSeconds.value,
|
||||
message.payload.autoStepRandomDelayMaxSeconds ?? inputAutoStepDelayMaxSeconds.value
|
||||
);
|
||||
inputAutoStepDelayMinSeconds.value = String(autoStepDelayRange.minSeconds);
|
||||
inputAutoStepDelayMaxSeconds.value = String(autoStepDelayRange.maxSeconds);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
|
||||
function extractFunction(name) {
|
||||
const start = source.indexOf(`function ${name}(`);
|
||||
if (start < 0) {
|
||||
throw new Error(`missing function ${name}`);
|
||||
}
|
||||
|
||||
const paramsStart = source.indexOf('(', start);
|
||||
let paramsDepth = 0;
|
||||
let paramsEnd = paramsStart;
|
||||
for (; paramsEnd < source.length; paramsEnd += 1) {
|
||||
const ch = source[paramsEnd];
|
||||
if (ch === '(') paramsDepth += 1;
|
||||
if (ch === ')') {
|
||||
paramsDepth -= 1;
|
||||
if (paramsDepth === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const braceStart = source.indexOf('{', paramsEnd);
|
||||
let depth = 0;
|
||||
let end = braceStart;
|
||||
for (; end < source.length; end++) {
|
||||
const ch = source[end];
|
||||
if (ch === '{') depth += 1;
|
||||
if (ch === '}') {
|
||||
depth -= 1;
|
||||
if (depth === 0) {
|
||||
end += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return source.slice(start, end);
|
||||
}
|
||||
|
||||
const bundle = [
|
||||
'const AUTO_STEP_RANDOM_DELAY_MIN_ALLOWED_SECONDS = 0;',
|
||||
'const AUTO_STEP_RANDOM_DELAY_MAX_ALLOWED_SECONDS = 600;',
|
||||
'const AUTO_STEP_RANDOM_DELAY_DEFAULT_MIN_SECONDS = 12;',
|
||||
'const AUTO_STEP_RANDOM_DELAY_DEFAULT_MAX_SECONDS = 18;',
|
||||
'const PERSISTED_SETTING_DEFAULTS = { autoStepRandomDelayMinSeconds: 12, autoStepRandomDelayMaxSeconds: 18 };',
|
||||
extractFunction('normalizeAutoStepRandomDelaySeconds'),
|
||||
extractFunction('normalizeAutoStepRandomDelayRange'),
|
||||
extractFunction('getAutoStepRandomDelayMs'),
|
||||
].join('\n');
|
||||
|
||||
const api = new Function(`${bundle}; return { normalizeAutoStepRandomDelaySeconds, normalizeAutoStepRandomDelayRange, getAutoStepRandomDelayMs };`)();
|
||||
|
||||
const defaultRange = api.normalizeAutoStepRandomDelayRange({});
|
||||
assert.deepStrictEqual(defaultRange, { minSeconds: 12, maxSeconds: 18 }, 'missing settings should fall back to the default 12-18 second range');
|
||||
|
||||
for (let i = 0; i < 200; i += 1) {
|
||||
const delay = api.getAutoStepRandomDelayMs(defaultRange.minSeconds * 1000, defaultRange.maxSeconds * 1000);
|
||||
assert.ok(delay >= 12000, `delay ${delay} should respect the lower bound`);
|
||||
assert.ok(delay <= 18000, `delay ${delay} should respect the upper bound`);
|
||||
assert.ok(Number.isInteger(delay), `delay ${delay} should be an integer`);
|
||||
}
|
||||
|
||||
const samples = new Set(Array.from({ length: 50 }, () => api.getAutoStepRandomDelayMs(defaultRange.minSeconds * 1000, defaultRange.maxSeconds * 1000)));
|
||||
assert.ok(samples.size > 1, 'delay helper should produce randomized values');
|
||||
|
||||
const customRange = api.normalizeAutoStepRandomDelayRange({
|
||||
autoStepRandomDelayMinSeconds: 5,
|
||||
autoStepRandomDelayMaxSeconds: 7,
|
||||
});
|
||||
assert.deepStrictEqual(customRange, { minSeconds: 5, maxSeconds: 7 }, 'configured ranges should be preserved when already valid');
|
||||
|
||||
const collapsedRange = api.normalizeAutoStepRandomDelayRange({
|
||||
autoStepRandomDelayMinSeconds: 20,
|
||||
autoStepRandomDelayMaxSeconds: 10,
|
||||
});
|
||||
assert.deepStrictEqual(collapsedRange, { minSeconds: 20, maxSeconds: 20 }, 'max delay should collapse up to min delay when user input is inverted');
|
||||
|
||||
assert.strictEqual(
|
||||
api.getAutoStepRandomDelayMs(15000, 15000),
|
||||
15000,
|
||||
'equal bounds should produce a deterministic delay'
|
||||
);
|
||||
|
||||
const originalRandom = Math.random;
|
||||
try {
|
||||
Math.random = () => 0.6;
|
||||
assert.strictEqual(
|
||||
api.normalizeAutoStepRandomDelaySeconds(-50, 12),
|
||||
0,
|
||||
'negative configured delay should clamp to zero seconds'
|
||||
);
|
||||
assert.strictEqual(
|
||||
api.getAutoStepRandomDelayMs(-50, 10),
|
||||
6,
|
||||
'lower bound should be clamped to zero and still allow random output'
|
||||
);
|
||||
} finally {
|
||||
Math.random = originalRandom;
|
||||
}
|
||||
|
||||
console.log('auto step random delay tests passed');
|
||||
Reference in New Issue
Block a user