lib/calabash/wait.rb in calabash-2.0.0.pre10 vs lib/calabash/wait.rb in calabash-2.0.0.pre11
- old
+ new
@@ -1,74 +1,82 @@
module Calabash
# A public API for waiting for things to happen.
module Wait
- # @!visibility private
+ # Default error indicating a timeout
class TimeoutError < RuntimeError
end
# The default options used in the "wait" methods
@@default_options =
{
# default upper limit on how long to wait
timeout: Environment::WAIT_TIMEOUT,
# default message (String or Proc) if timeout occurs
- message: lambda do |options|
+ timeout_message: lambda do |options|
"Timed out after waiting for #{options[:timeout]} seconds..."
end,
# default polling frequency for waiting
retry_frequency: 0.1,
# default exception type to raise when the timeout is exceeded
- exception_class: Calabash::Wait::TimeoutError,
-
- # whether to embed a screenshot on failure
- screenshot_on_error: true
+ exception_class: Calabash::Wait::TimeoutError
}
# Returns the default wait options.
+ #
+ # @example
+ # # Get the current timeout message
+ # Calabash::Wait.default_options[:timeout_message]
+ #
+ # @example
+ # Calabash::Wait.default_options[:timeout] = 60
+ #
+ # @see @@default_options
# @return [Hash] Key/value pairs describing the wait options.
def self.default_options
@@default_options
end
- # Sets the default wait options.
- # @param [Hash] value The new default wait options.
- def self.default_options=(value)
- @@default_options = value
- end
-
# Evaluates the block given. If the execution time of the block exceeds
- # `timeout` it will raise a TimeoutError.
+ # `timeout` it will raise a `exception_class` (default:
+ # {Calabash::Wait.default_options
+ # Calabash::Wait.default_options[:exception_class]}).
#
# If you have an explicit or implicit loop in your block, or
# you want to limit the possible execution time of your block, use
- # `with_timeout`.
+ # {Calabash::Wait#with_timeout cal.with_timeout}
#
# @example
- # # If the 'PictureRow' view does not exist, keep scrolling down.
- # with_timeout(15, 'Could not find picture row') do
- # scroll_down until view_exists?("PictureRow")
+ # # If the 'PictureRow' view does not exist, keep panning up.
+ # cal.with_timeout(15, 'Could not find picture row') do
+ # cal.pan_screen_up until cal.view_exists?("PictureRow")
# end
#
- # # Scroll down **at least once** and continue scrolling down until the
+ # @example
+ # # Pan up **at least once** and continue pan up until the
# # 'PictureRow' exists.
- # wait_for(15, 'Could not find picture row') do
- # scroll_down
- # view_exists?("PictureRow")
+ # cal.wait_for('Could not find picture row') do
+ # cal.pan_screen_up
+ # cal.view_exists?("PictureRow")
# end
#
# @param [Number] timeout The time before failing
# @param [String, Proc] timeout_message The error message if timed out
- # @param [Class] exception_class The exception type raised if timed out
- # @return The returned value of `block`
+ # @param [Class] exception_class
+ # (default: {Calabash::Wait.default_options
+ # Calabash::Wait.default_options[:exception_class]}) The exception type
+ # raised if timed out
+ # @return The returned value of the block given
# @raise [ArgumentError] If an invalid timeout is given (<= 0)
# @raise [ArgumentError] If no timeout_message is given
# @raise [ArgumentError] If no block is given
- def with_timeout(timeout, timeout_message, exception_class = TimeoutError, &block)
+ def with_timeout(timeout, timeout_message,
+ exception_class: Wait.default_options[:exception_class],
+ &block)
if timeout_message.nil? ||
(timeout_message.is_a?(String) && timeout_message.empty?)
raise ArgumentError, 'You must provide a timeout message'
end
@@ -101,208 +109,229 @@
# "`rescue in with_timeout':" in the stack trace.
failed = true
end
if failed
- fail(exception_class, message)
+ raise exception_class, message
end
end
# Evaluates the given block until the block evaluates to truthy. If the
# block raises an error, it is **not** rescued.
#
# If the block does not evaluate to truthy within the given timeout
# an TimeoutError will be raised.
#
- # The default timeout will be `Wait.default_options[:timeout]`.
+ # The default timeout will be {Calabash::Wait.default_options
+ # Wait.default_options[:timeout]}.
#
+ # @example
+ # # Pan up **at least once** and continue pan up until the
+ # # 'PictureRow' exists.
+ # cal.wait_for('Could not find picture row') do
+ # cal.pan_screen_up
+ # cal.view_exists?("PictureRow")
+ # end
+ #
# @see Calabash::Wait#with_timeout
- # @see Calabash::Environment::WAIT_TIMEOUT
- # @see Calabash::Wait.default_options
#
# @param [String, Proc] timeout_message The error message if timed out.
- # @param [Hash] options Used to control the behavior of the wait.
- # @option options [Number] :timeout (30) How long to wait before timing out.
- # @option options [Number] :retry_frequency (0.3) How often to check for
- # the condition block to be truthy.
- # @option options [Boolean] :screenshot_on_error (true) Take a screenshot
- # if the block fails to be truthy or an error is raised in the block.
+ # @param [Number] timeout (default: {Calabash::Wait.default_options
+ # Calabash::Wait.default_options[:timeout]}) The time before
+ # @param [Number] retry_frequency (default: {Calabash::Wait.default_options
+ # Calabash::Wait.default_options[:retry_frequency]}) How often to check
+ # for the block to be truthy
+ # @param [Class] exception_class
+ # (default: {Calabash::Wait.default_options
+ # Calabash::Wait.default_options[:exception_class]}) The exception type
+ # raised if timed out
# @return The returned value of `block` if it is truthy
- def wait_for(timeout_message, options={}, &block)
- wait_options = Wait.default_options.merge(options)
- timeout = wait_options[:timeout]
-
- with_timeout(timeout, timeout_message, wait_options[:exception_class]) do
+ def wait_for(timeout_message,
+ timeout: Calabash::Wait.default_options[:timeout],
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency],
+ exception_class: Calabash::Wait.default_options[:exception_class],
+ &block)
+ with_timeout(timeout, timeout_message,
+ exception_class: exception_class) do
loop do
value = block.call
return value if value
- sleep(wait_options[:retry_frequency])
+ sleep(retry_frequency)
end
end
end
# Waits for `query` to match one or more views.
#
# @example
- # wait_for_view({marked: 'mark'})
+ # cal.wait_for_view({marked: 'mark'})
#
# @example
- # text = wait_for_view("myview")['text']
+ # cal.wait_for_view({marked: 'login'},
+ # timeout_message: "Did not see login button")
#
+ # @example
+ # text = cal.wait_for_view("myview")['text']
+ #
+ # @see Calabash::Wait#wait_for for optional parameters
+ #
# @param [String, Hash, Calabash::Query] query Query to match view
- # @see Calabash::Wait#with_timeout for options
# @return [Hash] The first view matching `query`.
- def wait_for_view(query, options={})
+ # @raise [ViewNotFoundError] If `query` do not match at least one view.
+ def wait_for_view(query,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
if query.nil?
raise ArgumentError, 'Query cannot be nil'
end
- defaults = Wait.default_options.dup
-
- defaults[:message] = lambda do |wait_options|
- "Waited #{wait_options[:timeout]} seconds for #{parse_query_list(query)} to match a view"
+ timeout_message ||= lambda do |wait_options|
+ "Waited #{wait_options[:timeout]} seconds for #{Wait.parse_query_list(query)} to match a view"
end
- defaults[:exception_class] = ViewNotFoundError
-
- timeout_options = defaults.merge(options)
-
- wait_for(timeout_options[:message],
- {timeout: timeout_options[:timeout],
- exception_class: timeout_options[:exception_class],
- retry_frequency: timeout_options[:retry_frequency]}) do
- view_exists?(query)
+ wait_for(timeout_message,
+ timeout: timeout,
+ retry_frequency: retry_frequency,
+ exception_class: ViewNotFoundError) do
+ result = query(query)
+ !result.empty? && result
end.first
end
# Waits for all `queries` to simultaneously match at least one view.
#
+ # @example
+ # cal.wait_for_views({id: 'foo'}, {id: 'bar'})
+ #
+ # @see Calabash::Wait#wait_for for optional parameters
+ #
# @param [String, Hash, Calabash::Query] queries List of queries or a
# query.
- #
- # @see Calabash::Wait#with_timeout for options
- # @return [void] The return value for this method is undefined.
- def wait_for_views(*queries, **options)
+ # @return The returned value is undefined
+ # @raise [ViewNotFoundError] If `queries` do not all match at least one
+ # view.
+ def wait_for_views(*queries,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
if queries.nil? || queries.any?(&:nil?)
raise ArgumentError, 'Query cannot be nil'
end
- defaults = Wait.default_options.dup
- defaults[:message] = lambda do |wait_options|
- "Waited #{wait_options[:timeout]} seconds for #{parse_query_list(queries)} to each match a view"
+ timeout_message ||= lambda do |wait_options|
+ "Waited #{wait_options[:timeout]} seconds for #{Wait.parse_query_list(queries)} to each match a view"
end
- defaults[:exception_class] = ViewNotFoundError
-
- timeout_options = defaults.merge(options)
-
- wait_for(timeout_options[:message],
- {timeout: timeout_options[:timeout],
- exception_class: timeout_options[:exception_class],
- retry_frequency: timeout_options[:retry_frequency]}) do
+ wait_for(timeout_message,
+ timeout: timeout,
+ retry_frequency: retry_frequency,
+ exception_class: ViewNotFoundError) do
views_exist?(*queries)
end
# Do not return the value of views_exist?(queries) as it clutters
# a console environment
true
end
# Waits for `query` not to match any views
#
+ # @example
+ # cal.wait_for_no_view({marked: 'mark'})
+ #
+ # @example
+ # cal.wait_for_no_view({marked: 'login'},
+ # timeout_message: "Login button did not disappear")
+ #
+ # @see Calabash::Wait#wait_for for optional parameters
+ #
# @param [String, Hash, Calabash::Query] query Query to match view
- # @see Calabash::Wait#with_timeout for options
- def wait_for_no_view(query, options={})
+ # @raise [ViewFoundError] If `query` do not match at least one view.
+ def wait_for_no_view(query,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
if query.nil?
raise ArgumentError, 'Query cannot be nil'
end
- defaults = Wait.default_options.dup
- defaults[:message] = lambda do |wait_options|
- "Waited #{wait_options[:timeout]} seconds for #{parse_query_list(query)} to not match any view"
+ timeout_message ||= lambda do |wait_options|
+ "Waited #{wait_options[:timeout]} seconds for #{Wait.parse_query_list(query)} to not match any view"
end
- defaults[:exception_class] = ViewFoundError
-
- timeout_options = defaults.merge(options)
-
- wait_for(timeout_options[:message],
- {timeout: timeout_options[:timeout],
- exception_class: timeout_options[:exception_class],
- retry_frequency: timeout_options[:retry_frequency]}) do
+ wait_for(timeout_message,
+ timeout: timeout,
+ retry_frequency: retry_frequency,
+ exception_class: ViewFoundError) do
!view_exists?(query)
end
end
# Waits for all `queries` to simultaneously match no views
#
+ # @example
+ # cal.wait_for_no_views({id: 'foo'}, {id: 'bar'})
+ #
+ # @see Calabash::Wait#wait_for for optional parameters
+ #
# @param [String, Hash, Calabash::Query] queries List of queries or a
# query.
- #
- # @see Calabash::Wait#with_timeout for options
- def wait_for_no_views(*queries, **options)
+ # @raise [ViewNotFoundError] If `queries` do not all match at least one
+ # view.
+ def wait_for_no_views(*queries,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
if queries.nil? || queries.any?(&:nil?)
raise ArgumentError, 'Query cannot be nil'
end
- defaults = Wait.default_options.dup
- defaults[:message] = lambda do |wait_options|
- "Waited #{wait_options[:timeout]} seconds for #{parse_query_list(queries)} to each not match any view"
+ timeout_message ||= lambda do |wait_options|
+ "Waited #{wait_options[:timeout]} seconds for #{Wait.parse_query_list(queries)} to each not match any view"
end
- defaults[:exception_class] = ViewFoundError
-
- timeout_options = defaults.merge(options)
-
- wait_for(timeout_options[:message],
- {timeout: timeout_options[:timeout],
- exception_class: timeout_options[:exception_class],
- retry_frequency: timeout_options[:retry_frequency]}) do
+ wait_for(timeout_message,
+ timeout: timeout,
+ retry_frequency: retry_frequency,
+ exception_class: ViewFoundError) do
!views_exist?(*queries)
end
end
# Does the given `query` match at least one view?
#
# @param [String, Hash, Calabash::Query] query Query to match view
- # @return [Object] Returns truthy if the `query` matches at least one view
+ # @return [Boolean] Returns true if the `query` matches at least one view
# @raise [ArgumentError] If given an invalid `query`
def view_exists?(query)
if query.nil?
raise ArgumentError, 'Query cannot be nil'
end
result = query(query)
- if result.empty?
- false
- else
- result
- end
+ !result.empty?
end
# Does the given `queries` all match at least one view?
#
# @param [String, Hash, Calabash::Query] queries List of queries or a
# query
- #
- # @return Returns truthy if the `queries` all match at least one view
+ # @return [Boolean] Returns true if the `queries` all match at least one
+ # view
# @raise [ArgumentError] If given an invalid list of queries
def views_exist?(*queries)
if queries.nil? || queries.any?(&:nil?)
raise ArgumentError, 'Query cannot be nil'
end
results = queries.map{|query| view_exists?(query)}
- if results.all?
- results
- else
- false
- end
+ results.all?
end
# Expect `query` to match at least one view. Raise an exception if it does
# not.
#
@@ -314,11 +343,11 @@
raise ArgumentError, 'Query cannot be nil'
end
unless view_exists?(query)
raise ViewNotFoundError,
- "No view matched #{parse_query_list(query)}"
+ "No view matched #{Wait.parse_query_list(query)}"
end
true
end
@@ -337,11 +366,11 @@
raise ArgumentError, 'Query cannot be nil'
end
unless views_exist?(*queries)
raise ViewNotFoundError,
- "Not all queries #{parse_query_list(queries)} matched a view"
+ "Not all queries #{Wait.parse_query_list(queries)} matched a view"
end
true
end
@@ -356,11 +385,11 @@
if query.nil?
raise ArgumentError, 'Query cannot be nil'
end
if view_exists?(query)
- raise ViewFoundError, "A view matched #{parse_query_list(query)}"
+ raise ViewFoundError, "A view matched #{Wait.parse_query_list(query)}"
end
true
end
@@ -377,98 +406,66 @@
raise ArgumentError, 'Query cannot be nil'
end
if queries.map{|query| view_exists?(query)}.any?
raise ViewFoundError,
- "Some views matched #{parse_query_list(queries)}"
+ "Some views matched #{Wait.parse_query_list(queries)}"
end
true
end
alias_method :views_should_not_exist, :do_not_expect_views
# Waits for a view containing `text`.
#
+ # @see Calabash::Wait#wait_for_view
+ #
# @param text [String] Text to look for
# @return [Object] The view matched by the text query
- # @see Calabash::Wait#wait_for_view
- def wait_for_text(text, options={})
- wait_for_view("* {text CONTAINS[c] '#{text}'}", options)
+ def wait_for_text(text,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
+
+ wait_for_view("* {text CONTAINS[c] '#{text}'}",
+ timeout: timeout,
+ timeout_message: timeout_message,
+ retry_frequency: retry_frequency)
end
# Waits for no views containing `text`.
#
+ # @see Calabash::Wait#wait_for_view
+ #
# @param text [String] Text to look for
- # @see Calabash::Wait#wait_for_no_view
- def wait_for_text_to_disappear(text, options={})
- wait_for_no_view("* {text CONTAINS[c] '#{text}'}", options)
+ # @return [Object] The view matched by the text query
+ def wait_for_no_text(text,
+ timeout: Calabash::Wait.default_options[:timeout],
+ timeout_message: nil,
+ retry_frequency: Calabash::Wait.default_options[:retry_frequency])
+
+ wait_for_no_view("* {text CONTAINS[c] '#{text}'}",
+ timeout: timeout,
+ timeout_message: timeout_message,
+ retry_frequency: retry_frequency)
end
- # Raises an exception. Embeds a screenshot if
- # Calabash::Wait#default_options[:screenshot_on_error] is true. The fail
- # method should be used when the test should fail and stop executing. Do
- # not use fail if you intent on rescuing the error raised without
- # re-raising.
- #
- # @example
- # unless view_exists?("* marked:'login'")
- # fail('Did not see "login" button')
- # end
- #
- # @example
- # entries = query("ListEntry").length
- #
- # if entries < 5
- # fail(MyError, "Should see at least 5 entries, saw #{entries}")
- # end
- #
- # @raise [RuntimeError, StandardError] By default, raises a RuntimeError with
- # `message`. You can pass in your own Exception class to override the
- # the default behavior.
- def fail(*several_variants)
- arg0 = several_variants[0]
- arg1 = several_variants[1]
-
- if arg1.nil?
- exception_type = RuntimeError
- message = arg0
- else
- exception_type = arg0
- message = arg1
- end
-
- screenshot_embed if Wait.default_options[:screenshot_on_error]
-
- raise exception_type, message
+ # Query matched an unexpected set of views
+ class UnexpectedMatchError < RuntimeError
end
- # Raises an exception and always embeds a screenshot
- #
- # @raise [RuntimeError, StandardError] By default, raises a RuntimeError with
- # `message`. You can pass in your own Exception class to override the
- # the default behavior.
- # @see Wait#fail
- def screenshot_and_raise(*several_variants)
- arg0 = several_variants[0]
- arg1 = several_variants[1]
-
- if arg1.nil?
- exception_type = RuntimeError
- message = arg0
- else
- exception_type = arg0
- message = arg1
- end
-
- screenshot_embed
-
- raise exception_type, message
+ # View was found
+ class ViewFoundError < UnexpectedMatchError
end
+ # View was not found
+ class ViewNotFoundError < UnexpectedMatchError
+ end
+
# @!visibility private
- def parse_query_list(queries)
+ def self.parse_query_list(queries)
unless queries.is_a?(Array)
queries = [queries]
end
queries_dup = queries.map{|query| "\"#{Query.new(query).send(:formatted_as_string)}\""}
@@ -480,21 +477,9 @@
elsif queries_dup.length == 2
"[#{queries_dup.first} and #{queries_dup.last}]"
else
"[#{queries_dup[0, queries_dup.length-1].join(',')}, and #{queries_dup.last}]"
end
- end
-
- # Query matched an unexpected set of views
- class UnexpectedMatchError < RuntimeError
- end
-
- # View was found
- class ViewFoundError < UnexpectedMatchError
- end
-
- # View was not found
- class ViewNotFoundError < UnexpectedMatchError
end
# @!visibility private
class PrivateWaitTimeoutError < RuntimeError
end