From 364affa757f42f8ee110a82fa39186ede4776841 Mon Sep 17 00:00:00 2001 From: Jonas Nicklas Date: Wed, 9 Dec 2009 21:43:40 +0100 Subject: [PATCH] Automatically wait for asynchonous loading --- lib/capybara.rb | 7 ++++--- lib/capybara/driver/base.rb | 20 ++++++++++++++++++ lib/capybara/driver/culerity_driver.rb | 11 +++++++++- lib/capybara/driver/rack_test_driver.rb | 2 +- lib/capybara/driver/selenium_driver.rb | 11 +++++++++- lib/capybara/session.rb | 25 ++++++++++------------- spec/session/culerity_session_spec.rb | 1 + spec/session/selenium_session_spec.rb | 1 + spec/session_spec.rb | 27 +++++++++++++++++++++++++ spec/views/with_js.erb | 13 +++++++++++- 10 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 lib/capybara/driver/base.rb diff --git a/lib/capybara.rb b/lib/capybara.rb index b4e7da5f..53c02b25 100644 --- a/lib/capybara.rb +++ b/lib/capybara.rb @@ -21,12 +21,13 @@ module Capybara end end - autoload :Server, 'capybara/server' + autoload :Server, 'capybara/server' autoload :Session, 'capybara/session' - autoload :Node, 'capybara/node' - autoload :XPath, 'capybara/xpath' + autoload :Node, 'capybara/node' + autoload :XPath, 'capybara/xpath' module Driver + autoload :Base, 'capybara/driver/base' autoload :RackTest, 'capybara/driver/rack_test_driver' autoload :Culerity, 'capybara/driver/culerity_driver' autoload :Selenium, 'capybara/driver/selenium_driver' diff --git a/lib/capybara/driver/base.rb b/lib/capybara/driver/base.rb new file mode 100644 index 00000000..cea89c9e --- /dev/null +++ b/lib/capybara/driver/base.rb @@ -0,0 +1,20 @@ +class Capybara::Driver::Base + def visit(path) + raise "Not implemented" + end + + def find(query) + raise "Not implemented" + end + + def body + raise "Not implemented" + end + + def fetch(*paths) + paths.find do |path| + result = find(path).first + return result if result + end + end +end \ No newline at end of file diff --git a/lib/capybara/driver/culerity_driver.rb b/lib/capybara/driver/culerity_driver.rb index b0f3d4d4..930ef6bb 100644 --- a/lib/capybara/driver/culerity_driver.rb +++ b/lib/capybara/driver/culerity_driver.rb @@ -1,6 +1,6 @@ require 'culerity' -class Capybara::Driver::Culerity +class Capybara::Driver::Culerity < Capybara::Driver::Base class Node < Capybara::Node def text node.text @@ -69,6 +69,15 @@ class Capybara::Driver::Culerity def find(selector) browser.elements_by_xpath(selector).map { |node| Node.new(self, node) } end + + def fetch(*paths) + 8.times do + result = super + return result if result + sleep(0.1) + end + nil + end private diff --git a/lib/capybara/driver/rack_test_driver.rb b/lib/capybara/driver/rack_test_driver.rb index f937527a..cc856261 100644 --- a/lib/capybara/driver/rack_test_driver.rb +++ b/lib/capybara/driver/rack_test_driver.rb @@ -2,7 +2,7 @@ require 'rack/test' require 'nokogiri' require 'cgi' -class Capybara::Driver::RackTest +class Capybara::Driver::RackTest < Capybara::Driver::Base class Node < Capybara::Node def text node.text diff --git a/lib/capybara/driver/selenium_driver.rb b/lib/capybara/driver/selenium_driver.rb index b5b8db5b..dc191e35 100644 --- a/lib/capybara/driver/selenium_driver.rb +++ b/lib/capybara/driver/selenium_driver.rb @@ -1,6 +1,6 @@ require 'selenium-webdriver' -class Capybara::Driver::Selenium +class Capybara::Driver::Selenium < Capybara::Driver::Base class Node < Capybara::Node def text node.text @@ -83,6 +83,15 @@ class Capybara::Driver::Selenium def find(selector) driver.find_elements(:xpath, selector).map { |node| Node.new(self, node) } end + + def fetch(*paths) + 8.times do + result = super + return result if result + sleep(0.1) + end + nil + end private diff --git a/lib/capybara/session.rb b/lib/capybara/session.rb index 9875ac54..2bf27bc9 100644 --- a/lib/capybara/session.rb +++ b/lib/capybara/session.rb @@ -38,37 +38,37 @@ module Capybara end def fill_in(locator, options={}) - field = get(XPath.fillable_field(locator)) + field = fetch(XPath.fillable_field(locator)) raise Capybara::ElementNotFound, "cannot fill in, no text field, text area or password field with id or label '#{locator}' found" unless field field.set(options[:with]) end def choose(locator) - field = get(XPath.radio_button(locator)) + field = fetch(XPath.radio_button(locator)) raise Capybara::ElementNotFound, "cannot choose field, no radio button with id or label '#{locator}' found" unless field field.set(true) end def check(locator) - field = get(XPath.checkbox(locator)) + field = fetch(XPath.checkbox(locator)) raise Capybara::ElementNotFound, "cannot check field, no checkbox with id or label '#{locator}' found" unless field field.set(true) end def uncheck(locator) - field = get(XPath.checkbox(locator)) + field = fetch(XPath.checkbox(locator)) raise Capybara::ElementNotFound, "cannot uncheck field, no checkbox with id or label '#{locator}' found" unless field field.set(false) end def select(value, options={}) - field = get(XPath.select(options[:from])) + field = fetch(XPath.select(options[:from])) raise Capybara::ElementNotFound, "cannot select option, no select box with id or label '#{options[:from]}' found" unless field field.select(value) end def attach_file(locator, path) - field = get(XPath.file_field(locator)) + field = fetch(XPath.file_field(locator)) raise Capybara::ElementNotFound, "cannot attach file, no file field with id or label '#{locator}' found" unless field field.set(path) end @@ -133,25 +133,22 @@ module Capybara end def find_field(locator) - get(XPath.field(locator)) + fetch(XPath.field(locator)) end alias_method :field_labeled, :find_field def find_link(locator) - get(XPath.link(locator)) + fetch(XPath.link(locator)) end def find_button(locator) - get(XPath.button(locator)) + fetch(XPath.button(locator)) end private - def get(xpath) - xpath.paths.find do |path| - path = all(path).first - return path if path - end + def fetch(xpath) + driver.fetch(*xpath.paths.map { |path| current_scope.to_s + path }) end def css_to_xpath(css) diff --git a/spec/session/culerity_session_spec.rb b/spec/session/culerity_session_spec.rb index 2a377966..d80783dc 100644 --- a/spec/session/culerity_session_spec.rb +++ b/spec/session/culerity_session_spec.rb @@ -19,5 +19,6 @@ describe Capybara::Session do end it_should_behave_like "session" + it_should_behave_like "session with javascript support" end end diff --git a/spec/session/selenium_session_spec.rb b/spec/session/selenium_session_spec.rb index b31afca7..401e1e3b 100644 --- a/spec/session/selenium_session_spec.rb +++ b/spec/session/selenium_session_spec.rb @@ -19,5 +19,6 @@ describe Capybara::Session do end it_should_behave_like "session" + it_should_behave_like "session with javascript support" end end diff --git a/spec/session_spec.rb b/spec/session_spec.rb index 1cdf196f..a51dcfb8 100644 --- a/spec/session_spec.rb +++ b/spec/session_spec.rb @@ -790,6 +790,33 @@ shared_examples_for "session" do end end +shared_examples_for "session with javascript support" do + describe '#click_link' do + it "should wait for asynchronous load" do + @session.visit('/with_js') + @session.click_link('Click me') + @session.click_link('Has been clicked') + end + end + + describe '#click_button' do + it "should wait for asynchronous load" do + @session.visit('/with_js') + @session.click_link('Click me') + @session.click_button('New Here') + end + end + + describe '#fill_in' do + it "should wait for asynchronous load" do + @session.visit('/with_js') + @session.click_link('Click me') + @session.fill_in('new_field', :with => 'Testing...') + end + end + +end + describe Capybara::Session do context 'with non-existant driver' do it "should raise an error" do diff --git a/spec/views/with_js.erb b/spec/views/with_js.erb index 975e4ee4..faa120a4 100644 --- a/spec/views/with_js.erb +++ b/spec/views/with_js.erb @@ -11,10 +11,19 @@ $('#drag').draggable(); $('#drop').droppable({ drop: function(event, ui) { - ui.draggable.remove() + ui.draggable.remove(); $(this).html('Dropped!'); } }); + $('#clickable').click(function() { + var link = $(this); + setTimeout(function() { + $(link).after('Has been clicked'); + $(link).after(''); + $(link).after(''); + }, 500); + return false; + }); }); //]]> @@ -30,5 +39,7 @@

It should be dropped here.

+ +

Click me

\ No newline at end of file