diff --git a/README.md b/README.md index 03be4cc..920176f 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,10 @@ makes debugging easier). Running `rake autocompile` will watch the The click will fail, but an obsolete node error will be raised, meaning that Capybara's retry mechanisms will kick in. [Issue #130] +* Mouse over the element we will click, before clicking it. This + enables `:hover` effects etc to trigger before the click happens, + which can affect the click in some cases. [Issue #120] + ### 0.7.0 ### #### Features #### diff --git a/lib/capybara/poltergeist/client/compiled/node.js b/lib/capybara/poltergeist/client/compiled/node.js index 9f3050f..572ac9c 100644 --- a/lib/capybara/poltergeist/client/compiled/node.js +++ b/lib/capybara/poltergeist/client/compiled/node.js @@ -47,7 +47,7 @@ Poltergeist.Node = (function() { pos = this.clickPosition(); test = this.clickTest(pos.x, pos.y); if (test.status === 'success') { - return this.page.sendEvent('click', pos.x, pos.y); + return this.page.mouseEvent('click', pos.x, pos.y); } else { throw new Poltergeist.ClickFailed(test.selector, pos); } @@ -58,9 +58,8 @@ Poltergeist.Node = (function() { this.scrollIntoView(); position = this.clickPosition(); otherPosition = other.clickPosition(); - this.page.sendEvent('mousedown', position.x, position.y); - this.page.sendEvent('mousemove', otherPosition.x, otherPosition.y); - return this.page.sendEvent('mouseup', otherPosition.x, otherPosition.y); + this.page.mouseEvent('mousedown', position.x, position.y); + return this.page.mouseEvent('mouseup', otherPosition.x, otherPosition.y); }; Node.prototype.isEqual = function(other) { diff --git a/lib/capybara/poltergeist/client/compiled/web_page.js b/lib/capybara/poltergeist/client/compiled/web_page.js index e31bd89..e331e35 100644 --- a/lib/capybara/poltergeist/client/compiled/web_page.js +++ b/lib/capybara/poltergeist/client/compiled/web_page.js @@ -210,6 +210,11 @@ Poltergeist.WebPage = (function() { return (_base = this.nodes)[id] || (_base[id] = new Poltergeist.Node(this, id)); }; + WebPage.prototype.mouseEvent = function(name, x, y) { + this.sendEvent('mousemove', x, y); + return this.sendEvent(name, x, y); + }; + WebPage.prototype.evaluate = function() { var args, fn; fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; diff --git a/lib/capybara/poltergeist/client/node.coffee b/lib/capybara/poltergeist/client/node.coffee index 27b31f8..dc9c926 100644 --- a/lib/capybara/poltergeist/client/node.coffee +++ b/lib/capybara/poltergeist/client/node.coffee @@ -35,7 +35,7 @@ class Poltergeist.Node test = this.clickTest(pos.x, pos.y) if test.status == 'success' - @page.sendEvent('click', pos.x, pos.y) + @page.mouseEvent('click', pos.x, pos.y) else throw new Poltergeist.ClickFailed(test.selector, pos) @@ -45,9 +45,8 @@ class Poltergeist.Node position = this.clickPosition() otherPosition = other.clickPosition() - @page.sendEvent('mousedown', position.x, position.y) - @page.sendEvent('mousemove', otherPosition.x, otherPosition.y) - @page.sendEvent('mouseup', otherPosition.x, otherPosition.y) + @page.mouseEvent('mousedown', position.x, position.y) + @page.mouseEvent('mouseup', otherPosition.x, otherPosition.y) isEqual: (other) -> @page == other.page && this.isDOMEqual(other.id) diff --git a/lib/capybara/poltergeist/client/web_page.coffee b/lib/capybara/poltergeist/client/web_page.coffee index 7dd1da7..9577d57 100644 --- a/lib/capybara/poltergeist/client/web_page.coffee +++ b/lib/capybara/poltergeist/client/web_page.coffee @@ -146,6 +146,12 @@ class Poltergeist.WebPage get: (id) -> @nodes[id] or= new Poltergeist.Node(this, id) + # Before each mouse event we make sure that the mouse is moved to where the + # event will take place. This deals with e.g. :hover changes. + mouseEvent: (name, x, y) -> + this.sendEvent('mousemove', x, y) + this.sendEvent(name, x, y) + evaluate: (fn, args...) -> JSON.parse @native.evaluate("function() { return PoltergeistAgent.stringify(#{this.stringifyCall(fn, args)}) }") diff --git a/spec/integration/session_spec.rb b/spec/integration/session_spec.rb index d476e0a..009d30c 100644 --- a/spec/integration/session_spec.rb +++ b/spec/integration/session_spec.rb @@ -34,6 +34,12 @@ describe Capybara::Session do expect { @session.click_link "JS redirect" }.to raise_error(Capybara::Poltergeist::ObsoleteNode) end + it 'hovers an element before clicking it' do + @session.visit('/poltergeist/with_js') + @session.click_link "Hidden link" + @session.current_path.should == '/' + end + context "when someone (*cough* prototype *cough*) messes with Array#toJSON" do before do @session.visit("/poltergeist/index") diff --git a/spec/support/views/with_js.erb b/spec/support/views/with_js.erb index 628d983..1117703 100644 --- a/spec/support/views/with_js.erb +++ b/spec/support/views/with_js.erb @@ -5,6 +5,25 @@ + + @@ -26,6 +45,7 @@

-
O hai
+
O hai
+ Hidden link