Skip to content

Fix/wait repaint context & it looks like the CI environment needs to be upgraded - #1241

Open
zeoxisca wants to merge 3 commits into
go-rod:mainfrom
zeoxisca:fix/wait-repaint-context
Open

zeoxisca wants to merge 3 commits into
go-rod:mainfrom
zeoxisca:fix/wait-repaint-context

Conversation

@zeoxisca

@zeoxisca zeoxisca commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

WaitStableRAF can block indefinitely when it is called on a background or frozen tab.

Root cause

Element.WaitStableRAF derives a context-bound page before waiting for repaint:

page := el.page.Context(el.ctx)

However, Page.WaitRepaint performs the evaluation through p.root:

p.root.Eval(`() => new Promise(r => requestAnimationFrame(r))`)

Page.Context creates a shallow page clone. Its root field still points to the original root page, so the caller's context is not propagated to the page that evaluates requestAnimationFrame.
When a tab is hidden, backgrounded, frozen, or continuously changing, requestAnimationFrame may be throttled or never invoked. In that case, the returned promise remains pending and the caller's timeout cannot cancel the operation.

Fix

Preserve the caller's context when evaluating requestAnimationFrame on the root page:

p.root.Context(p.ctx).Eval(
    `() => new Promise(r => requestAnimationFrame(r))`,
)

This keeps the existing root-page behavior required for iframe support while ensuring that Page.Context, Page.Timeout, and cancellation remain effective.

Tests

The following regression tests were added:

  • TestWaitRepaintHonorsPageContext
  • Verifies that a canceled page context is honored by WaitRepaint.
  • TestWaitStableRAFOnBackgroundPageHonorsContext
  • Uses an embedded demo page.
  • Moves the page to the background and freezes its lifecycle so RAF cannot resolve.
  • Verifies that WaitStableRAF returns context.DeadlineExceeded instead of blocking indefinitely.
  • TestWaitStableRAFSurvivesFrequentActivationSwitches
  • Uses an embedded page with a continuously changing element driven by requestAnimationFrame.
  • Frequently switches the active tab while WaitStableRAF is running.
  • Verifies that the operation still terminates when its context expires.
    The background-tab test was also run against the previous implementation. It failed with:
    background WaitStableRAF remained blocked; this reproduces the pre-fix root-context regression

With the fix applied, all targeted tests pass:

go test . -run 'TestWait(RepaintHonorsPageContext|StableRAFOnBackgroundPageHonorsContext|StableRAFSurvivesFrequentActivationSwitches)$' -count=1
The same tests also pass with the race detector:
go test -race . -run 'TestWait(RepaintHonorsPageContext|StableRAFOnBackgroundPageHonorsContext|StableRAFSurvivesFrequentActivationSwitches)$' -count=1

Effect

Before this change, WaitStableRAF could remain blocked forever on a background or frozen tab, even when the caller supplied a timeout or cancellation context.
After this change, the operation reliably returns when its context expires, including while the target tab is inactive or when multiple tabs are repeatedly activated and deactivated.

@zeoxisca zeoxisca changed the title Fix/wait repaint context Fix/wait repaint context & it looks like the CI environment needs to be upgraded Aug 28, 2026

This branch has not been deployed

No deployments
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