Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions lib/capybara/cuprite/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
26 changes: 26 additions & 0 deletions spec/features/session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '<textarea name="draft"></textarea>'; }, 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 = '<input type="checkbox" name="agree">'; }, 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
Expand Down
8 changes: 8 additions & 0 deletions spec/support/views/with_js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,13 @@
<p>
<a href="#" id="open-twice">Open check twice</a>
</p>

<div id="draft-wrapper">
<textarea name="draft"></textarea>
</div>

<div id="agree-wrapper">
<input type="checkbox" name="agree">
</div>
</body>
</html>
Loading