Skip to content

Make waitUntilLoaded best-effort: one deadline, no throwing, report each signal (#87) - #90

Merged
morisil merged 2 commits into
mainfrom
fix/87-wait-until-loaded-timeout
Sep 30, 2026
Merged

morisil merged 2 commits into
mainfrom
fix/87-wait-until-loaded-timeout

Conversation

@morisil

@morisil morisil commented Sep 30, 2026

Copy link
Copy Markdown
Member

Fixes #87.

Tab.waitUntilLoaded() threw TimeoutWaitingForReadyStateException when a page's load event never fired. For example, one sub-resource the server never answers.
It now stays best-effort in every case.

Changes

  • No throwing on page behaviour.
    waitUntilLoaded polls document.readyState itself instead of calling kdriver's waitForReadyState.
    If a step fails because of the page (a navigation destroys the JS context, a CDP command times out, an evaluation errors), it is retried against the new document instead of escaping.
    Only a closed browser connection still throws.
  • One deadline.
    The readyState poll and the network and DOM waiters share a single timeout, and each is cut off at it.
    Before, the worst case was about 2× timeout (6 s on a 3 s timeout in the new test).
  • PageLoad result instead of Boolean (public API change, API dump updated).
    It reports the last readyState seen and whether the network and DOM went quiet.
    settled is the old boolean.
    parsed tells a merely busy page apart from a document that never finished parsing, whose capture would be truncated.
    Capture.kt warns in that case.
  • Tests.
    Tests that stall a request via the Fetch domain now assert the request was actually paused and disable interception afterwards.
    New tests cover a parser-blocked document (blocked.html), a page reloading itself during the wait (navigating.html), and the shared budget.
    The budget test is the one wall-clock assertion: under 4.5 s for a 3 s timeout.

Testing

./gradlew :markanywhere-browse:build passes (19 browser tests plus apiCheck), and markanywhere-html's test sources compile.
Before the fix, the navigation test threw CDPException: Inspected target navigated or closed and the budget test took 6.07 s.
The wait tests passed four times in a row at 3.8–3.9 s for the budget case.

🤖 Generated with Claude Code

morisil and others added 2 commits September 30, 2026 16:03
…ult (#87)

kdriver's Tab.waitForReadyState throws TimeoutWaitingForReadyStateException
at its cap, so a page whose document fully arrived but whose load event never
fires (one sub-resource never answered) made waitUntilLoaded throw instead of
returning false. Catch it and report best-effort false, matching the network
and DOM waiters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
waitUntilLoaded polls document.readyState itself instead of calling
kdriver's waitForReadyState, which checks its cap only between
evaluations. All three steps now share the single timeout: the network
and DOM waiters get what the readyState poll left, and each is cut off
at the deadline, so the call returns within timeout (it took 2x before).

A step failing because of the page (a navigation destroying the JS
context, a CDP command timeout, an evaluation error) is retried against
the new document instead of escaping; only a closed connection throws.

It now returns PageLoad (last readyState, networkIdle, domIdle) instead
of a Boolean: settled is the old result, and parsed tells a merely busy
page apart from a document that never finished parsing, whose capture
would be truncated. Capture.kt warns in that case.

Tests assert that the Fetch interception actually paused the request
and disable it afterwards, and cover a parser-blocked document, a page
navigating during the wait, and the shared budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@morisil
morisil merged commit 4f934e2 into main Sep 30, 2026
2 checks passed
@morisil
morisil deleted the fix/87-wait-until-loaded-timeout branch September 30, 2026 15:07
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.

Tab.waitUntilLoaded() throws TimeoutWaitingForReadyStateException instead of returning false

1 participant