feat: 增强2925邮箱处理逻辑,添加邮件预清空机制,更新相关测试用例
This commit is contained in:
@@ -237,6 +237,58 @@
|
|||||||
return requestedAt;
|
return requestedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldPreclear2925Mailbox(step, mail) {
|
||||||
|
return mail?.provider === '2925' && (step === 4 || step === 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function clear2925MailboxBeforePolling(step, mail, options = {}) {
|
||||||
|
if (!shouldPreclear2925Mailbox(step, mail)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throwIfStopped();
|
||||||
|
await addLog(`步骤 ${step}:开始刷新 2925 邮箱前先清空全部邮件,避免读取旧验证码邮件。`, 'warn');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const responseTimeoutMs = await getResponseTimeoutMsForStep(
|
||||||
|
step,
|
||||||
|
options,
|
||||||
|
15000,
|
||||||
|
'清空 2925 邮箱历史邮件'
|
||||||
|
);
|
||||||
|
const result = await sendToMailContentScriptResilient(
|
||||||
|
mail,
|
||||||
|
{
|
||||||
|
type: 'DELETE_ALL_EMAILS',
|
||||||
|
step,
|
||||||
|
source: 'background',
|
||||||
|
payload: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeoutMs: responseTimeoutMs,
|
||||||
|
responseTimeoutMs,
|
||||||
|
maxRecoveryAttempts: 2,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
throw new Error(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.deleted === false) {
|
||||||
|
await addLog(`步骤 ${step}:未能确认 2925 邮箱已清空,将继续刷新等待新邮件。`, 'warn');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await addLog(`步骤 ${step}:2925 邮箱已预先清空,开始刷新等待新邮件。`, 'info');
|
||||||
|
} catch (err) {
|
||||||
|
if (isStopError(err)) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
await addLog(`步骤 ${step}:预清空 2925 邮箱失败,将继续刷新等待新邮件:${err.message}`, 'warn');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function triggerPostSuccessMailboxCleanup(step, mail) {
|
function triggerPostSuccessMailboxCleanup(step, mail) {
|
||||||
if (mail?.provider !== '2925') {
|
if (mail?.provider !== '2925') {
|
||||||
return;
|
return;
|
||||||
@@ -573,6 +625,8 @@
|
|||||||
return nextFilterAfterTimestamp;
|
return nextFilterAfterTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await clear2925MailboxBeforePolling(step, mail, options);
|
||||||
|
|
||||||
if (requestFreshCodeFirst) {
|
if (requestFreshCodeFirst) {
|
||||||
if (remainingAutomaticResendCount <= 0) {
|
if (remainingAutomaticResendCount <= 0) {
|
||||||
await addLog(`步骤 ${step}:当前自动重新发送验证码次数为 0,将直接使用当前时间窗口轮询邮箱。`, 'info');
|
await addLog(`步骤 ${step}:当前自动重新发送验证码次数为 0,将直接使用当前时间窗口轮询邮箱。`, 'info');
|
||||||
|
|||||||
+17
-3
@@ -99,8 +99,11 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.type === 'DELETE_ALL_EMAILS') {
|
if (message.type === 'DELETE_ALL_EMAILS') {
|
||||||
Promise.resolve(deleteAllMailboxEmails(message.step)).catch(() => {});
|
Promise.resolve(deleteAllMailboxEmails(message.step)).then((deleted) => {
|
||||||
sendResponse({ ok: true });
|
sendResponse({ ok: true, deleted });
|
||||||
|
}).catch((err) => {
|
||||||
|
sendResponse({ ok: false, error: err?.message || String(err || '删除邮件失败') });
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +481,10 @@ async function openMailAndDeleteAfterRead(item, step) {
|
|||||||
async function deleteAllMailboxEmails(step) {
|
async function deleteAllMailboxEmails(step) {
|
||||||
try {
|
try {
|
||||||
await returnToInbox();
|
await returnToInbox();
|
||||||
|
const initialItems = findMailItems();
|
||||||
|
if (initialItems.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const selectAllControl = findSelectAllControl();
|
const selectAllControl = findSelectAllControl();
|
||||||
if (!selectAllControl) {
|
if (!selectAllControl) {
|
||||||
@@ -495,8 +502,15 @@ async function deleteAllMailboxEmails(step) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
simulateClick(deleteButton);
|
simulateClick(deleteButton);
|
||||||
await sleepRandom(200, 500);
|
for (let attempt = 0; attempt < 20; attempt += 1) {
|
||||||
|
await sleep(250);
|
||||||
|
if (findMailItems().length === 0) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await sleepRandom(200, 500);
|
||||||
|
return findMailItems().length === 0;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(MAIL2925_PREFIX, `Step ${step}: delete-all cleanup failed:`, err?.message || err);
|
console.warn(MAIL2925_PREFIX, `Step ${step}: delete-all cleanup failed:`, err?.message || err);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -431,12 +431,17 @@ test('deleteAllMailboxEmails selects all messages and clicks delete', async () =
|
|||||||
const calls = [];
|
const calls = [];
|
||||||
const selectAllControl = { kind: 'select-all' };
|
const selectAllControl = { kind: 'select-all' };
|
||||||
const deleteButton = { kind: 'delete' };
|
const deleteButton = { kind: 'delete' };
|
||||||
|
let mailboxCleared = false;
|
||||||
|
|
||||||
async function returnToInbox() {
|
async function returnToInbox() {
|
||||||
calls.push('inbox');
|
calls.push('inbox');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findMailItems() {
|
||||||
|
return mailboxCleared ? [] : [{ id: 'mail-1' }];
|
||||||
|
}
|
||||||
|
|
||||||
function findSelectAllControl() {
|
function findSelectAllControl() {
|
||||||
return selectAllControl;
|
return selectAllControl;
|
||||||
}
|
}
|
||||||
@@ -456,11 +461,13 @@ function simulateClick(node) {
|
|||||||
}
|
}
|
||||||
if (node === deleteButton) {
|
if (node === deleteButton) {
|
||||||
calls.push('delete');
|
calls.push('delete');
|
||||||
|
mailboxCleared = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Error('unexpected node');
|
throw new Error('unexpected node');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sleep() {}
|
||||||
async function sleepRandom() {}
|
async function sleepRandom() {}
|
||||||
|
|
||||||
const console = { warn() {} };
|
const console = { warn() {} };
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ test('verification flow runs beforeSubmit hook before filling the code', async (
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verification flow triggers 2925 mailbox cleanup only after code submission succeeds', async () => {
|
test('verification flow clears 2925 mailbox before polling and after successful login code submission', async () => {
|
||||||
const mailMessages = [];
|
const mailMessages = [];
|
||||||
|
|
||||||
const helpers = api.createVerificationFlowHelpers({
|
const helpers = api.createVerificationFlowHelpers({
|
||||||
@@ -169,7 +169,73 @@ test('verification flow triggers 2925 mailbox cleanup only after code submission
|
|||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
assert.deepStrictEqual(mailMessages, ['POLL_EMAIL', 'DELETE_ALL_EMAILS']);
|
assert.deepStrictEqual(mailMessages, ['DELETE_ALL_EMAILS', 'POLL_EMAIL', 'DELETE_ALL_EMAILS']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verification flow clears 2925 mailbox before polling and after successful signup code submission', async () => {
|
||||||
|
const mailMessages = [];
|
||||||
|
|
||||||
|
const helpers = api.createVerificationFlowHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
chrome: {
|
||||||
|
tabs: {
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
|
||||||
|
completeStepFromBackground: async () => {},
|
||||||
|
confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
|
||||||
|
getHotmailVerificationPollConfig: () => ({}),
|
||||||
|
getHotmailVerificationRequestTimestamp: () => 0,
|
||||||
|
getState: async () => ({}),
|
||||||
|
getTabId: async () => 1,
|
||||||
|
HOTMAIL_PROVIDER: 'hotmail-api',
|
||||||
|
isStopError: () => false,
|
||||||
|
LUCKMAIL_PROVIDER: 'luckmail-api',
|
||||||
|
MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
|
||||||
|
MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
|
||||||
|
pollCloudflareTempEmailVerificationCode: async () => ({}),
|
||||||
|
pollHotmailVerificationCode: async () => ({}),
|
||||||
|
pollLuckmailVerificationCode: async () => ({}),
|
||||||
|
sendToContentScript: async (_source, message) => {
|
||||||
|
if (message.type === 'FILL_CODE') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (message.type === 'RESEND_VERIFICATION_CODE') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
sendToMailContentScriptResilient: async (_mail, message) => {
|
||||||
|
mailMessages.push(message.type);
|
||||||
|
if (message.type === 'POLL_EMAIL') {
|
||||||
|
return { code: '654321', emailTimestamp: 123 };
|
||||||
|
}
|
||||||
|
return { ok: true, deleted: true };
|
||||||
|
},
|
||||||
|
setState: async () => {},
|
||||||
|
setStepStatus: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
VERIFICATION_POLL_MAX_ROUNDS: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
await helpers.resolveVerificationStep(
|
||||||
|
4,
|
||||||
|
{
|
||||||
|
email: 'user@example.com',
|
||||||
|
mailProvider: '2925',
|
||||||
|
lastSignupCode: null,
|
||||||
|
},
|
||||||
|
{ provider: '2925', label: '2925 邮箱' },
|
||||||
|
{
|
||||||
|
requestFreshCodeFirst: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
|
assert.deepStrictEqual(mailMessages, ['DELETE_ALL_EMAILS', 'POLL_EMAIL', 'DELETE_ALL_EMAILS']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verification flow treats add-phone after login code submit as fatal instead of completing step 8', async () => {
|
test('verification flow treats add-phone after login code submit as fatal instead of completing step 8', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user