fix: finalize HeroSMS reuse after full flow success

This commit is contained in:
zhangkun
2026-04-28 14:15:07 +08:00
parent 127fd1c653
commit 5c804fad6e
9 changed files with 294 additions and 36 deletions
+17
View File
@@ -560,6 +560,7 @@ const DEFAULT_STATE = {
currentLuckmailMailCursor: null, currentLuckmailMailCursor: null,
currentPhoneActivation: null, currentPhoneActivation: null,
reusablePhoneActivation: null, reusablePhoneActivation: null,
pendingPhoneActivationConfirmation: null,
autoRunning: false, // 当前是否处于自动运行中。 autoRunning: false, // 当前是否处于自动运行中。
autoRunPhase: 'idle', // 当前自动运行阶段。 autoRunPhase: 'idle', // 当前自动运行阶段。
autoRunCurrentRun: 0, // 自动运行当前执行到第几轮。 autoRunCurrentRun: 0, // 自动运行当前执行到第几轮。
@@ -5031,6 +5032,13 @@ async function finalizeIcloudAliasAfterSuccessfulFlow(state) {
} }
} }
async function finalizePhoneActivationAfterSuccessfulFlow(state) {
if (typeof phoneVerificationHelpers?.finalizePendingPhoneActivationConfirmation !== 'function') {
return null;
}
return phoneVerificationHelpers.finalizePendingPhoneActivationConfirmation(state);
}
// ============================================================ // ============================================================
// Tab Registry // Tab Registry
// ============================================================ // ============================================================
@@ -5766,6 +5774,7 @@ function getDownstreamStateResets(step, state = {}) {
loginVerificationRequestedAt: null, loginVerificationRequestedAt: null,
oauthFlowDeadlineAt: null, oauthFlowDeadlineAt: null,
oauthFlowDeadlineSourceUrl: null, oauthFlowDeadlineSourceUrl: null,
pendingPhoneActivationConfirmation: null,
lastSignupCode: null, lastSignupCode: null,
lastLoginCode: null, lastLoginCode: null,
localhostUrl: null, localhostUrl: null,
@@ -5780,6 +5789,7 @@ function getDownstreamStateResets(step, state = {}) {
loginVerificationRequestedAt: null, loginVerificationRequestedAt: null,
oauthFlowDeadlineAt: null, oauthFlowDeadlineAt: null,
oauthFlowDeadlineSourceUrl: null, oauthFlowDeadlineSourceUrl: null,
pendingPhoneActivationConfirmation: null,
lastSignupCode: null, lastSignupCode: null,
lastLoginCode: null, lastLoginCode: null,
localhostUrl: null, localhostUrl: null,
@@ -5793,6 +5803,7 @@ function getDownstreamStateResets(step, state = {}) {
loginVerificationRequestedAt: null, loginVerificationRequestedAt: null,
oauthFlowDeadlineAt: null, oauthFlowDeadlineAt: null,
oauthFlowDeadlineSourceUrl: null, oauthFlowDeadlineSourceUrl: null,
pendingPhoneActivationConfirmation: null,
lastSignupCode: null, lastSignupCode: null,
lastLoginCode: null, lastLoginCode: null,
localhostUrl: null, localhostUrl: null,
@@ -5815,11 +5826,13 @@ function getDownstreamStateResets(step, state = {}) {
loginVerificationRequestedAt: null, loginVerificationRequestedAt: null,
oauthFlowDeadlineAt: null, oauthFlowDeadlineAt: null,
oauthFlowDeadlineSourceUrl: null, oauthFlowDeadlineSourceUrl: null,
pendingPhoneActivationConfirmation: null,
localhostUrl: null, localhostUrl: null,
}; };
} }
if (step === 9) { if (step === 9) {
return { return {
pendingPhoneActivationConfirmation: null,
plusReturnUrl: '', plusReturnUrl: '',
localhostUrl: null, localhostUrl: null,
}; };
@@ -5830,11 +5843,13 @@ function getDownstreamStateResets(step, state = {}) {
loginVerificationRequestedAt: null, loginVerificationRequestedAt: null,
oauthFlowDeadlineAt: null, oauthFlowDeadlineAt: null,
oauthFlowDeadlineSourceUrl: null, oauthFlowDeadlineSourceUrl: null,
pendingPhoneActivationConfirmation: null,
localhostUrl: null, localhostUrl: null,
}; };
} }
if (stepKey === 'confirm-oauth') { if (stepKey === 'confirm-oauth') {
return { return {
pendingPhoneActivationConfirmation: null,
localhostUrl: null, localhostUrl: null,
}; };
} }
@@ -6676,6 +6691,7 @@ async function handleStepData(step, payload) {
excludeLocalhostCallbacks: true, excludeLocalhostCallbacks: true,
}); });
} }
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
await finalizeIcloudAliasAfterSuccessfulFlow(latestState); await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === ( const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === (
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string' typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
@@ -8528,6 +8544,7 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
executeStepViaCompletionSignal, executeStepViaCompletionSignal,
exportSettingsBundle, exportSettingsBundle,
fetchGeneratedEmail, fetchGeneratedEmail,
finalizePhoneActivationAfterSuccessfulFlow,
finalizeStep3Completion: async () => { finalizeStep3Completion: async () => {
const currentState = await getState(); const currentState = await getState();
const signupTabId = await getTabId('signup-page'); const signupTabId = await getTabId('signup-page');
+1
View File
@@ -391,6 +391,7 @@
inbucketMailbox: prevState.inbucketMailbox, inbucketMailbox: prevState.inbucketMailbox,
cloudflareDomain: prevState.cloudflareDomain, cloudflareDomain: prevState.cloudflareDomain,
cloudflareDomains: prevState.cloudflareDomains, cloudflareDomains: prevState.cloudflareDomains,
reusablePhoneActivation: prevState.reusablePhoneActivation,
autoRunRoundSummaries: serializeAutoRunRoundSummaries(totalRuns, roundSummaries), autoRunRoundSummaries: serializeAutoRunRoundSummaries(totalRuns, roundSummaries),
autoRunSessionId: sessionId, autoRunSessionId: sessionId,
tabRegistry: {}, tabRegistry: {},
+4
View File
@@ -32,6 +32,7 @@
executeStepViaCompletionSignal, executeStepViaCompletionSignal,
exportSettingsBundle, exportSettingsBundle,
fetchGeneratedEmail, fetchGeneratedEmail,
finalizePhoneActivationAfterSuccessfulFlow,
finalizeStep3Completion, finalizeStep3Completion,
finalizeIcloudAliasAfterSuccessfulFlow, finalizeIcloudAliasAfterSuccessfulFlow,
findHotmailAccount, findHotmailAccount,
@@ -202,6 +203,9 @@
excludeLocalhostCallbacks: true, excludeLocalhostCallbacks: true,
}); });
} }
if (typeof finalizePhoneActivationAfterSuccessfulFlow === 'function') {
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
}
await finalizeIcloudAliasAfterSuccessfulFlow(latestState); await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
} }
+39 -6
View File
@@ -21,6 +21,7 @@
const PHONE_ACTIVATION_STATE_KEY = 'currentPhoneActivation'; const PHONE_ACTIVATION_STATE_KEY = 'currentPhoneActivation';
const REUSABLE_PHONE_ACTIVATION_STATE_KEY = 'reusablePhoneActivation'; const REUSABLE_PHONE_ACTIVATION_STATE_KEY = 'reusablePhoneActivation';
const PENDING_PHONE_ACTIVATION_CONFIRMATION_STATE_KEY = 'pendingPhoneActivationConfirmation';
const DEFAULT_PHONE_POLL_INTERVAL_MS = 5000; const DEFAULT_PHONE_POLL_INTERVAL_MS = 5000;
const DEFAULT_PHONE_POLL_TIMEOUT_MS = 180000; const DEFAULT_PHONE_POLL_TIMEOUT_MS = 180000;
const DEFAULT_PHONE_REQUEST_TIMEOUT_MS = 20000; const DEFAULT_PHONE_REQUEST_TIMEOUT_MS = 20000;
@@ -634,18 +635,16 @@
await persistReusableActivation(null); await persistReusableActivation(null);
} }
async function incrementCurrentActivationUseCount(activation) { function incrementActivationUseCount(activation) {
const normalizedActivation = normalizeActivation(activation); const normalizedActivation = normalizeActivation(activation);
if (!normalizedActivation) { if (!normalizedActivation) {
return null; return null;
} }
const nextActivation = { return {
...normalizedActivation, ...normalizedActivation,
successfulUses: Math.min(normalizedActivation.successfulUses + 1, normalizedActivation.maxUses), successfulUses: Math.min(normalizedActivation.successfulUses + 1, normalizedActivation.maxUses),
}; };
await persistCurrentActivation(nextActivation);
return nextActivation;
} }
async function acquirePhoneActivation(state = {}) { async function acquirePhoneActivation(state = {}) {
@@ -694,6 +693,35 @@
await persistReusableActivation(normalizedActivation); await persistReusableActivation(normalizedActivation);
} }
async function persistPendingPhoneActivationConfirmation(activation) {
await setState({
[PENDING_PHONE_ACTIVATION_CONFIRMATION_STATE_KEY]: activation || null,
});
}
async function clearPendingPhoneActivationConfirmation() {
await persistPendingPhoneActivationConfirmation(null);
}
async function finalizePendingPhoneActivationConfirmation(stateOverride = null) {
const state = stateOverride || await getState();
const pendingActivation = normalizeActivation(state[PENDING_PHONE_ACTIVATION_CONFIRMATION_STATE_KEY]);
if (!pendingActivation) {
return null;
}
const committedActivation = incrementActivationUseCount(pendingActivation);
if (!committedActivation) {
await clearPendingPhoneActivationConfirmation();
await clearReusableActivation();
return null;
}
await syncReusableActivationAfterUse(committedActivation);
await clearPendingPhoneActivationConfirmation();
return committedActivation;
}
async function waitForPhoneCodeOrRotateNumber(tabId, state, activation) { async function waitForPhoneCodeOrRotateNumber(tabId, state, activation) {
let currentActivation = normalizeActivation(activation); let currentActivation = normalizeActivation(activation);
if (!currentActivation) { if (!currentActivation) {
@@ -781,6 +809,9 @@
} }
if (pageState?.addPhonePage) { if (pageState?.addPhonePage) {
if (normalizeActivation(state[PENDING_PHONE_ACTIVATION_CONFIRMATION_STATE_KEY])) {
await clearPendingPhoneActivationConfirmation();
}
if (activation) { if (activation) {
await cancelPhoneActivation(state, activation); await cancelPhoneActivation(state, activation);
await clearCurrentActivation(); await clearCurrentActivation();
@@ -871,12 +902,13 @@
continue; continue;
} }
activation = await incrementCurrentActivationUseCount(activation);
try { try {
await completePhoneActivation(state, activation); await completePhoneActivation(state, activation);
await syncReusableActivationAfterUse(activation); await persistReusableActivation(activation);
await persistPendingPhoneActivationConfirmation(activation);
} catch (activationStatusError) { } catch (activationStatusError) {
await clearReusableActivation(); await clearReusableActivation();
await clearPendingPhoneActivationConfirmation();
await addLog( await addLog(
`Step 9: phone verification succeeded, but HeroSMS setStatus(3) failed. The next flow will request a new number. ${activationStatusError.message}`, `Step 9: phone verification succeeded, but HeroSMS setStatus(3) failed. The next flow will request a new number. ${activationStatusError.message}`,
'warn' 'warn'
@@ -903,6 +935,7 @@
return { return {
completePhoneVerificationFlow, completePhoneVerificationFlow,
finalizePendingPhoneActivationConfirmation,
normalizeActivation, normalizeActivation,
pollPhoneActivationCode, pollPhoneActivationCode,
reactivatePhoneActivation, reactivatePhoneActivation,
@@ -114,6 +114,12 @@ let currentState = {
inbucketMailbox: '', inbucketMailbox: '',
cloudflareDomain: '', cloudflareDomain: '',
cloudflareDomains: [], cloudflareDomains: [],
reusablePhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
successfulUses: 1,
maxUses: 3,
},
tabRegistry: {}, tabRegistry: {},
sourceLastUrls: {}, sourceLastUrls: {},
}; };
@@ -329,6 +335,16 @@ return {
assert.strictEqual(snapshot.currentState.autoRunSessionId, 0, 'session id should be cleared after completion'); assert.strictEqual(snapshot.currentState.autoRunSessionId, 0, 'session id should be cleared after completion');
assert.strictEqual(snapshot.currentState.gmailBaseEmail, 'demo@gmail.com', 'gmail base email should survive fresh-attempt reset'); assert.strictEqual(snapshot.currentState.gmailBaseEmail, 'demo@gmail.com', 'gmail base email should survive fresh-attempt reset');
assert.strictEqual(snapshot.currentState.mail2925BaseEmail, 'demo@2925.com', '2925 base email should survive fresh-attempt reset'); assert.strictEqual(snapshot.currentState.mail2925BaseEmail, 'demo@2925.com', '2925 base email should survive fresh-attempt reset');
assert.deepStrictEqual(
snapshot.currentState.reusablePhoneActivation,
{
activationId: '123456',
phoneNumber: '66959916439',
successfulUses: 1,
maxUses: 3,
},
'reusable phone activation should survive fresh-attempt reset'
);
console.log('auto-run fresh attempt reset tests passed'); console.log('auto-run fresh attempt reset tests passed');
})().catch((error) => { })().catch((error) => {
+1
View File
@@ -713,6 +713,7 @@ function broadcastDataUpdate() {}
function isLocalhostOAuthCallbackUrl() { function isLocalhostOAuthCallbackUrl() {
return true; return true;
} }
async function finalizePhoneActivationAfterSuccessfulFlow() {}
async function finalizeIcloudAliasAfterSuccessfulFlow() {} async function finalizeIcloudAliasAfterSuccessfulFlow() {}
${bundle} ${bundle}
@@ -12,6 +12,7 @@ function createRouter(overrides = {}) {
stepStatuses: [], stepStatuses: [],
emailStates: [], emailStates: [],
finalizePayloads: [], finalizePayloads: [],
phoneFinalizations: [],
notifyCompletions: [], notifyCompletions: [],
notifyErrors: [], notifyErrors: [],
securityBlocks: [], securityBlocks: [],
@@ -49,6 +50,9 @@ function createRouter(overrides = {}) {
executeStepViaCompletionSignal: async () => {}, executeStepViaCompletionSignal: async () => {},
exportSettingsBundle: async () => ({}), exportSettingsBundle: async () => ({}),
fetchGeneratedEmail: async () => '', fetchGeneratedEmail: async () => '',
finalizePhoneActivationAfterSuccessfulFlow: overrides.finalizePhoneActivationAfterSuccessfulFlow || (async (state) => {
events.phoneFinalizations.push(state);
}),
finalizeStep3Completion: overrides.finalizeStep3Completion || (async (payload) => { finalizeStep3Completion: overrides.finalizeStep3Completion || (async (payload) => {
events.finalizePayloads.push(payload); events.finalizePayloads.push(payload);
}), }),
@@ -262,6 +266,34 @@ test('message router finalizes step 3 before marking it completed', async () =>
assert.deepStrictEqual(response, { ok: true }); assert.deepStrictEqual(response, { ok: true });
}); });
test('message router finalizes pending phone activation on platform verify success', async () => {
const state = {
stepStatuses: { 10: 'pending' },
reusablePhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
successfulUses: 0,
maxUses: 3,
},
pendingPhoneActivationConfirmation: {
activationId: '123456',
phoneNumber: '66959916439',
successfulUses: 0,
maxUses: 3,
},
};
const { router, events } = createRouter({
state,
getStepDefinitionForState: (step) => ({ id: step, key: step === 10 ? 'platform-verify' : '' }),
});
await router.handleStepData(10, {
localhostUrl: 'http://localhost:1455/auth/callback?code=ok',
});
assert.deepStrictEqual(events.phoneFinalizations, [state]);
});
test('message router marks step 3 failed when post-submit finalize fails', async () => { test('message router marks step 3 failed when post-submit finalize fails', async () => {
const { router, events } = createRouter({ const { router, events } = createRouter({
finalizeStep3Completion: async () => { finalizeStep3Completion: async () => {
+183 -30
View File
@@ -260,18 +260,6 @@ test('phone verification helper uses HeroSMS getStatusV2 after acquiring a numbe
statusAction: 'getStatusV2', statusAction: 'getStatusV2',
}, },
}, },
{
currentPhoneActivation: {
activationId: '654321',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 1,
maxUses: 3,
statusAction: 'getStatusV2',
},
},
{ {
reusablePhoneActivation: { reusablePhoneActivation: {
activationId: '654321', activationId: '654321',
@@ -279,7 +267,19 @@ test('phone verification helper uses HeroSMS getStatusV2 after acquiring a numbe
provider: 'hero-sms', provider: 'hero-sms',
serviceCode: 'dr', serviceCode: 'dr',
countryId: 16, countryId: 16,
successfulUses: 1, successfulUses: 0,
maxUses: 3,
statusAction: 'getStatusV2',
},
},
{
pendingPhoneActivationConfirmation: {
activationId: '654321',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 0,
maxUses: 3, maxUses: 3,
statusAction: 'getStatusV2', statusAction: 'getStatusV2',
}, },
@@ -413,17 +413,6 @@ test('phone verification helper completes add-phone flow, clears current activat
maxUses: 3, maxUses: 3,
}, },
}, },
{
currentPhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 1,
maxUses: 3,
},
},
{ {
reusablePhoneActivation: { reusablePhoneActivation: {
activationId: '123456', activationId: '123456',
@@ -431,7 +420,18 @@ test('phone verification helper completes add-phone flow, clears current activat
provider: 'hero-sms', provider: 'hero-sms',
serviceCode: 'dr', serviceCode: 'dr',
countryId: 52, countryId: 52,
successfulUses: 1, successfulUses: 0,
maxUses: 3,
},
},
{
pendingPhoneActivationConfirmation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3, maxUses: 3,
}, },
}, },
@@ -519,6 +519,7 @@ test('phone verification helper still succeeds when HeroSMS setStatus(3) fails a
}); });
assert.deepStrictEqual(currentState.currentPhoneActivation, null); assert.deepStrictEqual(currentState.currentPhoneActivation, null);
assert.deepStrictEqual(currentState.reusablePhoneActivation, null); assert.deepStrictEqual(currentState.reusablePhoneActivation, null);
assert.deepStrictEqual(currentState.pendingPhoneActivationConfirmation, null);
const actions = requests.map((url) => url.searchParams.get('action')); const actions = requests.map((url) => url.searchParams.get('action'));
assert.deepStrictEqual(actions, ['getNumber', 'getStatus', 'setStatus']); assert.deepStrictEqual(actions, ['getNumber', 'getStatus', 'setStatus']);
}); });
@@ -843,12 +844,21 @@ test('phone verification helper replaces the number when code submission returns
provider: 'hero-sms', provider: 'hero-sms',
serviceCode: 'dr', serviceCode: 'dr',
countryId: 52, countryId: 52,
successfulUses: 1, successfulUses: 0,
maxUses: 3,
});
assert.deepStrictEqual(currentState.pendingPhoneActivationConfirmation, {
activationId: '222222',
phoneNumber: '66950000002',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3, maxUses: 3,
}); });
}); });
test('phone verification helper reuses the same number up to three successful registrations', async () => { test('phone verification helper defers maxUses accounting for reused activations until the full flow succeeds', async () => {
const requests = []; const requests = [];
let currentState = { let currentState = {
heroSmsApiKey: 'demo-key', heroSmsApiKey: 'demo-key',
@@ -934,10 +944,27 @@ test('phone verification helper reuses the same number up to three successful re
}); });
assert.equal(requests[0].searchParams.get('action'), 'reactivate'); assert.equal(requests[0].searchParams.get('action'), 'reactivate');
assert.equal(requests[0].searchParams.get('id'), '123456'); assert.equal(requests[0].searchParams.get('id'), '123456');
assert.deepStrictEqual(currentState.reusablePhoneActivation, null); assert.deepStrictEqual(currentState.reusablePhoneActivation, {
activationId: '222333',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 2,
maxUses: 3,
});
assert.deepStrictEqual(currentState.pendingPhoneActivationConfirmation, {
activationId: '222333',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 2,
maxUses: 3,
});
}); });
test('phone verification helper keeps maxUses behavior for reused V2 activations', async () => { test('phone verification helper defers maxUses accounting for reused V2 activations until the full flow succeeds', async () => {
const requests = []; const requests = [];
let currentState = { let currentState = {
heroSmsApiKey: 'demo-key', heroSmsApiKey: 'demo-key',
@@ -1026,5 +1053,131 @@ test('phone verification helper keeps maxUses behavior for reused V2 activations
}); });
const actions = requests.map((url) => url.searchParams.get('action')); const actions = requests.map((url) => url.searchParams.get('action'));
assert.deepStrictEqual(actions, ['reactivate', 'getStatusV2', 'setStatus']); assert.deepStrictEqual(actions, ['reactivate', 'getStatusV2', 'setStatus']);
assert.deepStrictEqual(currentState.reusablePhoneActivation, null); assert.deepStrictEqual(currentState.reusablePhoneActivation, {
activationId: '222333',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 2,
maxUses: 3,
statusAction: 'getStatusV2',
});
assert.deepStrictEqual(currentState.pendingPhoneActivationConfirmation, {
activationId: '222333',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 2,
maxUses: 3,
statusAction: 'getStatusV2',
});
});
test('phone verification helper finalizes pending phone activation confirmation after the full flow succeeds', async () => {
let currentState = {
reusablePhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3,
},
pendingPhoneActivationConfirmation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3,
},
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async () => ({}),
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const committedActivation = await helpers.finalizePendingPhoneActivationConfirmation();
assert.deepStrictEqual(committedActivation, {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 1,
maxUses: 3,
});
assert.deepStrictEqual(currentState.reusablePhoneActivation, {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 1,
maxUses: 3,
});
assert.equal(currentState.pendingPhoneActivationConfirmation, null);
});
test('phone verification helper clears reusable activation when final success exhausts maxUses', async () => {
let currentState = {
reusablePhoneActivation: {
activationId: '222333',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 2,
maxUses: 3,
statusAction: 'getStatusV2',
},
pendingPhoneActivationConfirmation: {
activationId: '222333',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 2,
maxUses: 3,
statusAction: 'getStatusV2',
},
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async () => ({}),
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const committedActivation = await helpers.finalizePendingPhoneActivationConfirmation();
assert.deepStrictEqual(committedActivation, {
activationId: '222333',
phoneNumber: '447911123456',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
successfulUses: 3,
maxUses: 3,
statusAction: 'getStatusV2',
});
assert.equal(currentState.reusablePhoneActivation, null);
assert.equal(currentState.pendingPhoneActivationConfirmation, null);
}); });
@@ -114,6 +114,7 @@ function broadcastDataUpdate() {}
async function addLog(message) { async function addLog(message) {
logMessages.push(message); logMessages.push(message);
} }
async function finalizePhoneActivationAfterSuccessfulFlow() {}
async function finalizeIcloudAliasAfterSuccessfulFlow() {} async function finalizeIcloudAliasAfterSuccessfulFlow() {}
function matchesSourceUrlFamily() { function matchesSourceUrlFamily() {
return false; return false;