# encoding: UTF-8
# frozen_string_literal: true
module Capybara
# @api private
module Helpers
extend self
##
#
# Normalizes whitespace space by stripping leading and trailing
# whitespace and replacing sequences of whitespace characters
# with a single space.
#
# @param [String] text Text to normalize
# @return [String] Normalized text
#
def normalize_whitespace(text)
text.to_s.gsub(/[[:space:]]+/, ' ').strip
end
##
#
# Escapes any characters that would have special meaning in a regexp
# if text is not a regexp
#
# @param [String] text Text to escape
# @return [String] Escaped text
#
def to_regexp(text)
text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
end
##
#
# Injects a `` tag into the given HTML code, pointing to
# `Capybara.asset_host`.
#
# @param [String] html HTML code to inject into
# @return [String] The modified HTML code
#
def inject_asset_host(html)
if Capybara.asset_host && Nokogiri::HTML(html).css("base").empty?
match = html.match(/
/)
if match
return html.clone.insert match.end(0), ""
end
end
html
end
##
#
# Checks if the given count matches the given count options.
# Defaults to true if no options are specified. If multiple
# options are provided, it tests that all conditions are met;
# however, if :count is supplied, all other options are ignored.
#
# @param [Integer] count The actual number. Should be coercible via Integer()
# @option [Range] between Count must be within the given range
# @option [Integer] count Count must be exactly this
# @option [Integer] maximum Count must be smaller than or equal to this value
# @option [Integer] minimum Count must be larger than or equal to this value
#
def matches_count?(count, options={})
return (Integer(options[:count]) == count) if options[:count]
return false if options[:maximum] && (Integer(options[:maximum]) < count)
return false if options[:minimum] && (Integer(options[:minimum]) > count)
return false if options[:between] && !(options[:between] === count)
return true
end
##
#
# Checks if a count of 0 is valid for the given options hash.
# Returns false if options hash does not specify any count options.
#
def expects_none?(options={})
if [:count, :maximum, :minimum, :between].any? { |k| options.has_key? k }
matches_count?(0,options)
else
false
end
end
##
#
# Generates a failure message given a description of the query and count
# options.
#
# @param [String] description Description of a query
# @option [Range] between Count should have been within the given range
# @option [Integer] count Count should have been exactly this
# @option [Integer] maximum Count should have been smaller than or equal to this value
# @option [Integer] minimum Count should have been larger than or equal to this value
#
def failure_message(description, options={})
message = String.new("expected to find #{description}")
if options[:count]
message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
elsif options[:between]
message << " between #{options[:between].first} and #{options[:between].last} times"
elsif options[:maximum]
message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}"
elsif options[:minimum]
message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}"
end
message
end
##
#
# A poor man's `pluralize`. Given two declensions, one singular and one
# plural, as well as a count, this will pick the correct declension. This
# way we can generate grammatically correct error message.
#
# @param [String] singular The singular form of the word
# @param [String] plural The plural form of the word
# @param [Integer] count The number of items
#
def declension(singular, plural, count)
if count == 1
singular
else
plural
end
end
if defined?(Process::CLOCK_MONOTONIC)
def monotonic_time
Process.clock_gettime Process::CLOCK_MONOTONIC
end
else
def monotonic_time
Time.now.to_f
end
end
end
end