fix(chatgpt-review): retry finding the send button instead of racing its render - #657
Merged
Merged
Conversation
…its render Follow-up to PR #656: the user correctly pushed back on my initial diagnosis that live-testing failures against big/long conversations were purely a self-inflicted dangling-CDP-connection artifact. Testing properly (isolating "pre-existing" from "big page", and using the real production selector- fallback discipline instead of a hardcoded selector index) found the actual production code works fine on big pages -- but surfaced a real, separate, previously-undetected bug: insertNatively() resolves as soon as its in-page evaluate() call returns, which is BEFORE React has necessarily re-rendered in response to it. Confirmed live against the real ChatGPT composer: the send button's own selector showed 0 matches on the very next synchronous DOM query, and only 1 match after yielding a render tick (requestAnimationFrame). fillAndSend's single, immediate, no-retry check for the send button was silently falling through to composer.press('Enter') on this timing race, not because the button was missing. Extracted a shared submit(page, composer) helper (used by both fillAndSend and the stall-recovery nudge) that retries finding the send button briefly (up to 5 x 100ms) before falling back to Enter, removing the race instead of relying on incidental Playwright-call latency to happen to mask it. Verified: 59/59 unit tests (2 new, directly reproducing the race and the still-correct Enter fallback when the button genuinely never appears), and live reproduction of the exact race against the real, currently-open, long-running conversation this was originally investigated on. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to PR #656. The user correctly challenged my initial conclusion that the live-testing failures were purely a self-inflicted dangling-CDP-connection artifact, pointing out the problem correlated with big/long conversations specifically. Retested properly:
assertReady()andinsertNatively()fed a correctly-found composer via the real selector-fallback discipline — works completely fine on the big page (assertReady in 906ms, composer found in 16ms, insertion in 292-501ms at 5-60KB).SELECTORS.composer[0]directly instead of using the realfirstVisible()fallback, which is why they hung —[data-testid="prompt-textarea"]isn't present in ChatGPT's current markup at all (only#prompt-textareaand a[contenteditable]selector still work), and blocking Playwright methods (.innerText()/.fill()/.evaluate()) correctly wait forever for a selector matching zero elements.insertNatively()returns as soon as its in-pageevaluate()call returns, before React has necessarily re-rendered. Confirmed live: the send button's selector shows 0 matches on the very next synchronous DOM query, 1 match only after arequestAnimationFrame.fillAndSend's single, immediate, no-retry check for the send button was silently falling through to theEnter-key fallback on this race, not because the button was actually missing.Fix
Extracted a shared
submit(page, composer)helper (used by bothfillAndSendand the stall-recovery nudge from #656) that retries finding the send button briefly (up to 5×100ms) before falling back toEnter.Test plan
node --test tests/*.test.mjs— 59/59 pass (2 new: the race reproduced and fixed; the Enter fallback still correct when the button genuinely never appears)insertNativelyin 550ms, immediate send-button check varies by exact timing)doctoragainst the real connected Chrome — passes🤖 Generated with Claude Code
https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz