修复手机号注册绑定邮箱节点执行与资料提交等待

This commit is contained in:
QLHazyCoder
2026-05-16 00:53:14 +08:00
parent 999de8d36b
commit 727d1523dd
5 changed files with 93 additions and 8 deletions
+43 -6
View File
@@ -68,29 +68,56 @@ const NORMAL_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: false,
}) || [];
const NORMAL_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: false,
signupMethod: 'phone',
}) || NORMAL_STEP_DEFINITIONS;
const PLUS_PAYPAL_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'paypal',
}) || NORMAL_STEP_DEFINITIONS;
const PLUS_PAYPAL_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'paypal',
signupMethod: 'phone',
}) || PLUS_PAYPAL_STEP_DEFINITIONS;
const PLUS_GOPAY_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'gopay',
}) || PLUS_PAYPAL_STEP_DEFINITIONS;
const PLUS_GOPAY_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'gopay',
signupMethod: 'phone',
}) || PLUS_GOPAY_STEP_DEFINITIONS;
const PLUS_GPC_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'gpc-helper',
}) || PLUS_GOPAY_STEP_DEFINITIONS;
const PLUS_GPC_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
plusModeEnabled: true,
plusPaymentMethod: 'gpc-helper',
signupMethod: 'phone',
}) || PLUS_GPC_STEP_DEFINITIONS;
const PLUS_STEP_DEFINITIONS = PLUS_PAYPAL_STEP_DEFINITIONS;
const ALL_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getAllSteps?.({
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
}) || [
...NORMAL_STEP_DEFINITIONS,
...NORMAL_PHONE_STEP_DEFINITIONS,
...PLUS_PAYPAL_STEP_DEFINITIONS,
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
...PLUS_GOPAY_STEP_DEFINITIONS,
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
...PLUS_GPC_STEP_DEFINITIONS,
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
];
const STEP_IDS = Array.from(new Set(ALL_STEP_DEFINITIONS
.map((definition) => Number(definition?.id))
@@ -9608,6 +9635,7 @@ const STEP_COMPLETION_SIGNAL_STEP_KEYS = new Set([
'platform-verify',
]);
const STEP_COMPLETION_SIGNAL_TIMEOUTS_BY_STEP_KEY = new Map([
['fill-profile', 150000],
['gopay-subscription-confirm', 1800000],
]);
const AUTO_RUN_PRE_EXECUTION_DELAYS_BY_STEP_KEY = new Map([
@@ -10379,8 +10407,9 @@ async function executeNodeAndWait(nodeId, delayAfter = 2000) {
const latestState = await getState();
await addLog(`自动运行:节点 ${normalizedNodeId} 已执行返回,当前状态为 ${latestState.nodeStatuses?.[normalizedNodeId] || 'pending'},准备继续后续节点。`, 'info');
} else if (doesNodeUseCompletionSignal(normalizedNodeId, executionState)) {
await addLog(`自动运行:节点 ${normalizedNodeId} 已发起,正在等待完成信号(超时 ${AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS / 1000} 秒)。`, 'info');
completionPayload = await executeNodeViaCompletionSignal(normalizedNodeId, AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS);
const completionSignalTimeoutMs = getNodeCompletionSignalTimeoutMs(normalizedNodeId, executionState);
await addLog(`自动运行:节点 ${normalizedNodeId} 已发起,正在等待完成信号(超时 ${Math.round(completionSignalTimeoutMs / 1000)} 秒)。`, 'info');
completionPayload = await executeNodeViaCompletionSignal(normalizedNodeId, completionSignalTimeoutMs);
await addLog(`自动运行:节点 ${normalizedNodeId} 已收到完成信号,准备继续后续节点。`, 'info');
} else {
await executeNode(normalizedNodeId);
@@ -10391,7 +10420,7 @@ async function executeNodeAndWait(nodeId, delayAfter = 2000) {
if (signupTabId) {
await addLog('自动运行:填写资料节点已收到完成信号,正在等待当前页面完成加载并稳定...', 'info');
await waitForTabStableComplete(signupTabId, {
timeoutMs: 30000,
timeoutMs: 120000,
retryDelayMs: 300,
stableMs: 1000,
initialDelayMs: 800,
@@ -12560,23 +12589,31 @@ async function acquireTopLevelAuthChainExecution(step, state = {}) {
}
const normalStepRegistry = buildStepRegistry(NORMAL_STEP_DEFINITIONS);
const normalPhoneStepRegistry = buildStepRegistry(NORMAL_PHONE_STEP_DEFINITIONS);
const plusPayPalStepRegistry = buildStepRegistry(PLUS_PAYPAL_STEP_DEFINITIONS);
const plusPayPalPhoneStepRegistry = buildStepRegistry(PLUS_PAYPAL_PHONE_STEP_DEFINITIONS);
const plusGoPayStepRegistry = buildStepRegistry(PLUS_GOPAY_STEP_DEFINITIONS);
const plusGoPayPhoneStepRegistry = buildStepRegistry(PLUS_GOPAY_PHONE_STEP_DEFINITIONS);
const plusGpcStepRegistry = buildStepRegistry(PLUS_GPC_STEP_DEFINITIONS);
const plusGpcPhoneStepRegistry = buildStepRegistry(PLUS_GPC_PHONE_STEP_DEFINITIONS);
function getStepRegistryForState(state = {}) {
const activeFlowId = String(state?.activeFlowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID;
if (activeFlowId !== DEFAULT_ACTIVE_FLOW_ID) {
throw new Error(`当前尚未注册 flow=${activeFlowId} 的步骤执行器。`);
}
const signupMethod = getSignupMethodForStepDefinitions(state);
if (!isPlusModeState(state)) {
return normalStepRegistry;
return signupMethod === SIGNUP_METHOD_PHONE ? normalPhoneStepRegistry : normalStepRegistry;
}
const paymentMethod = normalizePlusPaymentMethod(state?.plusPaymentMethod);
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
return plusGpcStepRegistry;
return signupMethod === SIGNUP_METHOD_PHONE ? plusGpcPhoneStepRegistry : plusGpcStepRegistry;
}
return paymentMethod === PLUS_PAYMENT_METHOD_GOPAY ? plusGoPayStepRegistry : plusPayPalStepRegistry;
if (paymentMethod === PLUS_PAYMENT_METHOD_GOPAY) {
return signupMethod === SIGNUP_METHOD_PHONE ? plusGoPayPhoneStepRegistry : plusGoPayStepRegistry;
}
return signupMethod === SIGNUP_METHOD_PHONE ? plusPayPalPhoneStepRegistry : plusPayPalStepRegistry;
}
async function requestOAuthUrlFromPanel(state, options = {}) {
+1
View File
@@ -593,6 +593,7 @@
function getContentScriptResponseTimeoutMs(message) {
if (!message || typeof message !== 'object') return 30000;
if (message.type === 'EXECUTE_NODE' && String(message.nodeId || message.payload?.nodeId || '').trim() === 'fill-profile') return 150000;
if (message.type === 'EXECUTE_NODE' && String(message.nodeId || message.payload?.nodeId || '').trim() === 'wait-registration-success') return 75000;
if (message.type === 'POLL_EMAIL') {
const maxAttempts = Math.max(1, Number(message.payload?.maxAttempts) || 1);
+1 -1
View File
@@ -6753,7 +6753,7 @@ function installStep5NavigationCompletionReporter(completeOnce) {
async function waitForStep5SubmitOutcome(options = {}) {
const {
timeoutMs = 45000,
timeoutMs = 120000,
maxAuthRetryRecoveries = 2,
maxSubmitClicks = 3,
retryClickIntervalMs = 3500,
+17 -1
View File
@@ -12,10 +12,26 @@ test('background imports node registry and shared workflow definitions', () => {
assert.match(source, /buildNodeRegistry\(definitions/);
assert.match(source, /PLUS_PAYPAL_STEP_DEFINITIONS/);
assert.match(source, /PLUS_GOPAY_STEP_DEFINITIONS/);
assert.match(source, /NORMAL_PHONE_STEP_DEFINITIONS/);
assert.match(source, /PLUS_PAYPAL_PHONE_STEP_DEFINITIONS/);
assert.match(source, /PLUS_GOPAY_PHONE_STEP_DEFINITIONS/);
assert.match(source, /PLUS_GPC_PHONE_STEP_DEFINITIONS/);
assert.match(source, /plusPayPalStepRegistry/);
assert.match(source, /plusGoPayStepRegistry/);
assert.match(source, /normalizePlusPaymentMethod\(state\?\.plusPaymentMethod\) === PLUS_PAYMENT_METHOD_GOPAY/);
assert.match(source, /normalPhoneStepRegistry/);
assert.match(source, /plusPayPalPhoneStepRegistry/);
assert.match(source, /plusGoPayPhoneStepRegistry/);
assert.match(source, /plusGpcPhoneStepRegistry/);
assert.match(source, /const signupMethod = getSignupMethodForStepDefinitions\(state\);/);
assert.match(source, /signupMethod === SIGNUP_METHOD_PHONE \? normalPhoneStepRegistry : normalStepRegistry/);
assert.match(source, /const paymentMethod = normalizePlusPaymentMethod\(state\?\.plusPaymentMethod\);/);
assert.match(source, /paymentMethod === PLUS_PAYMENT_METHOD_GOPAY/);
assert.match(source, /signupMethod === SIGNUP_METHOD_PHONE \? plusGoPayPhoneStepRegistry : plusGoPayStepRegistry/);
assert.match(source, /signupMethod === SIGNUP_METHOD_PHONE \? plusPayPalPhoneStepRegistry : plusPayPalStepRegistry/);
assert.match(source, /signupMethod === SIGNUP_METHOD_PHONE \? plusGpcPhoneStepRegistry : plusGpcStepRegistry/);
assert.match(source, /activeStepRegistry\.executeNode\(normalizedNodeId,\s*\{/);
assert.match(source, /'bind-email': \(state\) => step8Executor\.executeBindEmail\(state\)/);
assert.match(source, /'fetch-bind-email-code': \(state\) => step8Executor\.executeFetchBindEmailCode\(state\)/);
assert.match(source, /background\/steps\/create-plus-checkout\.js/);
assert.match(source, /background\/steps\/fill-plus-checkout\.js/);
assert.match(source, /background\/steps\/gopay-manual-confirm\.js/);
@@ -121,6 +121,37 @@ test('tab runtime caps per-attempt response timeout to the remaining resilient t
);
});
test('tab runtime gives step 5 profile submit enough response time for slow page transitions', () => {
const source = fs.readFileSync('background/tab-runtime.js', 'utf8');
const globalScope = {};
const api = new Function('self', `${source}; return self.MultiPageBackgroundTabRuntime;`)(globalScope);
const runtime = api.createTabRuntime({
LOG_PREFIX: '[test]',
addLog: async () => {},
chrome: {
tabs: {
get: async () => ({ id: 1, url: 'https://example.com', status: 'complete' }),
query: async () => [],
},
},
getSourceLabel: (sourceName) => sourceName || 'unknown',
getState: async () => ({ tabRegistry: {}, sourceLastUrls: {} }),
matchesSourceUrlFamily: () => false,
setState: async () => {},
throwIfStopped: () => {},
});
assert.equal(
runtime.getContentScriptResponseTimeoutMs({ type: 'EXECUTE_NODE', nodeId: 'fill-profile' }),
150000
);
assert.equal(
runtime.getContentScriptResponseTimeoutMs({ type: 'EXECUTE_NODE', payload: { nodeId: 'fill-profile' } }),
150000
);
});
test('tab runtime waitForTabComplete waits until tab status becomes complete', async () => {
const source = fs.readFileSync('background/tab-runtime.js', 'utf8');
const globalScope = {};