feat: 添加邮箱验证页面处理逻辑,优化步骤 2 跳过密码步骤的逻辑,更新相关测试用例
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||
const globalScope = {};
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||
|
||||
function createRouter(overrides = {}) {
|
||||
const events = {
|
||||
logs: [],
|
||||
stepStatuses: [],
|
||||
emailStates: [],
|
||||
};
|
||||
|
||||
const router = api.createMessageRouter({
|
||||
addLog: async (message, level) => {
|
||||
events.logs.push({ message, level });
|
||||
},
|
||||
appendAccountRunRecord: async () => null,
|
||||
batchUpdateLuckmailPurchases: async () => {},
|
||||
buildLocalhostCleanupPrefix: () => '',
|
||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||
buildPersistentSettingsPayload: () => ({}),
|
||||
broadcastDataUpdate: () => {},
|
||||
cancelScheduledAutoRun: async () => {},
|
||||
checkIcloudSession: async () => {},
|
||||
clearAutoRunTimerAlarm: async () => {},
|
||||
clearLuckmailRuntimeState: async () => {},
|
||||
clearStopRequest: () => {},
|
||||
closeLocalhostCallbackTabs: async () => {},
|
||||
closeTabsByUrlPrefix: async () => {},
|
||||
deleteHotmailAccount: async () => {},
|
||||
deleteHotmailAccounts: async () => {},
|
||||
deleteIcloudAlias: async () => {},
|
||||
deleteUsedIcloudAliases: async () => {},
|
||||
disableUsedLuckmailPurchases: async () => {},
|
||||
doesStepUseCompletionSignal: () => false,
|
||||
ensureManualInteractionAllowed: async () => ({}),
|
||||
executeStep: async () => {},
|
||||
executeStepViaCompletionSignal: async () => {},
|
||||
exportSettingsBundle: async () => ({}),
|
||||
fetchGeneratedEmail: async () => '',
|
||||
finalizeIcloudAliasAfterSuccessfulFlow: async () => {},
|
||||
findHotmailAccount: async () => null,
|
||||
flushCommand: async () => {},
|
||||
getCurrentLuckmailPurchase: () => null,
|
||||
getPendingAutoRunTimerPlan: () => null,
|
||||
getSourceLabel: () => '',
|
||||
getState: async () => overrides.state || { stepStatuses: { 3: 'pending' } },
|
||||
getStopRequested: () => false,
|
||||
handleAutoRunLoopUnhandledError: async () => {},
|
||||
importSettingsBundle: async () => {},
|
||||
invalidateDownstreamAfterStepRestart: async () => {},
|
||||
isAutoRunLockedState: () => false,
|
||||
isHotmailProvider: () => false,
|
||||
isLocalhostOAuthCallbackUrl: () => true,
|
||||
isLuckmailProvider: () => false,
|
||||
isStopError: () => false,
|
||||
launchAutoRunTimerPlan: async () => {},
|
||||
listIcloudAliases: async () => [],
|
||||
listLuckmailPurchasesForManagement: async () => [],
|
||||
normalizeHotmailAccounts: (items) => items,
|
||||
normalizeRunCount: (value) => value,
|
||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
|
||||
notifyStepComplete: () => {},
|
||||
notifyStepError: () => {},
|
||||
patchHotmailAccount: async () => {},
|
||||
registerTab: async () => {},
|
||||
requestStop: async () => {},
|
||||
resetState: async () => {},
|
||||
resumeAutoRun: async () => {},
|
||||
scheduleAutoRun: async () => {},
|
||||
selectLuckmailPurchase: async () => {},
|
||||
setCurrentHotmailAccount: async () => {},
|
||||
setEmailState: async (email) => {
|
||||
events.emailStates.push(email);
|
||||
},
|
||||
setEmailStateSilently: async () => {},
|
||||
setIcloudAliasPreservedState: async () => {},
|
||||
setIcloudAliasUsedState: async () => {},
|
||||
setLuckmailPurchaseDisabledState: async () => {},
|
||||
setLuckmailPurchasePreservedState: async () => {},
|
||||
setLuckmailPurchaseUsedState: async () => {},
|
||||
setPersistentSettings: async () => {},
|
||||
setState: async () => {},
|
||||
setStepStatus: async (step, status) => {
|
||||
events.stepStatuses.push({ step, status });
|
||||
},
|
||||
skipAutoRunCountdown: async () => false,
|
||||
skipStep: async () => {},
|
||||
startAutoRunLoop: async () => {},
|
||||
syncHotmailAccounts: async () => {},
|
||||
testHotmailAccountMailAccess: async () => {},
|
||||
upsertHotmailAccount: async () => {},
|
||||
verifyHotmailAccount: async () => {},
|
||||
});
|
||||
|
||||
return { router, events };
|
||||
}
|
||||
|
||||
test('message router skips step 3 when step 2 lands on verification page', async () => {
|
||||
const { router, events } = createRouter({
|
||||
state: { stepStatuses: { 3: 'pending' } },
|
||||
});
|
||||
|
||||
await router.handleStepData(2, {
|
||||
email: 'user@example.com',
|
||||
skippedPasswordStep: true,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(events.emailStates, ['user@example.com']);
|
||||
assert.deepStrictEqual(events.stepStatuses, [{ step: 3, status: 'skipped' }]);
|
||||
assert.equal(events.logs[0]?.message, '步骤 2:提交邮箱后页面直接进入邮箱验证码页,已自动跳过步骤 3。');
|
||||
});
|
||||
|
||||
test('message router does not overwrite a completed step 3 when step 2 is replayed', async () => {
|
||||
const { router, events } = createRouter({
|
||||
state: { stepStatuses: { 3: 'completed' } },
|
||||
});
|
||||
|
||||
await router.handleStepData(2, {
|
||||
skippedPasswordStep: true,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(events.stepStatuses, []);
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const step2Source = fs.readFileSync('background/steps/submit-signup-email.js', 'utf8');
|
||||
const step2GlobalScope = {};
|
||||
const step2Api = new Function('self', `${step2Source}; return self.MultiPageBackgroundStep2;`)(step2GlobalScope);
|
||||
|
||||
const signupFlowSource = fs.readFileSync('background/signup-flow-helpers.js', 'utf8');
|
||||
const signupFlowGlobalScope = {};
|
||||
const signupFlowApi = new Function('self', `${signupFlowSource}; return self.MultiPageSignupFlowHelpers;`)(signupFlowGlobalScope);
|
||||
|
||||
test('step 2 completes with password step skipped when landing on email verification page', async () => {
|
||||
const completedPayloads = [];
|
||||
|
||||
const executor = step2Api.createStep2Executor({
|
||||
addLog: async () => {},
|
||||
chrome: { tabs: { update: async () => {} } },
|
||||
completeStepFromBackground: async (step, payload) => {
|
||||
completedPayloads.push({ step, payload });
|
||||
},
|
||||
ensureContentScriptReadyOnTab: async () => {},
|
||||
ensureSignupEntryPageReady: async () => ({ tabId: 11 }),
|
||||
ensureSignupPostEmailPageReadyInTab: async () => ({
|
||||
state: 'verification_page',
|
||||
url: 'https://auth.openai.com/email-verification',
|
||||
}),
|
||||
getTabId: async () => 11,
|
||||
isTabAlive: async () => true,
|
||||
resolveSignupEmailForFlow: async () => 'user@example.com',
|
||||
sendToContentScriptResilient: async () => ({ submitted: true }),
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ email: 'user@example.com' });
|
||||
|
||||
assert.deepStrictEqual(completedPayloads, [
|
||||
{
|
||||
step: 2,
|
||||
payload: {
|
||||
email: 'user@example.com',
|
||||
nextSignupState: 'verification_page',
|
||||
nextSignupUrl: 'https://auth.openai.com/email-verification',
|
||||
skippedPasswordStep: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('step 2 keeps password flow when landing on password page', async () => {
|
||||
const completedPayloads = [];
|
||||
|
||||
const executor = step2Api.createStep2Executor({
|
||||
addLog: async () => {},
|
||||
chrome: { tabs: { update: async () => {} } },
|
||||
completeStepFromBackground: async (step, payload) => {
|
||||
completedPayloads.push({ step, payload });
|
||||
},
|
||||
ensureContentScriptReadyOnTab: async () => {},
|
||||
ensureSignupEntryPageReady: async () => ({ tabId: 12 }),
|
||||
ensureSignupPostEmailPageReadyInTab: async () => ({
|
||||
state: 'password_page',
|
||||
url: 'https://auth.openai.com/create-account/password',
|
||||
}),
|
||||
getTabId: async () => 12,
|
||||
isTabAlive: async () => true,
|
||||
resolveSignupEmailForFlow: async () => 'user@example.com',
|
||||
sendToContentScriptResilient: async () => ({ submitted: true }),
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ email: 'user@example.com' });
|
||||
|
||||
assert.deepStrictEqual(completedPayloads, [
|
||||
{
|
||||
step: 2,
|
||||
payload: {
|
||||
email: 'user@example.com',
|
||||
nextSignupState: 'password_page',
|
||||
nextSignupUrl: 'https://auth.openai.com/create-account/password',
|
||||
skippedPasswordStep: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('signup flow helper recognizes email verification page as post-email landing page', async () => {
|
||||
let ensureCalls = 0;
|
||||
let passwordReadyChecks = 0;
|
||||
|
||||
const helpers = signupFlowApi.createSignupFlowHelpers({
|
||||
buildGeneratedAliasEmail: () => '',
|
||||
chrome: {
|
||||
tabs: {
|
||||
get: async () => ({
|
||||
id: 21,
|
||||
url: 'https://auth.openai.com/email-verification',
|
||||
}),
|
||||
},
|
||||
},
|
||||
ensureContentScriptReadyOnTab: async () => {
|
||||
ensureCalls += 1;
|
||||
},
|
||||
ensureHotmailAccountForFlow: async () => ({}),
|
||||
ensureLuckmailPurchaseForFlow: async () => ({}),
|
||||
isGeneratedAliasProvider: () => false,
|
||||
isHotmailProvider: () => false,
|
||||
isLuckmailProvider: () => false,
|
||||
isSignupEmailVerificationPageUrl: (url) => /\/email-verification(?:[/?#]|$)/i.test(url || ''),
|
||||
isSignupPasswordPageUrl: (url) => /\/create-account\/password(?:[/?#]|$)/i.test(url || ''),
|
||||
reuseOrCreateTab: async () => 21,
|
||||
sendToContentScriptResilient: async () => {
|
||||
passwordReadyChecks += 1;
|
||||
return {};
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => ({
|
||||
id: 21,
|
||||
url: 'https://auth.openai.com/email-verification',
|
||||
}),
|
||||
});
|
||||
|
||||
const result = await helpers.ensureSignupPostEmailPageReadyInTab(21, 2);
|
||||
|
||||
assert.deepStrictEqual(result, {
|
||||
ready: true,
|
||||
state: 'verification_page',
|
||||
url: 'https://auth.openai.com/email-verification',
|
||||
});
|
||||
assert.equal(ensureCalls, 1);
|
||||
assert.equal(passwordReadyChecks, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user