Skip to content

Commit

Permalink
Merge branch 'non_ambiguous'
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Feb 9, 2012
2 parents c21d5eb + 6afc49f commit 020ccf0
Show file tree
Hide file tree
Showing 37 changed files with 226 additions and 522 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ capybara-*.html
doc
.bundle
Gemfile*.lock
chromedriver.log
chromedriver.log
bundler_stubs
4 changes: 1 addition & 3 deletions lib/capybara.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class InfiniteRedirectError < TimeoutError; end
class << self
attr_accessor :asset_root, :app_host, :run_server, :default_host
attr_accessor :server_host, :server_port
attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements, :prefer_visible_elements
attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements
attr_accessor :save_and_open_page_path, :automatic_reload
attr_writer :default_driver, :current_driver, :javascript_driver, :session_name
attr_accessor :app
Expand All @@ -40,7 +40,6 @@ class << self
# [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: CSS)
# [default_wait_time = Integer] The number of seconds to wait for asynchronous processes to finish (Default: 2)
# [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: false)
# [prefer_visible_elements = Boolean] Whether to prefer visible elements over hidden elements (Default: true)
# [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
# [save_and_open_page_path = String] Where to put pages saved through save_and_open_page (Default: Dir.pwd)
#
Expand Down Expand Up @@ -354,7 +353,6 @@ module Selenium
config.default_selector = :css
config.default_wait_time = 2
config.ignore_hidden_elements = false
config.prefer_visible_elements = true
config.default_host = "http://www.example.com"
config.automatic_reload = true
end
Expand Down
8 changes: 0 additions & 8 deletions lib/capybara/driver/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,6 @@ def wait?
false
end

def wait_until(*args)
end

def reset!
end

def has_shortcircuit_timeout?
false
end

end
9 changes: 5 additions & 4 deletions lib/capybara/node/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,19 @@ def initialize(session, base)
@base = base
end

# overridden in subclasses, e.g. Capybara::Node::Element
def reload
self
end

protected

def wait_until(seconds=Capybara.default_wait_time)
def synchronize(seconds=Capybara.default_wait_time)
retries = (seconds.to_f / 0.05).round

begin
yield
rescue => e
raise e unless driver.wait?
raise e unless (driver.respond_to?(:invalid_element_errors) and driver.invalid_element_errors.include?(e.class)) or e.is_a?(Capybara::ElementNotFound)
raise e unless driver.invalid_element_errors.include?(e.class) or e.is_a?(Capybara::ElementNotFound)
raise e if retries.zero?
sleep(0.05)
reload if Capybara.automatic_reload
Expand All @@ -55,6 +54,8 @@ def wait_until(seconds=Capybara.default_wait_time)
end
end

protected

def driver
session.driver
end
Expand Down
36 changes: 18 additions & 18 deletions lib/capybara/node/element.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ def initialize(session, base, parent, selector)
# @return [Object] The native element from the driver, this allows access to driver specific methods
#
def native
wait_until { base.native }
synchronize { base.native }
end

##
#
# @return [String] The text of the element
#
def text
wait_until { base.text }
synchronize { base.text }
end

##
Expand All @@ -54,15 +54,15 @@ def text
# @return [String] The value of the attribute
#
def [](attribute)
wait_until { base[attribute] }
synchronize { base[attribute] }
end

##
#
# @return [String] The value of the form element
#
def value
wait_until { base.value }
synchronize { base.value }
end

##
Expand All @@ -72,39 +72,39 @@ def value
# @param [String] value The new value
#
def set(value)
wait_until { base.set(value) }
synchronize { base.set(value) }
end

##
#
# Select this node if is an option element inside a select tag
#
def select_option
wait_until { base.select_option }
synchronize { base.select_option }
end

##
#
# Unselect this node if is an option element inside a multiple select tag
#
def unselect_option
wait_until { base.unselect_option }
synchronize { base.unselect_option }
end

##
#
# Click the Element
#
def click
wait_until { base.click }
synchronize { base.click }
end

##
#
# @return [String] The tag name of the element
#
def tag_name
wait_until { base.tag_name }
synchronize { base.tag_name }
end

##
Expand All @@ -115,7 +115,7 @@ def tag_name
# @return [Boolean] Whether the element is visible
#
def visible?
wait_until { base.visible? }
synchronize { base.visible? }
end

##
Expand All @@ -125,7 +125,7 @@ def visible?
# @return [Boolean] Whether the element is checked
#
def checked?
wait_until { base.checked? }
synchronize { base.checked? }
end

##
Expand All @@ -135,7 +135,7 @@ def checked?
# @return [Boolean] Whether the element is selected
#
def selected?
wait_until { base.selected? }
synchronize { base.selected? }
end

##
Expand All @@ -145,7 +145,7 @@ def selected?
# @return [String] An XPath expression
#
def path
wait_until { base.path }
synchronize { base.path }
end

##
Expand All @@ -156,7 +156,7 @@ def path
# @param [String] event The name of the event to trigger
#
def trigger(event)
wait_until { base.trigger(event) }
synchronize { base.trigger(event) }
end

##
Expand All @@ -170,19 +170,19 @@ def trigger(event)
# @param [Capybara::Element] node The element to drag to
#
def drag_to(node)
wait_until { base.drag_to(node.base) }
synchronize { base.drag_to(node.base) }
end

def find(*args)
wait_until { super }
synchronize { super }
end

def first(*args)
wait_until { super }
synchronize { super }
end

def all(*args)
wait_until { super }
synchronize { super }
end

def reload
Expand Down
37 changes: 16 additions & 21 deletions lib/capybara/node/finders.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ module Finders
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
#
def find(*args)
wait_until { first(*args) or raise_find_error(*args) }
query = query(*args)
query.find = true
synchronize do
results = resolve(query)
query.verify!(results)
results.first
end
end

##
Expand Down Expand Up @@ -109,10 +115,7 @@ def find_by_id(id)
# @return [Array[Capybara::Element]] The found elements
#
def all(*args)
query = Capybara::Query.new(*args)
query.xpaths.
map { |path| find_in_base(query, path) }.flatten.
select { |node| query.matches_filters?(node) }
resolve(query(*args))
end

##
Expand All @@ -127,28 +130,20 @@ def all(*args)
# @return [Capybara::Element] The found element or nil
#
def first(*args)
results = all(*args)
if Capybara.prefer_visible_elements
results.find(&:visible?) or results.first
else
results.first
end
all(*args).first
end

protected

def raise_find_error(*args)
query = Capybara::Query.new(*args)
raise Capybara::ElementNotFound, query.failure_message(:find, self)
def query(*args)
Capybara::Query.new(self, *args)
end

def find_in_base(query, xpath)
base.find(xpath).map do |node|
Capybara::Node::Element.new(session, node, self, query)
def resolve(query)
synchronize do
base.find(query.xpath).map do |node|
Capybara::Node::Element.new(session, node, self, query)
end.select { |node| query.matches_filters?(node) }
end
end


end
end
end
42 changes: 8 additions & 34 deletions lib/capybara/node/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,10 @@ module Matchers
#
def has_selector?(*args)
options = if args.last.is_a?(Hash) then args.last else {} end
wait_until do
synchronize do
results = all(*args)

case
when results.empty?
false
when options[:between]
options[:between] === results.size
when options[:count]
options[:count].to_i == results.size
when options[:maximum]
options[:maximum].to_i >= results.size
when options[:minimum]
options[:minimum].to_i <= results.size
else
results.size > 0
end or raise ExpectationNotMet
query(*args).matches_count?(results) or raise Capybara::ExpectationNotMet
results
end
rescue Capybara::ExpectationNotMet
return false
Expand All @@ -66,23 +53,10 @@ def has_selector?(*args)
#
def has_no_selector?(*args)
options = if args.last.is_a?(Hash) then args.last else {} end
wait_until do
synchronize do
results = all(*args)

case
when results.empty?
true
when options[:between]
not(options[:between] === results.size)
when options[:count]
not(options[:count].to_i == results.size)
when options[:maximum]
not(options[:maximum].to_i >= results.size)
when options[:minimum]
not(options[:minimum].to_i <= results.size)
else
results.empty?
end or raise ExpectationNotMet
query(*args).matches_count?(results) and raise Capybara::ExpectationNotMet
results
end
rescue Capybara::ExpectationNotMet
return false
Expand Down Expand Up @@ -186,7 +160,7 @@ def has_no_css?(path, options={})
def has_text?(content)
normalized_content = normalize_whitespace(content)

wait_until do
synchronize do
normalize_whitespace(text).include?(normalized_content) or
raise ExpectationNotMet
end
Expand All @@ -209,7 +183,7 @@ def has_text?(content)
def has_no_text?(content)
normalized_content = normalize_whitespace(content)

wait_until do
synchronize do
!normalize_whitespace(text).include?(normalized_content) or
raise ExpectationNotMet
end
Expand Down
12 changes: 6 additions & 6 deletions lib/capybara/node/simple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ def selected?
native[:selected]
end

protected

def find_in_base(selector, xpath)
native.xpath(xpath).map { |node| self.class.new(node) }
def synchronize
yield # simple nodes don't need to wait
end

def wait_until
yield # simple nodes don't need to wait
def resolve(query)
native.xpath(query.xpath).map do |node|
self.class.new(node)
end.select { |node| query.matches_filters?(node) }
end
end
end
Expand Down
Loading

0 comments on commit 020ccf0

Please sign in to comment.