refactor shared flow settings and runtime cleanup
This commit is contained in:
@@ -134,8 +134,6 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -185,7 +183,7 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -201,7 +199,7 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -297,8 +295,6 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -348,7 +344,7 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -364,7 +360,7 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -460,8 +456,6 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -511,7 +505,7 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -527,7 +521,7 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -621,8 +615,6 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -672,7 +664,7 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -688,7 +680,7 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -779,8 +771,6 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -830,7 +820,7 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -846,7 +836,7 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -943,8 +933,6 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -994,7 +982,7 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -1010,7 +998,7 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -1108,8 +1096,6 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: 'custom',
|
||||
customMailProviderPool: ['first@example.com'],
|
||||
@@ -1160,7 +1146,7 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -1176,7 +1162,7 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -1274,8 +1260,6 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
@@ -1325,7 +1309,7 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
||||
events.broadcasts.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -1341,7 +1325,7 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
||||
return sessionSeed;
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
|
||||
@@ -130,8 +130,6 @@ let currentState = {
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
signupMethod: 'phone',
|
||||
resolvedSignupMethod: 'phone',
|
||||
@@ -204,8 +202,6 @@ async function resetState() {
|
||||
customPassword: prev.customPassword,
|
||||
autoRunSkipFailures: prev.autoRunSkipFailures,
|
||||
autoRunFallbackThreadIntervalMinutes: prev.autoRunFallbackThreadIntervalMinutes,
|
||||
autoRunDelayEnabled: prev.autoRunDelayEnabled,
|
||||
autoRunDelayMinutes: prev.autoRunDelayMinutes,
|
||||
autoStepDelaySeconds: prev.autoStepDelaySeconds,
|
||||
signupMethod: prev.signupMethod,
|
||||
resolvedSignupMethod: null,
|
||||
|
||||
@@ -104,8 +104,6 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: 'hotmail-api',
|
||||
emailGenerator: 'duck',
|
||||
@@ -149,7 +147,7 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
||||
broadcastAutoRunStatus: async (phase, payload = {}) => {
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||
@@ -169,7 +167,7 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
||||
events.preflightCalls.push({ ...payload });
|
||||
},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
|
||||
@@ -36,8 +36,6 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
signupMethod: 'email',
|
||||
stepExecutionRangeByFlow: {
|
||||
@@ -94,7 +92,7 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
||||
currentState = {
|
||||
...currentState,
|
||||
...extraState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
||||
@@ -124,7 +122,7 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
||||
},
|
||||
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
@@ -179,8 +177,6 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
signupMethod: 'email',
|
||||
stepExecutionRangeByFlow: {
|
||||
@@ -445,8 +441,6 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
||||
flowId: 'kiro',
|
||||
autoRunSkipFailures: true,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
nodeStatuses: {
|
||||
'kiro-open-register-page': 'pending',
|
||||
@@ -496,7 +490,7 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
||||
events.phases.push({ phase, ...payload });
|
||||
currentState = {
|
||||
...currentState,
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
||||
@@ -514,7 +508,7 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
||||
},
|
||||
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
|
||||
@@ -63,7 +63,6 @@ const helperBundle = [
|
||||
|
||||
test('launchAutoRunTimerPlan ignores stale timer plans after stop invalidates the session', async () => {
|
||||
const api = new Function(`
|
||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
||||
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
||||
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
||||
@@ -76,14 +75,15 @@ let autoRunAttemptRun = 0;
|
||||
let autoRunSessionId = 0;
|
||||
|
||||
const state = {
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunTimerPlan: {
|
||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
||||
kind: AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS,
|
||||
fireAt: Date.now() + 60_000,
|
||||
totalRuns: 2,
|
||||
autoRunSkipFailures: false,
|
||||
autoRunSessionId: 42,
|
||||
countdownTitle: '已计划自动运行',
|
||||
currentRun: 1,
|
||||
attemptRun: 1,
|
||||
countdownTitle: '等待继续',
|
||||
countdownNote: '等待启动',
|
||||
},
|
||||
};
|
||||
@@ -106,7 +106,6 @@ async function clearAutoRunTimerAlarm() {
|
||||
|
||||
async function broadcastAutoRunStatus() {}
|
||||
async function addLog() {}
|
||||
async function setAutoRunDelayEnabledState() {}
|
||||
function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
|
||||
return Array.isArray(summaries) ? summaries : [];
|
||||
}
|
||||
@@ -137,116 +136,10 @@ return {
|
||||
const started = await api.launchAutoRunTimerPlan('alarm');
|
||||
const snapshot = api.snapshot();
|
||||
|
||||
assert.equal(started, false);
|
||||
assert.equal(snapshot.startCalls, 0, 'stale timer plan should not restart auto-run');
|
||||
assert.equal(snapshot.clearStopCalls, 0, 'stale timer plan should not clear the stop flag for a cancelled run');
|
||||
assert.equal(snapshot.clearAlarmCalls, 0, 'stale timer plan should not clear a potentially newer alarm');
|
||||
assert.equal(snapshot.autoRunCurrentRun, 0);
|
||||
assert.equal(snapshot.autoRunTotalRuns, 1);
|
||||
assert.equal(snapshot.autoRunAttemptRun, 0);
|
||||
});
|
||||
|
||||
test('launchAutoRunTimerPlan cancels an invalid scheduled start before restarting auto-run', async () => {
|
||||
const api = new Function(`
|
||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
||||
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
||||
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
||||
|
||||
let autoRunTimerLaunching = false;
|
||||
let autoRunActive = false;
|
||||
let autoRunCurrentRun = 0;
|
||||
let autoRunTotalRuns = 1;
|
||||
let autoRunAttemptRun = 0;
|
||||
let autoRunSessionId = 0;
|
||||
|
||||
const state = {
|
||||
activeFlowId: 'site-a',
|
||||
panelMode: 'cpa',
|
||||
signupMethod: 'phone',
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunTimerPlan: {
|
||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
||||
fireAt: Date.now() + 60_000,
|
||||
totalRuns: 2,
|
||||
autoRunSkipFailures: false,
|
||||
autoRunSessionId: 0,
|
||||
countdownTitle: '已计划自动运行',
|
||||
countdownNote: '等待启动',
|
||||
},
|
||||
};
|
||||
|
||||
let startCalls = 0;
|
||||
let clearStopCalls = 0;
|
||||
let clearAlarmCalls = 0;
|
||||
const broadcasts = [];
|
||||
const logs = [];
|
||||
|
||||
async function getState() {
|
||||
return { ...state };
|
||||
}
|
||||
|
||||
function getPendingAutoRunTimerPlan() {
|
||||
return state.autoRunTimerPlan;
|
||||
}
|
||||
|
||||
async function clearAutoRunTimerAlarm() {
|
||||
clearAlarmCalls += 1;
|
||||
}
|
||||
|
||||
async function broadcastAutoRunStatus(phase, statusPayload, statePayload) {
|
||||
broadcasts.push({ phase, statusPayload, statePayload });
|
||||
}
|
||||
async function addLog(message, level) {
|
||||
logs.push({ message, level });
|
||||
}
|
||||
async function setAutoRunDelayEnabledState() {}
|
||||
function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
|
||||
return Array.isArray(summaries) ? summaries : [];
|
||||
}
|
||||
function clearStopRequest() {
|
||||
clearStopCalls += 1;
|
||||
}
|
||||
function startAutoRunLoop() {
|
||||
startCalls += 1;
|
||||
}
|
||||
function validateAutoRunStartState() {
|
||||
return {
|
||||
ok: false,
|
||||
errors: [{ message: '当前 flow 不支持手机号注册。' }],
|
||||
};
|
||||
}
|
||||
|
||||
${helperBundle}
|
||||
|
||||
return {
|
||||
launchAutoRunTimerPlan,
|
||||
snapshot() {
|
||||
return {
|
||||
startCalls,
|
||||
clearStopCalls,
|
||||
clearAlarmCalls,
|
||||
broadcasts,
|
||||
logs,
|
||||
autoRunCurrentRun,
|
||||
autoRunTotalRuns,
|
||||
autoRunAttemptRun,
|
||||
};
|
||||
},
|
||||
};
|
||||
`)();
|
||||
|
||||
const started = await api.launchAutoRunTimerPlan('alarm');
|
||||
const snapshot = api.snapshot();
|
||||
|
||||
assert.equal(started, false);
|
||||
assert.equal(snapshot.startCalls, 0);
|
||||
assert.equal(snapshot.clearStopCalls, 0);
|
||||
assert.equal(snapshot.clearAlarmCalls, 1);
|
||||
assert.equal(snapshot.broadcasts.length, 1);
|
||||
assert.equal(snapshot.broadcasts[0].phase, 'idle');
|
||||
assert.match(snapshot.logs[0].message, /自动运行计划已取消:当前 flow 不支持手机号注册。/);
|
||||
assert.equal(snapshot.logs[0].level, 'error');
|
||||
assert.equal(snapshot.clearAlarmCalls, 0);
|
||||
assert.equal(snapshot.autoRunCurrentRun, 0);
|
||||
assert.equal(snapshot.autoRunTotalRuns, 1);
|
||||
assert.equal(snapshot.autoRunAttemptRun, 0);
|
||||
|
||||
@@ -196,7 +196,6 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
function normalizePanelMode(value) { return value === 'sub2api' ? 'sub2api' : (value === 'codex2api' ? 'codex2api' : 'cpa'); }
|
||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value) { return value == null || value === '' ? null : Number(value); }
|
||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||
function normalizeMail2925Mode(value) { return String(value || '').trim().toLowerCase() === 'receive' ? 'receive' : 'provide'; }
|
||||
|
||||
@@ -82,7 +82,6 @@ function normalizeSignupMethod(value = '') { return String(value || '').trim().t
|
||||
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||
@@ -180,7 +179,6 @@ function normalizeSignupMethod(value = '') { return String(value || '').trim().t
|
||||
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||
|
||||
@@ -372,7 +372,7 @@ test('message router re-syncs contribution mode before AUTO_RUN when sidepanel p
|
||||
]);
|
||||
});
|
||||
|
||||
test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run validation fails', async () => {
|
||||
test('message router blocks AUTO_RUN when shared auto-run validation fails', async () => {
|
||||
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||
const globalScope = {};
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||
@@ -388,10 +388,6 @@ test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run
|
||||
stepStatuses: {},
|
||||
}),
|
||||
normalizeRunCount: (value) => Number(value) || 1,
|
||||
scheduleAutoRun: async () => {
|
||||
calls.push({ type: 'scheduleAutoRun' });
|
||||
return { ok: true };
|
||||
},
|
||||
setState: async (updates) => {
|
||||
calls.push({ type: 'setState', updates });
|
||||
},
|
||||
@@ -415,19 +411,6 @@ test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run
|
||||
}),
|
||||
/当前 flow 不支持手机号注册。/
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
() => router.handleMessage({
|
||||
type: 'SCHEDULE_AUTO_RUN',
|
||||
payload: {
|
||||
totalRuns: 2,
|
||||
delayMinutes: 5,
|
||||
autoRunSkipFailures: false,
|
||||
},
|
||||
}),
|
||||
/当前 flow 不支持手机号注册。/
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
|
||||
@@ -99,9 +99,6 @@ function normalizeMailProvider(value = '') {
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
||||
return Math.max(0, Math.floor(Number(value) || 0));
|
||||
}
|
||||
function normalizeAutoRunDelayMinutes(value) {
|
||||
return Math.max(1, Math.floor(Number(value) || 30));
|
||||
}
|
||||
function normalizeAutoStepDelaySeconds(value, fallback = null) {
|
||||
const numeric = Number(value);
|
||||
return Number.isFinite(numeric) ? Math.max(0, Math.floor(numeric)) : fallback;
|
||||
|
||||
@@ -35,7 +35,6 @@ function createRouterWithFinalNode(options = {}) {
|
||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||
buildPersistentSettingsPayload: () => ({}),
|
||||
broadcastDataUpdate: () => {},
|
||||
cancelScheduledAutoRun: async () => {},
|
||||
checkIcloudSession: async () => {},
|
||||
clearAutoRunTimerAlarm: async () => {},
|
||||
clearLuckmailRuntimeState: async () => {},
|
||||
@@ -87,7 +86,6 @@ function createRouterWithFinalNode(options = {}) {
|
||||
listLuckmailPurchasesForManagement: async () => [],
|
||||
normalizeHotmailAccounts: (items) => items,
|
||||
normalizeRunCount: (value) => value,
|
||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
|
||||
notifyNodeComplete: () => {},
|
||||
notifyNodeError: () => {},
|
||||
patchHotmailAccount: async () => {},
|
||||
@@ -96,7 +94,6 @@ function createRouterWithFinalNode(options = {}) {
|
||||
requestStop: async () => {},
|
||||
resetState: async () => {},
|
||||
resumeAutoRun: async () => {},
|
||||
scheduleAutoRun: async () => {},
|
||||
selectLuckmailPurchase: async () => {},
|
||||
setCurrentHotmailAccount: async () => {},
|
||||
setCurrentMail2925Account: async () => {},
|
||||
|
||||
@@ -103,7 +103,6 @@ function createRouter(overrides = {}) {
|
||||
broadcastDataUpdate: (updates) => {
|
||||
events.broadcasts.push(updates);
|
||||
},
|
||||
cancelScheduledAutoRun: async () => {},
|
||||
checkIcloudSession: async () => {},
|
||||
clearAutoRunTimerAlarm: async () => {},
|
||||
clearLuckmailRuntimeState: async () => {},
|
||||
@@ -171,7 +170,6 @@ function createRouter(overrides = {}) {
|
||||
listLuckmailPurchasesForManagement: async () => [],
|
||||
normalizeHotmailAccounts: (items) => items,
|
||||
normalizeRunCount: (value) => value,
|
||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
|
||||
notifyNodeComplete: (nodeId, payload) => {
|
||||
events.notifyCompletions.push({ step: getStepForNode(nodeId), nodeId, payload });
|
||||
},
|
||||
@@ -183,7 +181,6 @@ function createRouter(overrides = {}) {
|
||||
requestStop: async () => {},
|
||||
resetState: async () => {},
|
||||
resumeAutoRun: async () => {},
|
||||
scheduleAutoRun: async () => {},
|
||||
selectLuckmailPurchase: async () => {},
|
||||
setCurrentHotmailAccount: async () => {},
|
||||
setEmailState: async (email) => {
|
||||
|
||||
@@ -195,7 +195,6 @@ let step8TabUpdatedListener = null;
|
||||
let step8PendingReject = null;
|
||||
let resumeWaiter = null;
|
||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
||||
const DEFAULT_STATE = {
|
||||
stepStatuses: Object.fromEntries([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((step) => [step, 'pending'])),
|
||||
};
|
||||
@@ -218,7 +217,6 @@ function abortActiveIcloudRequests() {}
|
||||
function getPendingAutoRunTimerPlan() {
|
||||
return null;
|
||||
}
|
||||
async function cancelScheduledAutoRun() {}
|
||||
async function clearAutoRunTimerAlarm() {}
|
||||
function clearStopRequest() {
|
||||
stopRequested = false;
|
||||
|
||||
@@ -94,7 +94,7 @@ test('flow capability registry exposes Kiro as an independent flow with its own
|
||||
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, ['kiro-builder-id']);
|
||||
assert.deepEqual(
|
||||
capabilityState.visibleGroupIds,
|
||||
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||
['kiro-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||
);
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ test('flow capability registry exposes Grok as an independent SSO flow without O
|
||||
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, []);
|
||||
assert.deepEqual(
|
||||
capabilityState.visibleGroupIds,
|
||||
['grok-runtime-status', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||
['grok-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -21,20 +21,32 @@ test('flow registry exposes canonical flow and target metadata', () => {
|
||||
assert.equal(flowRegistry.normalizeFlowId('grok'), 'grok');
|
||||
assert.equal(flowRegistry.normalizeFlowId('unknown'), 'openai');
|
||||
assert.equal(flowRegistry.getFlowLabel('openai'), 'Codex / OpenAI');
|
||||
assert.deepEqual(
|
||||
flowRegistry.getFlowDefinition('openai')?.settingsDefaults?.autoRun?.stepExecutionRange,
|
||||
{ enabled: false, fromStep: 1, toStep: 11 }
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getFlowDefinition('openai')?.targets?.cpa?.defaultState,
|
||||
{ vpsUrl: '', vpsPassword: '', localCpaStep9Mode: 'submit' }
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getFlowDefinition('kiro')?.targets?.['kiro-rs']?.defaultState,
|
||||
{ baseUrl: '', apiKey: '' }
|
||||
);
|
||||
assert.equal(flowRegistry.normalizeTargetId('openai', 'sub2api'), 'sub2api');
|
||||
assert.equal(flowRegistry.normalizeTargetId('kiro', 'anything-else'), 'kiro-rs');
|
||||
assert.equal(flowRegistry.normalizeTargetId('grok', 'anything-else'), 'webchat2api');
|
||||
assert.deepEqual(
|
||||
flowRegistry.getVisibleGroupIds('openai', 'cpa'),
|
||||
['openai-plus', 'openai-phone', 'openai-oauth', 'openai-step6', 'openai-target-cpa', 'service-account', 'service-email', 'service-proxy']
|
||||
['openai-plus', 'openai-phone', 'shared-auto-run', 'openai-oauth', 'openai-step6', 'shared-settings-actions', 'openai-target-cpa', 'service-account', 'service-email', 'service-proxy']
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getVisibleGroupIds('kiro', 'kiro-rs'),
|
||||
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||
['kiro-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getVisibleGroupIds('grok', 'webchat2api'),
|
||||
['grok-runtime-status', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||
['grok-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getTargetOptions('openai').map((entry) => entry.id),
|
||||
@@ -48,6 +60,14 @@ test('flow registry exposes canonical flow and target metadata', () => {
|
||||
flowRegistry.getSettingsGroupDefinition('openai-plus')?.rowIds,
|
||||
['row-plus-mode', 'row-plus-account-access-strategy', 'row-plus-payment-method']
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getSettingsGroupDefinition('shared-auto-run')?.rowIds,
|
||||
['row-shared-auto-run', 'row-auto-run-thread-interval', 'row-step-execution-range']
|
||||
);
|
||||
assert.deepEqual(
|
||||
flowRegistry.getSettingsGroupDefinition('shared-settings-actions')?.rowIds,
|
||||
['row-settings-actions']
|
||||
);
|
||||
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
|
||||
assert.equal(flowRegistry.getFlowCapabilities('openai').supportsAccountContribution, true);
|
||||
assert.equal(flowRegistry.getFlowCapabilities('kiro').supportsAccountContribution, true);
|
||||
|
||||
@@ -78,6 +78,9 @@ test('grok verification runner polls by flow node and submits normalized code',
|
||||
registerTab: async () => {},
|
||||
sendToContentScriptResilient: async (sourceId, message) => {
|
||||
calls.push({ type: 'send', sourceId, message });
|
||||
if (message.nodeId === 'GET_PAGE_STATE') {
|
||||
return { submitted: true, state: 'verification_code_entry', url: 'https://accounts.x.ai/verify' };
|
||||
}
|
||||
return { submitted: true, state: 'profile_entry', url: 'https://accounts.x.ai/profile' };
|
||||
},
|
||||
setState: async (patch) => {
|
||||
@@ -97,7 +100,9 @@ test('grok verification runner polls by flow node and submits normalized code',
|
||||
assert.equal(pollCall.options.state.activeFlowId, 'grok');
|
||||
assert.equal(pollCall.options.state.visibleStep, 3);
|
||||
|
||||
const sendCall = calls.find((entry) => entry.type === 'send');
|
||||
const sendCall = calls.find((entry) => (
|
||||
entry.type === 'send' && entry.message.nodeId === 'grok-submit-verification-code'
|
||||
));
|
||||
assert.equal(sendCall.sourceId, 'grok-register-page');
|
||||
assert.equal(sendCall.message.type, 'EXECUTE_NODE');
|
||||
assert.equal(sendCall.message.nodeId, 'grok-submit-verification-code');
|
||||
@@ -110,6 +115,75 @@ test('grok verification runner polls by flow node and submits normalized code',
|
||||
assert.equal(getGrokRuntime(completedPayload).register.status, 'verified');
|
||||
});
|
||||
|
||||
test('grok verification runner waits for verification page before polling mail', async () => {
|
||||
const api = loadGrokRunnerApi();
|
||||
let pollCalled = false;
|
||||
let currentState = {
|
||||
activeFlowId: 'grok',
|
||||
grokRegisterTabId: 102,
|
||||
grokEmail: 'grok-user@example.com',
|
||||
grokVerificationRequestedAt: 1000000,
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
grok: {
|
||||
session: {
|
||||
registerTabId: 102,
|
||||
},
|
||||
register: {
|
||||
email: 'grok-user@example.com',
|
||||
verificationRequestedAt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const originalDateNow = Date.now;
|
||||
let fakeNow = 1000000;
|
||||
const runner = api.createGrokRegisterRunner({
|
||||
addLog: async () => {},
|
||||
chrome: {
|
||||
tabs: {
|
||||
get: async (tabId) => ({ id: tabId }),
|
||||
update: async () => {},
|
||||
},
|
||||
},
|
||||
completeNodeFromBackground: async () => {},
|
||||
ensureContentScriptReadyOnTab: async () => {},
|
||||
getState: async () => currentState,
|
||||
getTabId: async () => 102,
|
||||
isTabAlive: async () => true,
|
||||
pollFlowVerificationCode: async () => {
|
||||
pollCalled = true;
|
||||
return { code: 'ABC-123', messageId: 'mail-001' };
|
||||
},
|
||||
registerTab: async () => {},
|
||||
sendToContentScriptResilient: async (_sourceId, message) => {
|
||||
if (message.nodeId === 'GET_PAGE_STATE') {
|
||||
return { submitted: true, state: 'email_entry', url: 'https://accounts.x.ai/sign-up' };
|
||||
}
|
||||
return { submitted: true, state: 'profile_entry', url: 'https://accounts.x.ai/profile' };
|
||||
},
|
||||
setState: async (patch) => {
|
||||
currentState = { ...currentState, ...patch };
|
||||
},
|
||||
sleepWithStop: async (ms = 0) => {
|
||||
fakeNow += Number(ms) || 1000;
|
||||
},
|
||||
waitForTabStableComplete: async () => {},
|
||||
});
|
||||
|
||||
Date.now = () => fakeNow;
|
||||
try {
|
||||
await assert.rejects(
|
||||
() => runner.executeGrokSubmitVerificationCode({ nodeId: 'grok-submit-verification-code', ...currentState }),
|
||||
/尚未进入验证码页面/
|
||||
);
|
||||
} finally {
|
||||
Date.now = originalDateNow;
|
||||
}
|
||||
assert.equal(pollCalled, false);
|
||||
});
|
||||
|
||||
test('grok SSO extraction stores only the current cookie without logging the secret value', async () => {
|
||||
const api = loadGrokRunnerApi();
|
||||
const logs = [];
|
||||
|
||||
@@ -85,7 +85,6 @@ test('sidepanel idle auto-run status does not reset manual run count input', ()
|
||||
extractFunction(source, 'syncAutoRunState'),
|
||||
extractFunction(source, 'isAutoRunLockedPhase'),
|
||||
extractFunction(source, 'isAutoRunPausedPhase'),
|
||||
extractFunction(source, 'isAutoRunScheduledPhase'),
|
||||
extractFunction(source, 'applyAutoRunStatus'),
|
||||
].join('\n');
|
||||
|
||||
@@ -96,7 +95,6 @@ let currentAutoRun = {
|
||||
currentRun: 0,
|
||||
totalRuns: 1,
|
||||
attemptRun: 0,
|
||||
scheduledAt: null,
|
||||
countdownAt: null,
|
||||
countdownTitle: '',
|
||||
countdownNote: '',
|
||||
@@ -116,9 +114,8 @@ function getLockedRunCountFromEmailPool() { return lockedRunCount; }
|
||||
function isCustomMailProvider() { return false; }
|
||||
function usesCustomEmailPoolGenerator() { return false; }
|
||||
function setDefaultAutoRunButton() {}
|
||||
function updateAutoDelayInputState() {}
|
||||
function updateFallbackThreadIntervalInputState() {}
|
||||
function syncScheduledCountdownTicker() {}
|
||||
function syncAutoRunCountdownTicker() {}
|
||||
function updateStopButtonState() {}
|
||||
function getStepStatuses() { return {}; }
|
||||
function updateConfigMenuControls() {}
|
||||
@@ -171,7 +168,6 @@ test('sidepanel pending auto-run start ignores stale active run count sync', ()
|
||||
extractFunction(source, 'syncAutoRunState'),
|
||||
extractFunction(source, 'isAutoRunLockedPhase'),
|
||||
extractFunction(source, 'isAutoRunPausedPhase'),
|
||||
extractFunction(source, 'isAutoRunScheduledPhase'),
|
||||
extractFunction(source, 'isAutoRunSourceSyncPhase'),
|
||||
extractFunction(source, 'shouldSyncRunCountFromAutoRunSource'),
|
||||
extractFunction(source, 'applyAutoRunStatus'),
|
||||
@@ -184,7 +180,6 @@ let currentAutoRun = {
|
||||
currentRun: 0,
|
||||
totalRuns: 1,
|
||||
attemptRun: 0,
|
||||
scheduledAt: null,
|
||||
countdownAt: null,
|
||||
countdownTitle: '',
|
||||
countdownNote: '',
|
||||
@@ -205,9 +200,8 @@ function getLockedRunCountFromEmailPool() { return 0; }
|
||||
function isCustomMailProvider() { return false; }
|
||||
function usesCustomEmailPoolGenerator() { return false; }
|
||||
function setDefaultAutoRunButton() {}
|
||||
function updateAutoDelayInputState() {}
|
||||
function updateFallbackThreadIntervalInputState() {}
|
||||
function syncScheduledCountdownTicker() {}
|
||||
function syncAutoRunCountdownTicker() {}
|
||||
function updateStopButtonState() {}
|
||||
function getStepStatuses() { return {}; }
|
||||
function updateConfigMenuControls() {}
|
||||
|
||||
@@ -73,8 +73,6 @@ const inputAutoSkipFailures = { checked: false };
|
||||
const inputContributionNickname = { value: 'tester' };
|
||||
const inputContributionQq = { value: '123456' };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const btnAutoRun = { disabled: false, innerHTML: '' };
|
||||
const inputRunCount = { disabled: false };
|
||||
const selectFlow = { value: latestState.activeFlowId };
|
||||
@@ -132,7 +130,6 @@ function shouldWarnAutoRunFallbackRisk() { return false; }
|
||||
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
||||
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
||||
function setAutoRunFallbackRiskPromptDismissed() {}
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
async function refreshContributionContentHint() {
|
||||
events.push({ type: 'refresh' });
|
||||
${refreshImpl ? 'return (' + refreshImpl + ')();' : 'return null;'}
|
||||
@@ -272,8 +269,6 @@ const inputAutoSkipFailures = { checked: false };
|
||||
const inputContributionNickname = { value: 'tester' };
|
||||
const inputContributionQq = { value: '123456' };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const btnAutoRun = { disabled: false, innerHTML: '' };
|
||||
const inputRunCount = { disabled: false, value: '1' };
|
||||
const inputPhoneVerificationEnabled = { checked: true };
|
||||
@@ -324,7 +319,6 @@ function shouldWarnAutoRunFallbackRisk() { return false; }
|
||||
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
||||
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
||||
function setAutoRunFallbackRiskPromptDismissed() {}
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
async function refreshContributionContentHint() {
|
||||
events.push({ type: 'refresh' });
|
||||
return null;
|
||||
|
||||
@@ -247,8 +247,6 @@ const inputTempEmailReceiveMailbox = { value: 'relay@example.com' };
|
||||
const inputTempEmailUseRandomSubdomain = { checked: true };
|
||||
const inputAutoSkipFailures = { checked: false };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||
const inputAutoDelayEnabled = { checked: true };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const inputAutoStepDelaySeconds = { value: '10' };
|
||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||
const inputVerificationResendCount = { value: '6' };
|
||||
@@ -297,7 +295,6 @@ function normalizeLuckmailEmailType(value) { return String(value || '').trim();
|
||||
function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value || '').trim(); }
|
||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||
|
||||
@@ -38,7 +38,12 @@ test('sidepanel html exposes flow selector and kiro source fields', () => {
|
||||
'id="select-flow"',
|
||||
'<option value="grok">Grok</option>',
|
||||
'id="label-source-selector"',
|
||||
'id="btn-open-webchat2api-github"',
|
||||
'id="row-step6-cookie-settings"',
|
||||
'id="row-shared-auto-run"',
|
||||
'id="row-auto-run-thread-interval"',
|
||||
'id="row-oauth-callback"',
|
||||
'id="row-settings-actions"',
|
||||
'id="row-kiro-rs-url"',
|
||||
'id="btn-open-kiro-rs-github"',
|
||||
'id="row-kiro-rs-key"',
|
||||
@@ -148,6 +153,10 @@ test('sidepanel Kiro GitHub button opens the configured fork', () => {
|
||||
assert.doesNotMatch(sidepanelSource, /github\.com\/hank9999\/kiro\.rs/);
|
||||
});
|
||||
|
||||
test('sidepanel webchat2api GitHub button opens the configured repository', () => {
|
||||
assert.match(sidepanelSource, /openExternalUrl\('https:\/\/github\.com\/zqbxdev\/webchat2api'\)/);
|
||||
});
|
||||
|
||||
test('sidepanel step definitions rerender when active flow changes even if plus/signup settings stay the same', () => {
|
||||
const bundle = [
|
||||
extractFunction(sidepanelSource, 'normalizeSignupMethod'),
|
||||
|
||||
@@ -132,8 +132,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||
const inputAutoSkipFailures = { checked: false };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const inputAutoStepDelaySeconds = { value: '' };
|
||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||
const inputVerificationResendCount = { value: '4' };
|
||||
@@ -220,7 +218,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||
@@ -408,8 +405,6 @@ const selectLuckmailEmailType = { value: 'ms_graph' };
|
||||
const inputLuckmailDomain = { value: '' };
|
||||
const inputAutoSkipFailures = { checked: false };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '' };
|
||||
const inputAutoStepDelaySeconds = { value: '' };
|
||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||
const inputVerificationResendCount = { value: '' };
|
||||
@@ -483,7 +478,6 @@ function applyCloudflareTempEmailSettingsState() {}
|
||||
function renderCloudflareDomainOptions() {}
|
||||
function setCloudflareDomainEditMode() {}
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
function formatAutoStepDelayInputValue(value) { return value == null ? '' : String(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||
function normalizeHeroSmsMaxPriceValue(value = '') { return String(value || '').trim(); }
|
||||
@@ -519,7 +513,6 @@ function updateHeroSmsPlatformDisplay() {}
|
||||
function updatePhoneSmsProviderOrderSummary() {}
|
||||
function applyAutoRunStatus() {}
|
||||
function markSettingsDirty() {}
|
||||
function updateAutoDelayInputState() {}
|
||||
function updateFallbackThreadIntervalInputState() {}
|
||||
function updateAccountRunHistorySettingsUI() {}
|
||||
function updatePhoneVerificationSettingsUI() {}
|
||||
|
||||
@@ -203,8 +203,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||
const inputAutoSkipFailures = { checked: false };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const inputAutoStepDelaySeconds = { value: '' };
|
||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||
const inputVerificationResendCount = { value: '4' };
|
||||
@@ -258,7 +256,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||
|
||||
@@ -38,25 +38,37 @@ function extractFunction(name) {
|
||||
throw new Error(`unterminated ${name}`);
|
||||
}
|
||||
|
||||
test('sidepanel no longer exposes operation delay switch and places step execution range below oauth timeout', () => {
|
||||
test('sidepanel splits shared auto-run controls from openai oauth controls', () => {
|
||||
assert.doesNotMatch(html, /id="row-operation-delay-settings"/);
|
||||
assert.doesNotMatch(html, /id="input-operation-delay-enabled"/);
|
||||
assert.doesNotMatch(html, /id="row-auto-delay-settings"/);
|
||||
assert.doesNotMatch(html, /id="input-auto-delay-enabled"/);
|
||||
assert.doesNotMatch(html, /id="input-auto-delay-minutes"/);
|
||||
|
||||
const step6CookieIndex = html.indexOf('id="row-step6-cookie-settings"');
|
||||
const autoDelayIndex = html.indexOf('id="row-auto-delay-settings"');
|
||||
const sharedAutoRunIndex = html.indexOf('id="row-shared-auto-run"');
|
||||
const threadIntervalIndex = html.indexOf('id="row-auto-run-thread-interval"');
|
||||
const oauthTimeoutIndex = html.indexOf('id="row-oauth-flow-timeout"');
|
||||
const stepRangeIndex = html.indexOf('id="row-step-execution-range"');
|
||||
const oauthDisplayIndex = html.indexOf('id="row-oauth-display"');
|
||||
const oauthCallbackIndex = html.indexOf('id="row-oauth-callback"');
|
||||
const settingsActionsIndex = html.indexOf('id="row-settings-actions"');
|
||||
|
||||
assert.notEqual(step6CookieIndex, -1);
|
||||
assert.notEqual(autoDelayIndex, -1);
|
||||
assert.notEqual(sharedAutoRunIndex, -1);
|
||||
assert.notEqual(threadIntervalIndex, -1);
|
||||
assert.notEqual(oauthTimeoutIndex, -1);
|
||||
assert.notEqual(stepRangeIndex, -1);
|
||||
assert.notEqual(oauthDisplayIndex, -1);
|
||||
assert.ok(autoDelayIndex > step6CookieIndex, 'startup delay row should render below the openai step6 cookie row');
|
||||
assert.ok(stepRangeIndex > autoDelayIndex, 'step execution range should still remain below the startup delay row');
|
||||
assert.notEqual(oauthCallbackIndex, -1);
|
||||
assert.notEqual(settingsActionsIndex, -1);
|
||||
assert.ok(sharedAutoRunIndex > step6CookieIndex, 'shared auto-run should render below the openai step6 cookie row');
|
||||
assert.ok(threadIntervalIndex > sharedAutoRunIndex, 'thread interval should be part of the shared auto-run block');
|
||||
assert.ok(threadIntervalIndex < oauthTimeoutIndex, 'thread interval should stay outside openai oauth controls');
|
||||
assert.ok(stepRangeIndex > oauthTimeoutIndex, 'step execution range should render below oauth timeout');
|
||||
assert.ok(stepRangeIndex < oauthDisplayIndex, 'step execution range should stay above oauth runtime display');
|
||||
assert.ok(oauthCallbackIndex > oauthDisplayIndex, 'openai callback row should follow the oauth display');
|
||||
assert.ok(settingsActionsIndex > oauthCallbackIndex, 'save settings action should live outside the callback row');
|
||||
});
|
||||
|
||||
test('sidepanel operation delay state is always normalized back to enabled', () => {
|
||||
|
||||
@@ -713,7 +713,6 @@ function setFreePhoneReuseControlsLocked(locked) {
|
||||
|| !Boolean(inputPhoneVerificationEnabled.checked && phoneVerificationSectionExpanded);
|
||||
}
|
||||
function isAutoRunLockedPhase() { return false; }
|
||||
function isAutoRunScheduledPhase() { return false; }
|
||||
|
||||
${extractFunction('normalizeSignupMethod')}
|
||||
${extractFunction('normalizeHeroSmsReuseEnabledValue')}
|
||||
@@ -979,8 +978,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||
const inputAutoSkipFailures = { checked: false };
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||
const inputAutoDelayEnabled = { checked: false };
|
||||
const inputAutoDelayMinutes = { value: '30' };
|
||||
const inputAutoStepDelaySeconds = { value: '' };
|
||||
const inputPhoneVerificationEnabled = { checked: true };
|
||||
const inputFreePhoneReuseEnabled = { checked: true };
|
||||
@@ -1072,7 +1069,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||
|
||||
@@ -76,7 +76,6 @@ let autoRunCurrentRun = 2;
|
||||
let autoRunTotalRuns = 3;
|
||||
let autoRunAttemptRun = 4;
|
||||
let autoRunSessionId = 99;
|
||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
||||
const DEFAULT_STATE = {
|
||||
nodeStatuses: {},
|
||||
};
|
||||
@@ -158,9 +157,6 @@ async function getState() {
|
||||
function getPendingAutoRunTimerPlan() {
|
||||
return null;
|
||||
}
|
||||
function isAutoRunScheduledState() {
|
||||
return false;
|
||||
}
|
||||
function getStep8CallbackUrlFromNavigation() { return ''; }
|
||||
function getStep8CallbackUrlFromTabUpdate() { return ''; }
|
||||
function getStep8EffectLabel() { return 'no_effect'; }
|
||||
|
||||
Reference in New Issue
Block a user