From 0a17d95f447fa837af75e1fe3578069071a141a5 Mon Sep 17 00:00:00 2001 From: EmptyDust <1422492074@qq.com> Date: Sat, 2 May 2026 11:44:36 +0800 Subject: [PATCH] Fix delayed combined signup profile detection --- content/signup-page.js | 16 ++- tests/step4-split-code-submit.test.js | 197 ++++++++++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) diff --git a/content/signup-page.js b/content/signup-page.js index df8e3e8..7ea1cb7 100644 --- a/content/signup-page.js +++ b/content/signup-page.js @@ -2573,7 +2573,8 @@ async function fillVerificationCode(step, payload) { await waitForLoginVerificationPageReady(); } - const combinedSignupProfilePage = step === 4 && isCombinedSignupVerificationProfilePage(); + const combinedSignupProfilePage = step === 4 + && await waitForCombinedSignupVerificationProfilePage(); if (combinedSignupProfilePage) { if (!signupProfile || !signupProfile.firstName || !signupProfile.lastName) { throw new Error('当前注册验证码页面要求同时填写资料,但未提供姓名或生日数据。'); @@ -3404,6 +3405,19 @@ function isCombinedSignupVerificationProfilePage() { ); } +async function waitForCombinedSignupVerificationProfilePage(timeout = 2500) { + const start = Date.now(); + + while (Date.now() - start < timeout) { + if (isCombinedSignupVerificationProfilePage()) { + return true; + } + await sleep(100); + } + + return isCombinedSignupVerificationProfilePage(); +} + async function step5_fillNameBirthday(payload) { const { firstName, lastName, age, year, month, day, prefillOnly = false } = payload; if (!firstName || !lastName) throw new Error('未提供姓名数据。'); diff --git a/tests/step4-split-code-submit.test.js b/tests/step4-split-code-submit.test.js index 007b5ed..73bc6d8 100644 --- a/tests/step4-split-code-submit.test.js +++ b/tests/step4-split-code-submit.test.js @@ -134,6 +134,7 @@ ${extractFunction('waitForVerificationSubmitButton')} ${extractFunction('waitForVerificationCodeTarget')} ${extractFunction('waitForSplitVerificationInputsFilled')} ${extractFunction('isCombinedSignupVerificationProfilePage')} +${extractFunction('waitForCombinedSignupVerificationProfilePage')} ${extractFunction('isSignupProfilePageUrl')} ${extractFunction('isLikelyLoggedInChatgptHomeUrl')} ${extractFunction('getStep4PostVerificationState')} @@ -203,6 +204,7 @@ const document = { ${extractFunction('isVerificationPageStillVisible')} ${extractFunction('isCombinedSignupVerificationProfilePage')} +${extractFunction('waitForCombinedSignupVerificationProfilePage')} ${extractFunction('isSignupProfilePageUrl')} ${extractFunction('isLikelyLoggedInChatgptHomeUrl')} ${extractFunction('getStep4PostVerificationState')} @@ -375,6 +377,7 @@ ${extractFunction('getVerificationSubmitButtonForTarget')} ${extractFunction('waitForVerificationSubmitButton')} ${extractFunction('waitForVerificationCodeTarget')} ${extractFunction('waitForSplitVerificationInputsFilled')} +${extractFunction('waitForCombinedSignupVerificationProfilePage')} ${extractFunction('step5_fillNameBirthday')} ${extractFunction('fillVerificationCode')} @@ -417,3 +420,197 @@ return { assert.equal(snapshot.submitClicked, true); assert.deepStrictEqual(snapshot.clicks, ['Continue']); }); + +test('fillVerificationCode waits for delayed combined profile fields before prefilling', async () => { + const api = new Function(` +const logs = []; +const clicks = []; +let submitClicked = false; +let nameQueryCount = 0; +const VERIFICATION_CODE_INPUT_SELECTOR = 'input[name="code"]'; +const location = { + href: 'https://auth.openai.com/email-verification/register', + pathname: '/email-verification/register', +}; +function KeyboardEvent(type, init = {}) { + this.type = type; + Object.assign(this, init); +} + +const nameInput = { + value: '', + disabled: false, + getAttribute(name) { + if (name === 'name') return 'name'; + if (name === 'autocomplete') return 'name'; + return ''; + }, +}; +const ageInput = { + value: '', + disabled: false, + getAttribute(name) { + if (name === 'name') return 'age'; + return ''; + }, +}; +const codeInput = { + value: '', + disabled: false, + form: null, + getAttribute(name) { + if (name === 'maxlength') return '6'; + if (name === 'aria-disabled') return 'false'; + if (name === 'name') return 'code'; + return ''; + }, + closest() { return null; }, + focus() {}, + dispatchEvent() {}, +}; +const submitBtn = { + tagName: 'BUTTON', + textContent: 'Continue', + disabled: false, + getAttribute(name) { + if (name === 'type') return 'submit'; + if (name === 'aria-disabled') return 'false'; + return ''; + }, + click() { + submitClicked = true; + }, +}; + +const document = { + querySelector(selector) { + switch (selector) { + case 'input[name="name"], input[autocomplete="name"]': + nameQueryCount += 1; + return nameQueryCount >= 3 ? nameInput : null; + case 'input[name="name"], input[autocomplete="name"], input[name="birthday"], input[name="age"], [role="spinbutton"][data-type="year"]': + nameQueryCount += 1; + return nameQueryCount >= 3 ? nameInput : null; + case 'input[name="name"], input[placeholder*="全名"], input[autocomplete="name"]': + return nameInput; + case 'input[name="age"]': + return nameQueryCount >= 3 ? ageInput : null; + case '[role="spinbutton"][data-type="year"]': + case '[role="spinbutton"][data-type="month"]': + case '[role="spinbutton"][data-type="day"]': + case 'input[name="birthday"]': + return null; + case 'form[action*="email-verification/register" i]': + case 'form[action*="email-verification" i]': + return { action: '/email-verification/register' }; + case VERIFICATION_CODE_INPUT_SELECTOR: + return codeInput; + case 'button[type="submit"]': + return submitBtn; + default: + return null; + } + }, + querySelectorAll(selector) { + if (selector === 'input[maxlength="1"]') return []; + if (selector === 'button[type="submit"], input[type="submit"]') return [submitBtn]; + if (selector === 'button, [role="button"], input[type="button"], input[type="submit"]') return [submitBtn]; + if (selector === 'input[name="allCheckboxes"][type="checkbox"]') return []; + if (selector === 'input[type="checkbox"]') return []; + return []; + }, + execCommand() {}, +}; + +function throwIfStopped() {} +function log(message, level = 'info') { logs.push({ message, level }); } +async function waitForLoginVerificationPageReady() {} +function is405MethodNotAllowedPage() { return false; } +async function handle405ResendError() {} +function fillInput(el, value) { + el.value = value; +} +async function sleep() {} +function isStep5Ready() { return false; } +function isStep8Ready() { return false; } +function isAddPhonePageReady() { return false; } +function isVisibleElement(el) { return Boolean(el) && !el.disabled; } +function isActionEnabled(el) { return Boolean(el) && !el.disabled; } +function getActionText(el) { return el.textContent || ''; } +async function humanPause() {} +function simulateClick(el) { el.click(); clicks.push(el.textContent); } +function getCurrentAuthRetryPageState() { return null; } +function isPhoneVerificationPageReady() { return false; } +function findResendVerificationCodeTrigger() { return null; } +function isEmailVerificationPage() { return true; } +function getPageTextSnapshot() { return 'Create your account Enter the verification code we just sent Tell us about you'; } +function findBirthdayReactAriaSelect() { return null; } +async function setReactAriaBirthdaySelect() {} +async function waitForElement(selector) { + if (/input\\[name=\"name\"\\]/.test(selector)) { + return nameInput; + } + throw new Error('unexpected selector ' + selector); +} +async function waitForElementByText() { return submitBtn; } +function isStep5AllConsentText() { return false; } +function findStep5AllConsentCheckbox() { return null; } +function isStep5CheckboxChecked() { return false; } +async function waitForVerificationSubmitOutcome() { + return { success: true, skipProfileStep: true }; +} + +${extractFunction('getStep5DirectCompletionPayload')} +${extractFunction('isVerificationPageStillVisible')} +${extractFunction('isCombinedSignupVerificationProfilePage')} +${extractFunction('waitForCombinedSignupVerificationProfilePage')} +${extractFunction('isSignupProfilePageUrl')} +${extractFunction('isLikelyLoggedInChatgptHomeUrl')} +${extractFunction('getStep4PostVerificationState')} +${extractFunction('getVisibleSplitVerificationInputs')} +${extractFunction('getVerificationCodeTarget')} +${extractFunction('getVerificationSubmitButtonForTarget')} +${extractFunction('waitForVerificationSubmitButton')} +${extractFunction('waitForVerificationCodeTarget')} +${extractFunction('waitForSplitVerificationInputsFilled')} +${extractFunction('step5_fillNameBirthday')} +${extractFunction('fillVerificationCode')} + +return { + run() { + return fillVerificationCode(4, { + code: '123456', + signupProfile: { + firstName: 'Ada', + lastName: 'Lovelace', + age: 22, + }, + }); + }, + snapshot() { + return { + nameValue: nameInput.value, + ageValue: ageInput.value, + codeValue: codeInput.value, + submitClicked, + clicks, + nameQueryCount, + }; + }, +}; +`)(); + + const result = await api.run(); + const snapshot = api.snapshot(); + + assert.deepStrictEqual(result, { + success: true, + skipProfileStep: true, + skipProfileStepReason: 'combined_verification_profile', + }); + assert.equal(snapshot.nameValue, 'Ada Lovelace'); + assert.equal(snapshot.ageValue, '22'); + assert.equal(snapshot.codeValue, '123456'); + assert.equal(snapshot.submitClicked, true); + assert.equal(snapshot.nameQueryCount >= 3, true); +});