Find a waited selector in the frames a page shows

Merged
YO
10d ago
+162-28

Summary

On a public bid-information site built of framesets, wait: {selector} never held. In a browser session on its search page:

{"wait": {"selector": "select[name=ejMaxDisplayRowCount]"}, "timeout": "5s"}
-> wait failed: Uncaught (in promise) Error: waitForSelector: Timeout 5000ms exceeded waiting for "select[name=ejMaxDisplayRowCount]" to be visible

The select was on screen, in a frame. #3429 made expect/when {text} and {selector} read the frames a page shows; wait: {selector} and an upload without into still looked in the top document only.

Root cause

  • WaitForSelector handed a CSS selector to the runtime's page.waitForSelector, which resolves a plain CSS selector in the main frame only. Frames are reached only through >> hops or a deep XPath.
  • upload without into counted xpath=//input[@type=file] through the runtime, which also evaluates in the main frame only. So a frameset page's only file input was reported as errNoFileInput.

Fix

  • shownDocuments (from #3429) now also returns, for each document, the XPath of the frame holding it, in the runtime's deep-XPath form (/html[1]/frameset[1]/frame[2]/html[1]/...).
  • WaitForSelector:
    • A CSS selector is polled with the frame-aware SelectorVisible until it matches or the timeout ends, with the same error as before.
    • A selector with >> hops, or an XPath, still goes to the runtime as written.
  • SelectorVisible now also matches inside open shadow roots. The runtime's wait pierced shadow roots, so moving CSS waits onto SelectorVisible keeps that, and expect/when {selector} now agree with wait.
  • upload without into lists the file inputs of the page and its shown frames by deep XPath, refuses none or several as before, and gives the files to the one it finds.
  • The step reference (skills/dagu/references/steptypes.md, regenerated llms.txt) says which checks cover frames and shadow roots.

Tests

  • TestStagehandWaitsForSelectorInFrames uses the frameset fixture from #3429 (nested framesets, hidden frames), with an element added 2s after its frame loads. A wait finds the late element and a link in a nested frame, a >> hop selector and a deep XPath still resolve, and an element of a hidden frame times out with the usual error. The CSS cases failed before the fix with the runtime's timeout.
  • TestStagehandPageChecks: an element inside an open shadow root is matched by SelectorVisible and by WaitForSelector.
  • TestStagehandUploadFindsTheFileInputInAFrame: on a frameset whose only file input is in a frame, an upload without into goes straight to that input. Before the fix it failed with no file input. The existing upload tests, including the count of four file inputs on a page that has them, are unchanged.

Checked with the built binary against the live site: the wait above, which failed after 5s, now holds in 9 ms; the frame[name=mainfrm] >> frame >> … form holds as before.


Summary by cubic

Fixes wait: {selector} and upload without into so they find elements in the frames a page shows, not just its top document.

  • A CSS selector wait now polls with the frame-aware visibility check until the element appears, with the same error as before; >> hops and XPath selectors still go to the runtime as written.
  • A selector wait's reads end with the wait's own timeout, so an unresponsive page now fails near the wait's deadline instead of a single page read's.
  • SelectorVisible now also matches inside open shadow roots, so wait and expect/when {selector} agree.
  • upload without into finds the page's only file input across shown frames by deep XPath, and still fails when there are none or several.
  • Checks read only frames of the page's own origin.

Tests

  • Adds coverage for waits on late and nested-frame elements, hidden frames timing out, a wait near its own timeout on an unresponsive page, open shadow roots, and a file input in a frame.

Summary by CodeRabbit

  • New Features
    • Selector checks and waits can find elements in same-origin frames and open shadow roots, including nested frames and XPath selectors.
    • Selector waits can detect elements that appear after the wait begins.
    • Uploads without a specified selector can target the page’s sole file input, including one inside a visible frame.
  • Documentation
    • Updated browser-operation guidance to describe frame, shadow-root, upload, and selector-wait behavior.