fix: finalize HeroSMS reuse after full flow success
This commit is contained in:
@@ -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');
|
||||||
|
|||||||
@@ -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: {},
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user