feat: 添加邮箱验证页面处理逻辑,优化步骤 2 跳过密码步骤的逻辑,更新相关测试用例

This commit is contained in:
QLHazyCoder
2026-04-17 03:54:30 +08:00
parent 5a0003af3c
commit 1a5f569d16
8 changed files with 388 additions and 15 deletions
+13
View File
@@ -109,6 +109,19 @@
}
break;
}
case 2:
if (payload.email) {
await setEmailState(payload.email);
}
if (payload.skippedPasswordStep) {
const latestState = await getState();
const step3Status = latestState.stepStatuses?.[3];
if (step3Status !== 'running' && step3Status !== 'completed' && step3Status !== 'manual_completed') {
await setStepStatus(3, 'skipped');
await addLog('步骤 2:提交邮箱后页面直接进入邮箱验证码页,已自动跳过步骤 3。', 'warn');
}
}
break;
case 3:
if (payload.email) await setEmailState(payload.email);
if (payload.signupVerificationRequestedAt) {
+8
View File
@@ -52,6 +52,13 @@
&& /\/create-account\/password(?:[/?#]|$)/i.test(parsed.pathname || '');
}
function isSignupEmailVerificationPageUrl(rawUrl) {
const parsed = parseUrlSafely(rawUrl);
if (!parsed) return false;
return isSignupPageHost(parsed.hostname)
&& /\/email-verification(?:[/?#]|$)/i.test(parsed.pathname || '');
}
function is163MailHost(hostname = '') {
return hostname === 'mail.163.com'
|| hostname.endsWith('.mail.163.com')
@@ -154,6 +161,7 @@
is163MailHost,
isLocalCpaUrl,
isLocalhostOAuthCallbackUrl,
isSignupEmailVerificationPageUrl,
isSignupEntryHost,
isSignupPageHost,
isSignupPasswordPageUrl,
+59 -8
View File
@@ -3,18 +3,16 @@
})(typeof self !== 'undefined' ? self : globalThis, function createSignupFlowHelpersModule() {
function createSignupFlowHelpers(deps = {}) {
const {
addLog,
buildGeneratedAliasEmail,
chrome,
ensureContentScriptReadyOnTab,
ensureHotmailAccountForFlow,
ensureLuckmailPurchaseForFlow,
getTabId,
isGeneratedAliasProvider,
isHotmailProvider,
isLuckmailProvider,
isSignupEmailVerificationPageUrl,
isSignupPasswordPageUrl,
isTabAlive,
reuseOrCreateTab,
sendToContentScriptResilient,
setEmailState,
@@ -60,17 +58,46 @@
return { tabId, result: result || {} };
}
async function ensureSignupPasswordPageReadyInTab(tabId, step = 2, options = {}) {
function resolveSignupPostEmailState(rawUrl) {
if (isSignupPasswordPageUrl(rawUrl)) {
return 'password_page';
}
if (isSignupEmailVerificationPageUrl(rawUrl)) {
return 'verification_page';
}
return '';
}
async function ensureSignupPostEmailPageReadyInTab(tabId, step = 2, options = {}) {
const { skipUrlWait = false } = options;
let landingUrl = '';
let landingState = '';
if (!skipUrlWait) {
const matchedTab = await waitForTabUrlMatch(tabId, (url) => isSignupPasswordPageUrl(url), {
const matchedTab = await waitForTabUrlMatch(tabId, (url) => Boolean(resolveSignupPostEmailState(url)), {
timeoutMs: 45000,
retryDelayMs: 300,
});
if (!matchedTab) {
throw new Error('等待进入密码页超时,请检查邮箱提交后页面是否仍停留在官网或邮箱页。');
throw new Error('等待邮箱提交后的页面跳转超时,请检查页面是否仍停留在邮箱输入页。');
}
landingUrl = matchedTab.url || '';
landingState = resolveSignupPostEmailState(landingUrl);
}
if (!landingState) {
try {
const currentTab = await chrome.tabs.get(tabId);
landingUrl = landingUrl || currentTab?.url || '';
landingState = resolveSignupPostEmailState(landingUrl);
} catch {
landingUrl = landingUrl || '';
}
}
if (!landingState) {
throw new Error(`邮箱提交后未能识别当前页面,既不是密码页也不是邮箱验证码页。URL: ${landingUrl || 'unknown'}`);
}
await ensureContentScriptReadyOnTab('signup-page', tabId, {
@@ -78,9 +105,19 @@
injectSource: 'signup-page',
timeoutMs: 45000,
retryDelayMs: 900,
logMessage: `步骤 ${step}:密码页仍在加载,正在重试连接内容脚本...`,
logMessage: landingState === 'verification_page'
? `步骤 ${step}:邮箱验证码页仍在加载,正在等待页面恢复...`
: `步骤 ${step}:密码页仍在加载,正在重试连接内容脚本...`,
});
if (landingState === 'verification_page') {
return {
ready: true,
state: landingState,
url: landingUrl,
};
}
const result = await sendToContentScriptResilient('signup-page', {
type: 'ENSURE_SIGNUP_PASSWORD_PAGE_READY',
step,
@@ -96,7 +133,20 @@
throw new Error(result.error);
}
return result || {};
return {
...(result || {}),
ready: true,
state: landingState,
url: landingUrl,
};
}
async function ensureSignupPasswordPageReadyInTab(tabId, step = 2, options = {}) {
const result = await ensureSignupPostEmailPageReadyInTab(tabId, step, options);
if (result.state !== 'password_page') {
throw new Error(`当前页面不是密码页,实际落地为 ${result.state || 'unknown'}。URL: ${result.url || 'unknown'}`);
}
return result;
}
async function resolveSignupEmailForFlow(state) {
@@ -128,6 +178,7 @@
return {
ensureSignupEntryPageReady,
ensureSignupPostEmailPageReadyInTab,
ensureSignupPasswordPageReadyInTab,
openSignupEntryTab,
resolveSignupEmailForFlow,
+10 -4
View File
@@ -8,7 +8,7 @@
completeStepFromBackground,
ensureContentScriptReadyOnTab,
ensureSignupEntryPageReady,
ensureSignupPasswordPageReadyInTab,
ensureSignupPostEmailPageReadyInTab,
getTabId,
isTabAlive,
resolveSignupEmailForFlow,
@@ -50,13 +50,19 @@
}
if (!step2Result?.alreadyOnPasswordPage) {
await addLog(`步骤 2:邮箱 ${resolvedEmail} 已提交,正在等待进入密码页...`);
await addLog(`步骤 2:邮箱 ${resolvedEmail} 已提交,正在等待页面加载并确认下一步入口...`);
}
await ensureSignupPasswordPageReadyInTab(signupTabId, 2, {
const landingResult = await ensureSignupPostEmailPageReadyInTab(signupTabId, 2, {
skipUrlWait: Boolean(step2Result?.alreadyOnPasswordPage),
});
await completeStepFromBackground(2, {});
await completeStepFromBackground(2, {
email: resolvedEmail,
nextSignupState: landingResult?.state || 'password_page',
nextSignupUrl: landingResult?.url || step2Result?.url || '',
skippedPasswordStep: landingResult?.state === 'verification_page',
});
}
return { executeStep2 };