Skip to content

fix(node): drop cached node id when the document is updated - #653

Merged
route merged 3 commits into
mainfrom
fix/stale-node-id
Oct 18, 2026
Merged

route merged 3 commits into
mainfrom
fix/stale-node-id

Conversation

@route

@route route commented Oct 18, 2026

Copy link
Copy Markdown
Member

Fixes #86

A Ferrum::Node caches its CDP node id. Chrome invalidates node ids on DOM.documentUpdated and reuses them for the new document, so a node found before a navigation or reload silently acted on another element: focus, click, scroll_into_view, evaluate on the node, or passing it as a script argument.

This also affected Cuprite: its this.isConnected guard resolves the node through the same cached id, so it passed for the wrong element and the command went ahead.

Changes

  • Page#document_version is bumped on every DOM.documentUpdated. Node#node_id re-requests its id from its remote object once the version changed. For a node from a previous document this raises NodeNotFoundError, which Cuprite turns into ObsoleteNode, so Capybara reloads and retries.
  • The version is recorded only after a successful lookup, so a failed one doesn't leave the stale id looking current.
  • NodeNotFoundError raised by Node#node_id now carries its message ("node is not trackable") instead of the class name.

Testing

  • New spec: a node found before a reload raises NodeNotFoundError on focus (twice) instead of focusing the new document's element. It fails without the fix.
  • Ferrum suite: 633 examples, 0 failures.
  • Cuprite suite against this branch: 1863 examples, 1 failure, spec/features/driver_spec.rb:113, which also fails on main. It calls Process#default_user_agent, removed in ref(browser): read browser details over CDP and ask /json/version only for url: #651.

route added 3 commits October 18, 2026 16:46
Chrome invalidates node ids on DOM.documentUpdated and hands the same ids out again for the new document, so a node
found before a navigation or reload acted on a different element. Page now tracks a document version and Node
re-requests its id from its remote object after it changes, which raises NodeNotFoundError for a stale node.

Fixes #86
@route
route merged commit 6d251cc into main Oct 18, 2026
7 checks passed
@route
route deleted the fix/stale-node-id branch October 18, 2026 14: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.

Ferrum needs to listen DOM.documentUpdated in order to use NodeId values properly

1 participant