feat: 更新手机号输入框逻辑,确保手动输入值在执行步骤前被保存,避免被旧状态覆盖
This commit is contained in:
@@ -296,6 +296,66 @@ test('step 7 forwards phone login identity payload when account identifier is ph
|
||||
]);
|
||||
});
|
||||
|
||||
test('step 7 can start from a manually filled signup phone without completed step 2 or step 3 state', async () => {
|
||||
const source = fs.readFileSync('background/steps/oauth-login.js', 'utf8');
|
||||
const globalScope = {};
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep7;`)(globalScope);
|
||||
|
||||
const events = {
|
||||
payloads: [],
|
||||
completions: [],
|
||||
};
|
||||
|
||||
const executor = api.createStep7Executor({
|
||||
addLog: async () => {},
|
||||
completeStepFromBackground: async (step, payload) => {
|
||||
events.completions.push({ step, payload });
|
||||
},
|
||||
getErrorMessage: (error) => error?.message || String(error || ''),
|
||||
getLoginAuthStateLabel: (state) => state || 'unknown',
|
||||
getState: async () => ({
|
||||
accountIdentifierType: 'phone',
|
||||
accountIdentifier: '+447780579093',
|
||||
signupPhoneNumber: '+447780579093',
|
||||
stepStatuses: { 2: 'pending', 3: 'pending' },
|
||||
}),
|
||||
isStep6RecoverableResult: (result) => result?.step6Outcome === 'recoverable',
|
||||
isStep6SuccessResult: (result) => result?.step6Outcome === 'success',
|
||||
refreshOAuthUrlBeforeStep6: async () => 'https://oauth.example/latest',
|
||||
reuseOrCreateTab: async () => {},
|
||||
sendToContentScriptResilient: async (_sourceName, message) => {
|
||||
events.payloads.push(message.payload);
|
||||
return {
|
||||
step6Outcome: 'success',
|
||||
state: 'phone_verification_page',
|
||||
loginVerificationRequestedAt: 987654,
|
||||
};
|
||||
},
|
||||
STEP6_MAX_ATTEMPTS: 3,
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
await executor.executeStep7({
|
||||
accountIdentifierType: 'phone',
|
||||
accountIdentifier: '+447780579093',
|
||||
signupPhoneNumber: '+447780579093',
|
||||
stepStatuses: { 2: 'pending', 3: 'pending' },
|
||||
});
|
||||
|
||||
assert.equal(events.payloads[0].loginIdentifierType, 'phone');
|
||||
assert.equal(events.payloads[0].phoneNumber, '+447780579093');
|
||||
assert.equal(events.payloads[0].email, '');
|
||||
assert.equal(events.payloads[0].password, '');
|
||||
assert.deepStrictEqual(events.completions, [
|
||||
{
|
||||
step: 7,
|
||||
payload: {
|
||||
loginVerificationRequestedAt: 987654,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('step 7 stops immediately when management secret is missing', async () => {
|
||||
const source = fs.readFileSync('background/steps/oauth-login.js', 'utf8');
|
||||
const globalScope = {};
|
||||
|
||||
@@ -282,10 +282,14 @@ let clearedTimer = null;
|
||||
let settingsSaveInFlight = false;
|
||||
let settingsDirty = false;
|
||||
let settingsSaveRevision = 0;
|
||||
let phonePersistCalls = 0;
|
||||
const saveCalls = [];
|
||||
function clearTimeout(value) {
|
||||
clearedTimer = value;
|
||||
}
|
||||
async function persistSignupPhoneInputForAction() {
|
||||
phonePersistCalls += 1;
|
||||
}
|
||||
function updateSaveButtonState() {}
|
||||
function collectSettingsPayload() {
|
||||
return { luckmailApiKey: 'autofilled-key' };
|
||||
@@ -308,7 +312,7 @@ ${bundle}
|
||||
return {
|
||||
persistCurrentSettingsForAction,
|
||||
getSnapshot() {
|
||||
return { clearedTimer, saveCalls };
|
||||
return { clearedTimer, phonePersistCalls, saveCalls };
|
||||
},
|
||||
};
|
||||
`)();
|
||||
@@ -317,5 +321,6 @@ return {
|
||||
const snapshot = api.getSnapshot();
|
||||
|
||||
assert.equal(snapshot.clearedTimer, 123);
|
||||
assert.equal(snapshot.phonePersistCalls, 1);
|
||||
assert.deepStrictEqual(snapshot.saveCalls, [{ luckmailApiKey: 'autofilled-key' }]);
|
||||
});
|
||||
|
||||
@@ -136,10 +136,57 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
|
||||
|
||||
test('sidepanel source wires runtime signup phone field to background sync messages', () => {
|
||||
assert.match(sidepanelSource, /function getRuntimeSignupPhoneValue\(state = latestState\)/);
|
||||
assert.match(sidepanelSource, /function shouldPreserveSignupPhoneInputValue\(stateSignupPhone = ''\)/);
|
||||
assert.match(sidepanelSource, /function syncSignupPhoneInputFromState\(state = latestState\)/);
|
||||
assert.match(sidepanelSource, /async function persistSignupPhoneInputForAction\(\)/);
|
||||
assert.match(sidepanelSource, /type:\s*'SET_SIGNUP_PHONE_STATE'/);
|
||||
assert.match(sidepanelSource, /type:\s*'SAVE_SIGNUP_PHONE'/);
|
||||
assert.match(sidepanelSource, /final \? 'SAVE_SIGNUP_PHONE' : 'SET_SIGNUP_PHONE_STATE'/);
|
||||
assert.match(sidepanelSource, /message\.payload\.signupPhoneNumber !== undefined/);
|
||||
assert.match(sidepanelSource, /await persistSignupPhoneInputForAction\(\);\s*await saveSettings/);
|
||||
assert.match(sidepanelSource, /async function handleSkipStep\(step\)[\s\S]*await persistCurrentSettingsForAction\(\);/);
|
||||
assert.match(sidepanelSource, /inputSignupPhone\.addEventListener\('input'[\s\S]*signupPhoneInputDirty = true/);
|
||||
});
|
||||
|
||||
test('runtime signup phone sync preserves active manual input until it is saved', () => {
|
||||
const api = new Function(`
|
||||
let latestState = { signupMethod: 'phone', phoneVerificationEnabled: true, signupPhoneNumber: '+441111111111' };
|
||||
let signupPhoneInputDirty = true;
|
||||
let signupPhoneInputFocused = true;
|
||||
const inputSignupPhone = { value: '+442222222222' };
|
||||
const rowSignupPhone = { style: { display: 'none' } };
|
||||
const inputPhoneVerificationEnabled = { checked: true };
|
||||
const document = { activeElement: inputSignupPhone };
|
||||
function getSelectedSignupMethod() { return 'phone'; }
|
||||
${extractFunction('normalizeSignupMethod')}
|
||||
${extractFunction('getRuntimeSignupPhoneValue')}
|
||||
${extractFunction('getSignupPhoneInputValue')}
|
||||
${extractFunction('shouldPreserveSignupPhoneInputValue')}
|
||||
${extractFunction('syncSignupPhoneInputFromState')}
|
||||
return {
|
||||
inputSignupPhone,
|
||||
rowSignupPhone,
|
||||
syncSignupPhoneInputFromState,
|
||||
getDirty: () => signupPhoneInputDirty,
|
||||
setFocused: (value) => { signupPhoneInputFocused = Boolean(value); document.activeElement = value ? inputSignupPhone : null; },
|
||||
};
|
||||
`)();
|
||||
|
||||
api.syncSignupPhoneInputFromState({
|
||||
signupMethod: 'phone',
|
||||
phoneVerificationEnabled: true,
|
||||
signupPhoneNumber: '+441111111111',
|
||||
});
|
||||
assert.equal(api.inputSignupPhone.value, '+442222222222');
|
||||
assert.equal(api.rowSignupPhone.style.display, '');
|
||||
assert.equal(api.getDirty(), true);
|
||||
|
||||
api.setFocused(false);
|
||||
api.syncSignupPhoneInputFromState({
|
||||
signupMethod: 'phone',
|
||||
phoneVerificationEnabled: true,
|
||||
signupPhoneNumber: '+441111111111',
|
||||
});
|
||||
assert.equal(api.inputSignupPhone.value, '+441111111111');
|
||||
});
|
||||
|
||||
test('hero sms country helpers keep empty summary state and expose removable order handling', () => {
|
||||
|
||||
Reference in New Issue
Block a user