fix: keep signup identity submit deferred with operation delay

This commit is contained in:
QLHazyCoder
2026-05-10 06:25:33 +08:00
parent 7d31e93c0e
commit 532e0c01b8
2 changed files with 90 additions and 40 deletions
+22 -22
View File
@@ -1206,18 +1206,18 @@ async function fillSignupEmailAndContinue(email, step) {
} }
log(`步骤 ${step}:邮箱已准备提交,正在前往密码页...`); log(`步骤 ${step}:邮箱已准备提交,正在前往密码页...`);
try { window.setTimeout(async () => {
await sleep(120); try {
throwIfStopped(); throwIfStopped();
await performOperationWithDelay({ stepKey: step === 2 ? 'signup-entry' : 'fill-password', kind: 'submit', label: 'submit-signup-email' }, async () => { await performOperationWithDelay({ stepKey: step === 2 ? 'signup-entry' : 'fill-password', kind: 'submit', label: 'submit-signup-email' }, async () => {
simulateClick(continueButton); simulateClick(continueButton);
}); });
} catch (error) { } catch (error) {
if (!isStopError(error)) { if (!isStopError(error)) {
console.error('[MultiPage:signup-page] signup email submit failed:', error?.message || error); console.error('[MultiPage:signup-page] deferred signup email submit failed:', error?.message || error);
}
} }
throw error; }, 120);
}
return { return {
submitted: true, submitted: true,
@@ -2472,18 +2472,18 @@ async function submitSignupPhoneNumberAndContinue(payload = {}) {
} }
log('步骤 2:手机号已准备提交,正在前往下一页...'); log('步骤 2:手机号已准备提交,正在前往下一页...');
try { window.setTimeout(async () => {
await sleep(120); try {
throwIfStopped(); throwIfStopped();
await performOperationWithDelay({ stepKey: 'signup-phone-entry', kind: 'submit', label: 'submit-signup-phone' }, async () => { await performOperationWithDelay({ stepKey: 'signup-phone-entry', kind: 'submit', label: 'submit-signup-phone' }, async () => {
simulateClick(continueButton); simulateClick(continueButton);
}); });
} catch (error) { } catch (error) {
if (!isStopError(error)) { if (!isStopError(error)) {
console.error('[MultiPage:signup-page] signup phone submit failed:', error?.message || error); console.error('[MultiPage:signup-page] deferred signup phone submit failed:', error?.message || error);
}
} }
throw error; }, 120);
}
return { return {
submitted: true, submitted: true,
+68 -18
View File
@@ -1124,9 +1124,10 @@ return {
assert.equal(result.logs.some(({ message }) => /检测到密码页报错/.test(message)), true); assert.equal(result.logs.some(({ message }) => /检测到密码页报错/.test(message)), true);
}); });
test('fillSignupEmailAndContinue waits for submit operation delay before returning', async () => { test('fillSignupEmailAndContinue reports before deferred submit while submit still waits for operation delay', async () => {
const api = new Function(` const api = new Function(`
const events = []; const events = [];
const scheduled = [];
let releaseSubmitDelay; let releaseSubmitDelay;
const submitDelay = new Promise((resolve) => { releaseSubmitDelay = resolve; }); const submitDelay = new Promise((resolve) => { releaseSubmitDelay = resolve; });
const emailInput = { value: '' }; const emailInput = { value: '' };
@@ -1135,7 +1136,8 @@ const location = { href: 'https://auth.openai.com/u/signup' };
const window = { const window = {
setTimeout(callback, ms) { setTimeout(callback, ms) {
events.push(\`timer:\${ms}\`); events.push(\`timer:\${ms}\`);
return 1; scheduled.push(callback);
return scheduled.length;
}, },
CodexOperationDelay: { CodexOperationDelay: {
async performOperationWithDelay(metadata, operation) { async performOperationWithDelay(metadata, operation) {
@@ -1170,6 +1172,11 @@ ${extractFunction('fillSignupEmailAndContinue')}
return { return {
events, events,
scheduledCount() { return scheduled.length; },
async flushDeferredSubmit() {
if (!scheduled.length) throw new Error('missing deferred submit');
await scheduled[0]();
},
releaseSubmitDelay() { releaseSubmitDelay(); }, releaseSubmitDelay() { releaseSubmitDelay(); },
run() { return fillSignupEmailAndContinue('ada@example.com', 2); }, run() { return fillSignupEmailAndContinue('ada@example.com', 2); },
}; };
@@ -1183,31 +1190,50 @@ return {
}); });
await new Promise((resolve) => setImmediate(resolve)); await new Promise((resolve) => setImmediate(resolve));
assert.equal(settled, false, 'email submit must not return before submit delay resolves'); assert.equal(settled, true, 'email submit must return before deferred submit can navigate');
assert.equal(api.events.includes('delay:submit-signup-email:pending'), true);
assert.equal(api.events.includes('run:resolved'), false);
api.releaseSubmitDelay();
const result = await tracked; const result = await tracked;
assert.equal(result.submitted, true); assert.equal(result.submitted, true);
assert.equal(api.scheduledCount(), 1);
assert.deepStrictEqual(api.events, [ assert.deepStrictEqual(api.events, [
'operation:signup-email:start', 'operation:signup-email:start',
'fill:ada@example.com', 'fill:ada@example.com',
'operation:signup-email:end', 'operation:signup-email:end',
'delay:signup-email:2000', 'delay:signup-email:2000',
'sleep:120', 'timer:120',
'run:resolved',
]);
let flushed = false;
const flush = api.flushDeferredSubmit().then(() => {
flushed = true;
api.events.push('flush:resolved');
});
await new Promise((resolve) => setImmediate(resolve));
assert.equal(api.events.includes('operation:submit-signup-email:start'), true);
assert.equal(api.events.includes('delay:submit-signup-email:pending'), true);
assert.equal(flushed, false, 'deferred email submit callback must wait for submit delay before resolving');
api.releaseSubmitDelay();
await flush;
assert.deepStrictEqual(api.events, [
'operation:signup-email:start',
'fill:ada@example.com',
'operation:signup-email:end',
'delay:signup-email:2000',
'timer:120',
'run:resolved',
'operation:submit-signup-email:start', 'operation:submit-signup-email:start',
'click:Continue', 'click:Continue',
'operation:submit-signup-email:end', 'operation:submit-signup-email:end',
'delay:submit-signup-email:pending', 'delay:submit-signup-email:pending',
'delay:submit-signup-email:2000', 'delay:submit-signup-email:2000',
'run:resolved', 'flush:resolved',
]); ]);
}); });
test('submitSignupPhoneNumberAndContinue waits for submit operation delay before returning', async () => { test('submitSignupPhoneNumberAndContinue reports before deferred submit while submit still waits for operation delay', async () => {
const api = new Function(` const api = new Function(`
const events = []; const events = [];
const scheduled = [];
let releaseSubmitDelay; let releaseSubmitDelay;
const submitDelay = new Promise((resolve) => { releaseSubmitDelay = resolve; }); const submitDelay = new Promise((resolve) => { releaseSubmitDelay = resolve; });
const phoneInput = { value: '' }; const phoneInput = { value: '' };
@@ -1216,7 +1242,8 @@ const location = { href: 'https://auth.openai.com/u/signup/phone' };
const window = { const window = {
setTimeout(callback, ms) { setTimeout(callback, ms) {
events.push(\`timer:\${ms}\`); events.push(\`timer:\${ms}\`);
return 1; scheduled.push(callback);
return scheduled.length;
}, },
CodexOperationDelay: { CodexOperationDelay: {
async performOperationWithDelay(metadata, operation) { async performOperationWithDelay(metadata, operation) {
@@ -1258,6 +1285,11 @@ ${extractFunction('submitSignupPhoneNumberAndContinue')}
return { return {
events, events,
scheduledCount() { return scheduled.length; },
async flushDeferredSubmit() {
if (!scheduled.length) throw new Error('missing deferred submit');
await scheduled[0]();
},
releaseSubmitDelay() { releaseSubmitDelay(); }, releaseSubmitDelay() { releaseSubmitDelay(); },
run() { return submitSignupPhoneNumberAndContinue({ phoneNumber: '+15551234567' }); }, run() { return submitSignupPhoneNumberAndContinue({ phoneNumber: '+15551234567' }); },
}; };
@@ -1271,25 +1303,43 @@ return {
}); });
await new Promise((resolve) => setImmediate(resolve)); await new Promise((resolve) => setImmediate(resolve));
assert.equal(settled, false, 'phone submit must not return before submit delay resolves'); assert.equal(settled, true, 'phone submit must return before deferred submit can navigate');
assert.equal(api.events.includes('delay:submit-signup-phone:pending'), true);
assert.equal(api.events.includes('run:resolved'), false);
api.releaseSubmitDelay();
const result = await tracked; const result = await tracked;
assert.equal(result.submitted, true); assert.equal(result.submitted, true);
assert.equal(api.scheduledCount(), 1);
assert.deepStrictEqual(api.events, [ assert.deepStrictEqual(api.events, [
'operation:signup-phone-number:start', 'operation:signup-phone-number:start',
'fill:5551234567', 'fill:5551234567',
'operation:signup-phone-number:end', 'operation:signup-phone-number:end',
'delay:signup-phone-number:2000', 'delay:signup-phone-number:2000',
'sleep:120', 'timer:120',
'run:resolved',
]);
let flushed = false;
const flush = api.flushDeferredSubmit().then(() => {
flushed = true;
api.events.push('flush:resolved');
});
await new Promise((resolve) => setImmediate(resolve));
assert.equal(api.events.includes('operation:submit-signup-phone:start'), true);
assert.equal(api.events.includes('delay:submit-signup-phone:pending'), true);
assert.equal(flushed, false, 'deferred phone submit callback must wait for submit delay before resolving');
api.releaseSubmitDelay();
await flush;
assert.deepStrictEqual(api.events, [
'operation:signup-phone-number:start',
'fill:5551234567',
'operation:signup-phone-number:end',
'delay:signup-phone-number:2000',
'timer:120',
'run:resolved',
'operation:submit-signup-phone:start', 'operation:submit-signup-phone:start',
'click:Continue', 'click:Continue',
'operation:submit-signup-phone:end', 'operation:submit-signup-phone:end',
'delay:submit-signup-phone:pending', 'delay:submit-signup-phone:pending',
'delay:submit-signup-phone:2000', 'delay:submit-signup-phone:2000',
'run:resolved', 'flush:resolved',
]); ]);
}); });