Skip to content

fix(chatgpt-review): retry finding the send button instead of racing its render - #657

Merged
BorisTyshkevich merged 1 commit into
mainfrom
fix/chatgpt-review-send-button-race
Aug 9, 2026
Merged

fix(chatgpt-review): retry finding the send button instead of racing its render#657
BorisTyshkevich merged 1 commit into
mainfrom
fix/chatgpt-review-send-button-race

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

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:

  • Isolated "pre-existing tab" from "big conversation" as separate variables (they'd been confounded in my earlier testing).
  • Found the actual production code — assertReady() and insertNatively() 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).
  • My own standalone test scripts had hardcoded SELECTORS.composer[0] directly instead of using the real firstVisible() fallback, which is why they hung — [data-testid="prompt-textarea"] isn't present in ChatGPT's current markup at all (only #prompt-textarea and a [contenteditable] selector still work), and blocking Playwright methods (.innerText()/.fill()/.evaluate()) correctly wait forever for a selector matching zero elements.
  • While auditing selectors to confirm this, found a real, separate, previously-undetected bug: insertNatively() returns as soon as its in-page evaluate() 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 a requestAnimationFrame. fillAndSend's single, immediate, no-retry check for the send button was silently falling through to the Enter-key fallback on this race, not because the button was actually missing.

Fix

Extracted a shared submit(page, composer) helper (used by both fillAndSend and the stall-recovery nudge from #656) that retries finding the send button briefly (up to 5×100ms) before falling back to Enter.

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)
  • Live reproduction of the exact race against the real, currently-open, long conversation this was originally investigated on (insertNatively in 550ms, immediate send-button check varies by exact timing)
  • doctor against the real connected Chrome — passes

🤖 Generated with Claude Code

https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz

…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
@BorisTyshkevich
BorisTyshkevich merged commit 756c3d9 into main Aug 9, 2026
8 checks passed
@BorisTyshkevich
BorisTyshkevich deleted the fix/chatgpt-review-send-button-race branch August 9, 2026 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant