1
0
Fork 0
mirror of https://github.com/teamcapybara/capybara.git synced 2022-11-09 12:08:07 -05:00
teamcapybara--capybara/lib/capybara/result.rb

156 lines
4 KiB
Ruby
Raw Normal View History

2016-03-07 19:52:19 -05:00
# frozen_string_literal: true
require 'forwardable'
module Capybara
##
# A {Capybara::Result} represents a collection of {Capybara::Node::Element} on the page. It is possible to interact with this
# collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation:
#
# * []
# * each()
# * at()
# * size()
# * count()
# * length()
# * first()
# * last()
# * empty?()
#
# @see Capybara::Node::Element
#
class Result
include Enumerable
extend Forwardable
def initialize(elements, query)
2012-07-09 08:47:11 -04:00
@elements = elements
@result_cache = []
2017-03-07 22:34:26 -05:00
@results_enum = lazy_select_elements { |node| query.matches_filters?(node) }
@query = query
end
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
alias :index :find_index
def each(&block)
return enum_for(:each) unless block_given?
@result_cache.each(&block)
loop do
next_result = @results_enum.next
@result_cache << next_result
block.call(next_result)
end
self
end
def [](*args)
2016-08-31 17:55:03 -04:00
if (args.size == 1) && ((idx = args[0]).is_a? Integer) && (idx >= 0)
@result_cache << @results_enum.next while @result_cache.size <= idx
@result_cache[idx]
else
full_results[*args]
end
rescue StopIteration
return nil
end
alias :at :[]
def empty?
!any?
end
2017-11-13 16:04:47 -05:00
# rubocop:disable Metrics/MethodLength
2017-11-14 15:14:24 -05:00
def compare_count
2016-08-31 17:55:03 -04:00
# Only check filters for as many elements as necessary to determine result
if @query.options[:count]
count_opt = Integer(@query.options[:count])
loop do
break if @result_cache.size > count_opt
@result_cache << @results_enum.next
end
2017-11-14 15:14:24 -05:00
return @result_cache.size <=> count_opt
2016-08-31 17:55:03 -04:00
end
if @query.options[:minimum]
2016-08-31 17:55:03 -04:00
min_opt = Integer(@query.options[:minimum])
begin
2016-08-31 17:55:03 -04:00
@result_cache << @results_enum.next while @result_cache.size < min_opt
rescue StopIteration
2017-11-14 15:14:24 -05:00
return -1
end
end
if @query.options[:maximum]
2016-08-31 17:55:03 -04:00
max_opt = Integer(@query.options[:maximum])
begin
2016-08-31 17:55:03 -04:00
@result_cache << @results_enum.next while @result_cache.size <= max_opt
2017-11-14 15:14:24 -05:00
return 1
rescue StopIteration
end
end
2016-08-31 17:55:03 -04:00
if @query.options[:between]
2017-11-14 15:14:24 -05:00
max = Integer(@query.options[:between].max)
min = Integer(@query.options[:between].min)
2016-08-31 17:55:03 -04:00
loop do
break if @result_cache.size > max
@result_cache << @results_enum.next
end
2017-11-14 15:14:24 -05:00
return 0 if (@query.options[:between] === @result_cache.size)
return -1 if @result_cache.size < min
return 1
2016-08-31 17:55:03 -04:00
end
2017-11-14 15:14:24 -05:00
return 0
end
2017-11-13 16:04:47 -05:00
# rubocop:enable Metrics/MethodLength
2017-11-14 15:14:24 -05:00
def matches_count?
compare_count == 0
end
2012-07-09 07:21:44 -04:00
def failure_message
2016-08-30 14:37:54 -04:00
message = @query.failure_message
2012-07-09 08:47:11 -04:00
if count > 0
message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
2012-07-09 08:47:11 -04:00
else
message << " but there were no matches"
end
unless rest.empty?
2017-11-14 15:14:24 -05:00
elements = rest.map { |el| el.text rescue "<<ERROR>>" }.map(&:inspect).join(", ")
2012-07-09 08:47:11 -04:00
message << ". Also found " << elements << ", which matched the selector but not all filters."
end
message
end
def negative_failure_message
failure_message.sub(/(to find)/, 'not \1')
end
private
def full_results
2016-08-31 17:55:03 -04:00
loop { @result_cache << @results_enum.next }
@result_cache
end
def rest
@rest ||= @elements - full_results
end
def lazy_select_elements(&block)
# JRuby has an issue with lazy enumerators which
# causes a concurrency issue with network requests here
# https://github.com/jruby/jruby/issues/4212
if RUBY_PLATFORM == 'java'
@elements.select(&block).to_enum # non-lazy evaluation
else
@elements.lazy.select(&block)
end
end
end
end