module Calabash::Cucumber::WaitHelpers
A collection of methods that help you wait for things.
Constants
- CALABASH_CONDITIONS
Currently two conditions that can be waited for using ‘wait_for_condition`: `:none_animating` no UIKit object is animating and `:no_network_indicator` status bar network indicator not showing.
- CLIENT_TIMEOUT_ADDITION
@!visibility private
- DEFAULT_OPTS
The default options used in the “wait*” methods
Public Instance Methods
@!visibility private Raises an error by raising a error and conditionally takes a screenshot based on the value of screenshot_on_error
. @param [RuntimeError,nil] error an error to raise @param [String,nil] timeout_message the message of the raise @param [Boolean] screenshot_on_error if true takes a screenshot before
raising an error
@return [nil] @raise [StandardError] If ‘error`, then that kind of error is raised.
Otherwise raise a RuntimeError.
# File lib/calabash-cucumber/wait_helpers.rb, line 455 def handle_error_with_options(error, timeout_message, screenshot_on_error) msg = (timeout_message || error) if error error_class = error.class else error_class = RuntimeError end if screenshot_on_error screenshot_and_raise msg else raise error_class, msg end end
@!visibility private
# File lib/calabash-cucumber/wait_helpers.rb, line 427 def screenshot_and_retry(msg, &block) path = screenshot res = yield # Validate after taking screenshot if res FileUtils.rm_f(path) return res else begin embed(path, 'image/png', msg) rescue NoMethodError attach(path, 'image/png') end raise wait_error(msg) end end
Combines touching an element and ‘wait_for_transition` @see wait_for_transition
@param [String] touch_q the Calabash
query to touch @param [Array] done_queries passed to `wait_for_transition` @param [Hash] check_options ({}) passed to `wait_for_transition` @param [Hash] animation_options ({}) passed to `wait_for_transition`
# File lib/calabash-cucumber/wait_helpers.rb, line 364 def touch_transition(touch_q, done_queries,check_options={},animation_options={}) touch(touch_q) wait_for_transition(done_queries,check_options,animation_options) end
Performs a lambda action until the element (a query string) disappears. The default action is to do nothing.
Raises an error if no uiquery is specified.
@example
until_element_does_not_exist("button", :action => lambda { swipe("up") })
@see wait_poll
@param [String] uiquery the Calabash
query to wait for disappearing. @param [Hash] opts options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
# File lib/calabash-cucumber/wait_helpers.rb, line 400 def until_element_does_not_exist(uiquery, opts = {}) condition = lambda {element_does_not_exist(uiquery)} extra_opts = { :until => condition, :action => lambda {} } opts = DEFAULT_OPTS.merge(extra_opts).merge(opts) wait_poll(opts) do opts[:action].call end end
Performs a lambda action until the element (a query string) appears. The default action is to do nothing. Similar to ‘wait_poll`.
Raises an error if no uiquery is specified.
@see wait_poll
@example
until_element_exists("button", :action => lambda { swipe("up") })
@param [String] uiquery the Calabash
query to wait for @param [Hash] opts options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
# File lib/calabash-cucumber/wait_helpers.rb, line 381 def until_element_exists(uiquery, opts = {}) extra_opts = { :until_exists => uiquery, :action => lambda {} } opts = DEFAULT_OPTS.merge(extra_opts).merge(opts) wait_poll(opts) do opts[:action].call end end
@private if msg
is a String, a new WaitError
is returned. Otherwise msg
itself is returned. @param [String,Object] msg a message to raise @return [WaitError] if msg
is a String, returns a new WaitError
@return [Object] if msg
is anything else, returns msg
# File lib/calabash-cucumber/wait_helpers.rb, line 475 def wait_error(msg) (msg.is_a?(String) ? WaitError.new(msg) : msg) end
Waits for a condition to be true. The condition is specified by a given block that is called repeatedly. If the block returns a ‘trueish’ value the condition is considered true and ‘wait_for` immediately returns. There is a `:timeout` option that specifies a maximum number of seconds to wait. If the given block doesn’t return a ‘trueish’ value before the ‘:timeout` seconds has elapsed, the waiting fails and raises a {Calabash::Cucumber::WaitHelpers::WaitError} error.
The ‘options` hash controls the details of waiting (see `options_or_timeout` below). {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} specifies the default waiting options.
‘wait_for` is a low-level building-block for waiting and often there are higher-level waiting methods what use `wait_for` in their implementation (e.g. `wait_for_element_exists`). @see wait_for_element_exists
@example Waiting for an element (see also ‘wait_for_element_exists`)
wait_for(timeout: 60, timeout_message: "Could not find 'Sign in' button") do element_exists("button marked:'Sign in'") end
@param [Hash] options_or_timeout options for controlling the details of the wait.
Note for backwards compatibility with old Calabash versions can also be a number which is then interpreted as a timeout.
@option options_or_timeout [Numeric] :timeout (30) upper limit on how long to wait (in seconds) @option options_or_timeout [Numeric] :retry_frequency (0.3) how often to poll (i.e., call the given block) @option options_or_timeout [Numeric] :post_timeout (0) if positive, an extra wait is made after the condition
is satisfied
@option options_or_timeout [String] :timeout_message the error message to use if condition is not satisfied
in time
@option options_or_timeout [Boolean] :screenshot_on_error generate a screenshot on error @return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 115 def wait_for(options_or_timeout=DEFAULT_OPTS, &block) #note Hash is preferred, number acceptable for backwards compat default_timeout = 30 timeout = options_or_timeout || default_timeout post_timeout=0 retry_frequency=0.3 timeout_message = nil screenshot_on_error = true if options_or_timeout.is_a?(Hash) timeout = options_or_timeout[:timeout] || default_timeout retry_frequency = options_or_timeout[:retry_frequency] || retry_frequency post_timeout = options_or_timeout[:post_timeout] || post_timeout timeout_message = options_or_timeout[:timeout_message] if options_or_timeout.key?(:screenshot_on_error) screenshot_on_error = options_or_timeout[:screenshot_on_error] end end begin Timeout.timeout(timeout, WaitError) do sleep(retry_frequency) until yield end sleep(post_timeout) if post_timeout > 0 rescue WaitError => e msg = timeout_message || e if screenshot_on_error sleep(retry_frequency) return screenshot_and_retry(msg, &block) else raise wait_error(msg) end rescue => e handle_error_with_options(e, nil, screenshot_on_error) end end
@!visibility private
# File lib/calabash-cucumber/wait_helpers.rb, line 276 def wait_for_condition(options = {}) timeout = options[:timeout] || ENV['WAIT_TIMEOUT'].to_i timeout = DEFAULT_OPTS[:timeout] unless timeout && timeout > 0 options[:query] = options[:query] || '*' if options.has_key?(:condition) opt_condition = options[:condition] if opt_condition.is_a?(Symbol) target_condition = CALABASH_CONDITIONS[opt_condition] elsif opt_condition.is_a?(String) target_condition = options[:condition] end options[:condition] = target_condition end options[:condition] = options[:condition] || CALABASH_CONDITIONS[:none_animating] options[:post_timeout] = options[:post_timeout] || 0 retry_frequency = options[:frequency] = options[:frequency] || 0.2 timeout_message = options[:timeout_message] = options[:timeout_message] || "Timeout waiting (#{options[:timeout]}) for condition (#{options[:condition]})" screenshot_on_error = true if options.key?(:screenshot_on_error) screenshot_on_error = options[:screenshot_on_error] end begin Timeout.timeout(timeout + CLIENT_TIMEOUT_ADDITION, WaitError) do res = http({:method => :post, :path => 'condition'}, options) res = JSON.parse(res) unless res['outcome'] == 'SUCCESS' raise WaitError.new(res['reason']) end sleep(options[:post_timeout]) if options[:post_timeout] > 0 end rescue WaitError => e msg = timeout_message || e if screenshot_on_error sleep(retry_frequency) return screenshot_and_retry(msg) do res = http({:method => :post, :path => 'condition'}, options) res = JSON.parse(res) res['outcome'] == 'SUCCESS' end else raise wait_error(msg) end rescue => e handle_error_with_options(e, nil, screenshot_on_error) end end
Waits for a Calabash
query to return an empty result (typically a UI element to disappear). Uses ‘wait_for`. @see wait_for
@see wait_for_element_exists
@see Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS
@param [String] element_query a Calabash
query to be empty (i.e. ‘element_does_not_exist(element_query)`) @param [Hash] options options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
@return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 247 def wait_for_element_does_not_exist(element_query, options={}) options[:timeout_message] = options[:timeout_message] || "Timeout waiting for element to not exist: #{element_query}" wait_for(options) { element_does_not_exist(element_query) } end
Waits for a Calabash
query to return a non-empty result (typically a UI element to be visible). Uses ‘wait_for`. @see wait_for
@see Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS
@example Waiting for an element to be visible
wait_for_element_exists("button marked:'foo'", timeout: 60)
@param [String] element_query a Calabash
query to wait for (i.e. ‘element_exists(element_query)`) @param [Hash] options options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
@return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 210 def wait_for_element_exists(element_query, options={}) options[:timeout_message] = options[:timeout_message] || "Timeout waiting for element: #{element_query}" wait_for(options) { element_exists(element_query) } end
Waits for one or more Calabash
queries to all return empty results (typically a UI elements to disappear). Uses ‘wait_for`. @see wait_for
@see wait_for_element_exists
@see wait_for_element_does_not_exist
@see Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS
@param [Array<String>] elements_arr an Array of Calabash
queries to be empty (i.e. ‘element_does_not_exist(element_query)`) @param [Hash] options options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
@return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 265 def wait_for_elements_do_not_exist(elements_arr, options={}) if elements_arr.is_a?(String) elements_arr = [elements_arr] end options[:timeout_message] = options[:timeout_message] || "Timeout waiting for no elements matching: #{elements_arr.join(",")}" wait_for(options) do elements_arr.none? { |q| element_exists(q) } end end
Waits for one or more Calabash
queries to all return non-empty results (typically a UI elements to be visible). Uses ‘wait_for`. @see wait_for
@see wait_for_element_exists
@see Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS
@param [Array<String>] elements_arr an Array of Calabash
queries to wait for (i.e. ‘element_exists(element_query)`) @param [Hash] options options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
@return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 226 def wait_for_elements_exist(elements_arr, options={}) if elements_arr.is_a?(String) elements_arr = [elements_arr] end options[:timeout_message] = options[:timeout_message] || "Timeout waiting for elements: #{elements_arr.join(',')}" wait_for(options) do elements_arr.all? { |q| element_exists(q) } end end
Waits for the status-bar network indicator to stop animating (network activity done). @param [Hash] options options for controlling the details of the wait. @option options [Numeric] :timeout (30) maximum time to wait @return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 343 def wait_for_no_network_indicator(options = {}) options[:condition] = CALABASH_CONDITIONS[:no_network_indicator] wait_for_condition(options) end
Waits for all elements to stop animating (EXPERIMENTAL). @param [Hash] options options for controlling the details of the wait. @option options [Numeric] :timeout (30) maximum time to wait @return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 333 def wait_for_none_animating(options = {}) options[:condition] = CALABASH_CONDITIONS[:none_animating] wait_for_condition(options) end
Combines waiting for elements and waiting for animations. @param [Array] done_queries Calabash
queries to wait for (one or more). @param [Hash] check_options ({}) options used for ‘wait_for_elements_exists(done_queries, check_options)` @param [Hash] animation_options ({}) options used for `wait_for_none_animating(animation_options)`
# File lib/calabash-cucumber/wait_helpers.rb, line 352 def wait_for_transition(done_queries, check_options={},animation_options={}) done_queries = [*done_queries] wait_for_elements_exist(done_queries,check_options) wait_for_none_animating(animation_options) end
Repeatedly runs an action (for side-effects) until a condition is satisfied. Similar to ‘wait_for` but specifies both a condition to wait for and an action to repeatedly perform to make the condition true (e.g. scrolling). The return value of the action is ignored.
The block represents the action and options :until or :until_exists specify the condition to wait for. Same options as ‘wait_for` can be provided.
@see wait_for
@example Scrolling until we find an element
wait_poll(timeout: 10, timeout_message: 'Unable to find "Example"', until_exists: "* marked:'Example'") do scroll("tableView", :down) end
@example Win the battle
wait_poll(timeout: 60, timeout_message: 'Defeat!', until: lambda { enemy_defeated? }) do launch_the_missiles! end
@param [Hash] opts options for controlling the details of the wait in addition to the options specified below,
all options in {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} also apply and can be overridden.
@option opts [Proc] :until if specified this lambda/Proc becomes the condition to wait for. @option opts [String] :until_exists if specified, a calabash query to wait for. Exactly one of ‘:until` and
`:until_exists` must be specified
@return [nil] when the condition is satisfied @raise [Calabash::Cucumber::WaitHelpers::WaitError] when the timeout is exceeded
# File lib/calabash-cucumber/wait_helpers.rb, line 181 def wait_poll(opts, &block) test = opts[:until] if test.nil? cond = opts[:until_exists] raise 'Must provide :until or :until_exists' unless cond test = lambda { element_exists(cond) } end wait_for(opts) do if test.call() true else yield false end end end
Performs the ‘tap` gesture on the (first) view that matches query `uiquery`.
As opposed to ‘touch`, `wait_tap` is a high-level method that combines:
-
waiting for the view to appear,
-
waiting for animations to complete on the view (and it’s parents) and
-
actually tapping the view.
This replaces the common pattern:
“‘ wait_for_none_animating
wait_for_element_exists
(“* marked:’log in’”) touch(“* marked:‘log in’”) “‘
By default, taps the center of the view. @see Calabash::Cucumber::Core#touch
@see Calabash::Cucumber::Core#touch_point @param {String} uiquery query describing view to tap. Note ‘nil` is not allowed. @param {Hash} options option for modifying the details of the touch @option options {Hash} :offset (nil) optional offset to tap point. Offset has an `:x` and `:y` key
the tap will be performed on the center of the view plus the offset.
@option options {Hash} :timeout (30) maximum number of seconds to wait for the view to appear @option options {Hash} :frequency (0.2) polling frequency to for checking if the view is present (>= 0.1) @return {Array<Hash>} serialized version of the tapped view
# File lib/calabash-cucumber/wait_helpers.rb, line 77 def wait_tap(uiquery, options={}) wait_for_none_animating wait_for_element_exists(uiquery, options) touch(uiquery, options) end
Performs a lambda action once the element exists. The default behavior is to touch the specified element.
Raises an error if no uiquery is specified.
@example
when_element_exists("button", :timeout => 10)
@see wait_for
@param [String] uiquery the Calabash
query to wait for. @param [Hash] opts options for controlling the details of the wait.
The same options as {Calabash::Cucumber::WaitHelpers::DEFAULT_OPTS} apply.
# File lib/calabash-cucumber/wait_helpers.rb, line 420 def when_element_exists(uiquery, opts = {}) action = opts[:action] || lambda { touch(uiquery) } wait_for_element_exists(uiquery, opts) action.call end