From d6819727247a0442a6a82b5330bd2f104ad1be2c Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Fri, 15 May 2026 01:17:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B5=84=E6=96=99=E9=A1=B5?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=87=8D=E8=AF=95=E5=88=A4=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/signup-page.js | 63 +++++++++++++++++++-- tests/step5-direct-complete.test.js | 85 +++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/content/signup-page.js b/content/signup-page.js index faf7cd5..8307c34 100644 --- a/content/signup-page.js +++ b/content/signup-page.js @@ -6544,10 +6544,65 @@ async function waitForStep5SubmitButton(timeout = 5000) { } function isStep5SubmitButtonClickable(button) { - return Boolean(button) - && isVisibleElement(button) - && !button.disabled - && button.getAttribute?.('aria-disabled') !== 'true'; + if ( + !button + || !isVisibleElement(button) + || button.disabled + || button.getAttribute?.('aria-disabled') === 'true' + ) { + return false; + } + + const ariaBusy = String(button.getAttribute?.('aria-busy') || '').trim().toLowerCase(); + if (ariaBusy === 'true') { + return false; + } + + const pendingAttr = [ + button.getAttribute?.('data-loading'), + button.getAttribute?.('data-pending'), + button.getAttribute?.('data-submitting'), + button.getAttribute?.('data-state'), + ] + .map((value) => String(value || '').trim().toLowerCase()) + .filter(Boolean) + .join(' '); + if (/\b(?:true|loading|pending|submitting|busy)\b/.test(pendingAttr)) { + return false; + } + + const pendingAncestor = button.closest?.([ + '[aria-busy="true"]', + '[data-loading="true"]', + '[data-pending="true"]', + '[data-submitting="true"]', + '[data-state="loading"]', + '[data-state="pending"]', + '[data-state="submitting"]', + ].join(', ')); + if (pendingAncestor) { + return false; + } + + let style = null; + try { + style = typeof window !== 'undefined' && window.getComputedStyle + ? window.getComputedStyle(button) + : null; + } catch { + style = null; + } + + if (style?.pointerEvents === 'none') { + return false; + } + + const opacity = Number.parseFloat(style?.opacity || ''); + if (Number.isFinite(opacity) && opacity < 0.8) { + return false; + } + + return true; } function isStep5ProfileStillVisible() { diff --git a/tests/step5-direct-complete.test.js b/tests/step5-direct-complete.test.js index 953b2be..d561dcd 100644 --- a/tests/step5-direct-complete.test.js +++ b/tests/step5-direct-complete.test.js @@ -814,6 +814,91 @@ return { assert.equal(snapshot.logs.some(({ message }) => /仍停留在资料页,正在重新点击/.test(message)), true); }); +test('step 5 waits instead of retrying while profile submit is pending', async () => { + const api = new Function(` +const realDateNow = Date.now; +let now = 0; +const clicks = []; +const completeButton = { + tagName: 'BUTTON', + type: 'submit', + textContent: 'Complete account creation', + hidden: false, + disabled: false, + getAttribute(name) { + if (name === 'aria-disabled') return 'false'; + return ''; + }, + closest() { + return null; + }, +}; +const location = { href: 'https://auth.openai.com/u/signup/profile' }; +const document = { + querySelector(selector) { + if (selector === 'button[type="submit"], input[type="submit"]') return completeButton; + return null; + }, + querySelectorAll(selector) { + if (selector === 'button, [role="button"], input[type="button"], input[type="submit"]') return [completeButton]; + return []; + }, +}; +const window = { + getComputedStyle() { + return { opacity: '0.5', pointerEvents: 'auto' }; + }, +}; + +Date.now = () => now; +function throwIfStopped() {} +function log() {} +async function sleep(ms = 0) { now += ms || 250; } +async function humanPause() {} +function simulateClick(el) { clicks.push(el?.textContent || 'clicked'); } +function isVisibleElement(el) { return Boolean(el) && !el.hidden; } +function isActionEnabled(el) { return Boolean(el) && !el.disabled && el.getAttribute?.('aria-disabled') !== 'true'; } +function getActionText(el) { return el?.textContent || ''; } +function getSignupAuthRetryPathPatterns() { return []; } +function getAuthTimeoutErrorPageState() { return null; } +async function recoverCurrentAuthRetryPage() { throw new Error('should not recover retry page'); } +function createSignupUserAlreadyExistsError() { return new Error('user already exists'); } +function createAuthMaxCheckAttemptsError() { return new Error('max_check_attempts'); } +function getStep5ErrorText() { return ''; } +function isStep5Ready() { return true; } +function isLikelyLoggedInChatgptHomeUrl() { return false; } +function isOAuthConsentPage() { return false; } +function isAddPhonePageReady() { return false; } + +${extractFunction('isSignupProfilePageUrl')} +${getStep5OutcomeBundle()} + +return { + run() { + return waitForStep5SubmitOutcome({ timeoutMs: 4000, retryClickIntervalMs: 3500 }); + }, + snapshot() { + return { clicks, now }; + }, + restore() { + Date.now = realDateNow; + }, +}; +`)(); + + try { + await assert.rejects( + () => api.run(), + /已点击提交 1\/3 次/ + ); + const snapshot = api.snapshot(); + assert.deepStrictEqual(snapshot.clicks, []); + assert.ok(snapshot.now >= 4000); + } finally { + api.restore(); + } +}); + test('step 5 recovers auth retry page after profile submit', async () => { const api = new Function(` let retryVisible = true;