diff --git a/CHANGELOG.md b/CHANGELOG.md index ddbe085..d2ccddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixed - Ensure node has focus before setting value [#280] +- Raise `ObsoleteNode` instead of silently acting on a node that got disconnected from the DOM between being found and being used [#239] ### Removed diff --git a/lib/capybara/cuprite/node.rb b/lib/capybara/cuprite/node.rb index fdff0e2..7409592 100644 --- a/lib/capybara/cuprite/node.rb +++ b/lib/capybara/cuprite/node.rb @@ -18,6 +18,8 @@ def initialize(driver, node) end def command(name, *args) + raise ObsoleteNode.new(self, nil) unless node.evaluate("this.isConnected") + browser.send(name, node, *args) rescue Ferrum::NodeNotFoundError => e raise ObsoleteNode.new(self, e.response) diff --git a/spec/features/session_spec.rb b/spec/features/session_spec.rb index a44aea1..fd71fc6 100644 --- a/spec/features/session_spec.rb +++ b/spec/features/session_spec.rb @@ -42,6 +42,32 @@ expect(@session.current_path).to eq("/") end + it "raises an error instead of filling in a stale node replaced right after being found" do + @session.visit("/cuprite/with_js") + node = @session.find(:css, "[name=draft]", visible: :all) + + @session.execute_script(<<~JS) + var wrapper = document.getElementById("draft-wrapper"); + setTimeout(function() { wrapper.innerHTML = ''; }, 0); + JS + + # native.set bypasses Capybara::Node::Element#reload, which would + # otherwise silently re-find and retry against the live replacement. + expect { node.native.set("World") }.to raise_error(Capybara::Cuprite::ObsoleteNode) + end + + it "raises an error instead of checking a stale checkbox replaced right after being found" do + @session.visit("/cuprite/with_js") + node = @session.find(:css, "[name=agree]", visible: :all) + + @session.execute_script(<<~JS) + var wrapper = document.getElementById("agree-wrapper"); + setTimeout(function() { wrapper.innerHTML = ''; }, 0); + JS + + expect { node.native.set(true) }.to raise_error(Capybara::Cuprite::ObsoleteNode) + end + it "does not raise error when asserting svg elements with a count that is not what is in the dom" do @session.visit("/cuprite/with_js") expect { @session.has_css?("svg circle", count: 2) }.to_not raise_error diff --git a/spec/support/views/with_js.erb b/spec/support/views/with_js.erb index b837d7b..0efae6f 100644 --- a/spec/support/views/with_js.erb +++ b/spec/support/views/with_js.erb @@ -72,5 +72,13 @@
+ +