Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

WIP adding rdoc documentation

  • Loading branch information...
commit 5c56782a7ac8d93dbf4b4423321d867994fcab02 1 parent ff8d19f
@moredip authored
View
1  .yardopts
@@ -0,0 +1 @@
+gem/lib/**/*.rb
View
58 gem/Gemfile.lock
@@ -0,0 +1,58 @@
+PATH
+ remote: .
+ specs:
+ frank-cucumber (0.9.4)
+ cucumber
+ dnssd
+ i18n
+ json
+ plist
+ rspec (>= 2.0)
+ sim_launcher (= 0.3.8)
+ thor
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ builder (3.0.0)
+ cucumber (1.2.1)
+ builder (>= 2.1.2)
+ diff-lcs (>= 1.1.3)
+ gherkin (~> 2.11.0)
+ json (>= 1.4.6)
+ diff-lcs (1.1.3)
+ dnssd (2.0)
+ gherkin (2.11.1)
+ json (>= 1.4.6)
+ i18n (0.6.0)
+ json (1.7.3)
+ plist (3.1.0)
+ rack (1.4.1)
+ rack-protection (1.2.0)
+ rack
+ rr (1.0.4)
+ rspec (2.10.0)
+ rspec-core (~> 2.10.0)
+ rspec-expectations (~> 2.10.0)
+ rspec-mocks (~> 2.10.0)
+ rspec-core (2.10.1)
+ rspec-expectations (2.10.0)
+ diff-lcs (~> 1.1.3)
+ rspec-mocks (2.10.1)
+ sim_launcher (0.3.8)
+ sinatra
+ sinatra (1.3.2)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ thor (0.15.4)
+ tilt (1.3.3)
+ yard (0.8.2.1)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ frank-cucumber!
+ rr
+ yard
View
1  gem/frank-cucumber.gemspec
@@ -30,4 +30,5 @@ Gem::Specification.new do |s|
s.add_dependency( "thor" )
s.add_development_dependency( "rr" )
+ s.add_development_dependency( "yard" )
end
View
86 gem/lib/frank-cucumber/frank_helper.rb
@@ -7,73 +7,121 @@
module Frank module Cucumber
+ # FrankHelper provides a core set of helper functions for use when interacting with Frank.
+ #
+ # == Configuring the Frank driver
+ # There are some class-level facilities which configure how all Frank interactions work. For example you can specify which selector engine to use
+ # with {FrankHelper.selector_engine}. You can specify the base url which the native app's Frank server is listening on with {FrankHelper.server_base_url}.
+ #
+ # Two common use cases are covered more conveniently with {FrankHelper.use_shelley_from_now_on} and {FrankHelper.test_on_physical_device_via_bonjour}.
module FrankHelper
include WaitHelper
include KeyboardHelper
include HostScripting
+ # @!attribute [rw] selector_engine
class << self
- # TODO: adding an ivar to the module itself is a big ugyl hack. We need a FrankDriver class, or similar
- attr_accessor :selector_engine, :server_base_url
+ # @return [String] the selector engine we tell Frank to use when interpreting view selectors.
+ attr_accessor :selector_engine
+ # @return [String] the base url which the Frank server is running on. All Frank commands will be sent to that server.
+ attr_accessor :server_base_url
+ # After calling this method all subsequent commands will ask Frank to use the Shelley selector engine to interpret view selectors.
def use_shelley_from_now_on
@selector_engine = 'shelley_compat'
end
+ # Use Bonjour to search for a running Frank server. The server found will be the recipient for all subsequent Frank commands.
+ # @raise a generic exception if no Frank server could be found via Bonjour
def test_on_physical_device_via_bonjour
@server_base_url = Bonjour.new.lookup_frank_base_uri
raise 'could not detect running Frank server' unless @server_base_url
end
end
+ #@api private
+ #@return [:String] convient shorthand for {Frank::Cucumber::FrankHelper.selector_engine}, defaulting to 'uiquery'
def selector_engine
Frank::Cucumber::FrankHelper.selector_engine || 'uiquery' # default to UIQuery for backwards compatibility
end
+ #@api private
+ #@return [:String] convient shorthand for {Frank::Cucumber::FrankHelper.server_base_url}
def base_server_url
Frank::Cucumber::FrankHelper.server_base_url
end
-
-
- def touch( uiquery )
- touch_successes = frankly_map( uiquery, 'touch' )
- raise "could not find anything matching [#{uiquery}] to touch" if touch_successes.empty?
+ # Ask Frank to touch all views matching the specified selector. There may be views in the view heirarchy which match the selector but
+ # which Frank cannot or will not touch - for example views which are outside the current viewport. You can discover which of the matching
+ # views were actually touched by inspecting the Array which is returned.
+ #
+ # @param [String] selector a view selector.
+ # @return [Array<Boolean>] an array indicating for each view which matched the selector whether it was touched or not.
+ # @raise an expection if no views matched the selector
+ # @raise an expection if no views which matched the selector could be touched
+ def touch( selector )
+ touch_successes = frankly_map( selector, 'touch' )
+ raise "could not find anything matching [#{selector}] to touch" if touch_successes.empty?
raise "some views could not be touched (probably because they are not within the current viewport)" if touch_successes.include?(false)
end
-
- def element_exists( query )
- matches = frankly_map( query, 'accessibilityLabel' )
+
+ # Indicate whether there are any views in the current view heirarchy which match the specified selector.
+ # @param [String] selector a view selector.
+ # @return [Boolean]
+ # @see #check_element_exists
+ def element_exists( selector )
+ matches = frankly_map( selector, 'accessibilityLabel' )
# TODO: raise warning if matches.count > 1
!matches.empty?
end
- def check_element_exists( query )
- #puts "checking #{query} exists..."
- element_exists( query ).should be_true
+ # Assert whether there are any views in the current view heirarchy which match the specified selector.
+ # @param [String] selector a view selector.
+ # @raise an rspec exception if the assertion fails
+ # @see #element_exists, #check_element_does_not_exist
+ def check_element_exists( selector )
+ element_exists( selector ).should be_true
end
- def check_element_does_not_exist( query )
- #puts "checking #{query} does not exist..."
- element_exists( query ).should be_false
+ # Assert whether there are no views in the current view heirarchy which match the specified selector.
+ # @param [String] selector a view selector.
+ # @raise an rspec exception if the assertion fails
+ # @see #element_exists, #check_element_exists
+ def check_element_does_not_exist( selector )
+ element_exists( selector ).should be_false
end
+ # Indicate whether there are any views in the current view heirarchy which contain the specified accessibility label.
+ # @param [String] expected_mark the expected accessibility label
+ # @return [Boolean]
+ # @see #check_view_with_mark_exists
def view_with_mark_exists(expected_mark)
element_exists( "view marked:'#{expected_mark}'" )
end
+ # Assert whether there are any views in the current view heirarchy which contain the specified accessibility label.
+ # @param [String] expected_mark the expected accessibility label
+ # @raise an rspec exception if the assertion fails
+ # @see #view_with_mark_exists
def check_view_with_mark_exists(expected_mark)
check_element_exists( "view marked:'#{expected_mark}'" )
end
+ # Assert whether there are no views in the current view heirarchy which contain the specified accessibility label.
+ # @param [String] expected_mark the expected accessibility label
+ # @raise an rspec exception if the assertion fails
+ # @see #view_with_mark_exists, #check_view_with_mark_exists
def check_view_with_mark_does_not_exist(expected_mark)
check_element_does_not_exist( "view marked:'#{expected_mark}'" )
end
- # Waits for any of the selectors provided to match a view. Returns true
- # as soon as we find a matching view, otherwise keeps testing until timeout.
- # The first selector which matches is passed to a block if it was provided.
+ # Waits for any of the specified selectors to match a view.
+ #
+ # Checks each selector in turn within a {http://sauceio.com/index.php/2011/04/how-to-lose-races-and-win-at-selenium/ spin assert} loop and yields the first one which is found to exist in the view heirarchy.
+ # Raises an exception if no views could be found to match any of the provided selectors within {WaitHelper::TIMEOUT} seconds.
+ #
+ # @see WaitHelper#wait_until
def wait_for_element_to_exist(*selectors,&block)
wait_until(:message => "Waited for element matching any of #{selectors.join(', ')} to exist") do
at_least_one_exists = false
View
53 gem/lib/frank-cucumber/wait_helper.rb
@@ -3,38 +3,37 @@
module Frank
module Cucumber
-# What's going on here?!
+# This module contains a single method called wait_until which implements the {http://sauceio.com/index.php/2011/04/how-to-lose-races-and-win-at-selenium/ Spin Assert} pattern.
#
-# This module contains a single method called wait_until. When we mix this module into another class or module (such as
-# FrankHelper) then that wait_until method will be available inside that class or module. Because we call module_function
-# at the end of the module this method is also available as a static method on the module. That means you can also call
-# Frank::Cucumber::WaitHelper.wait_until from anywhere in your code.
+# When we mix this module into another class or module (such as {FrankHelper}) then that wait_until method will be available inside
+# that class or module. Because we call module_function at the end of the module this method is also available as a static method on the module.
+# That means you can also call {Frank::Cucumber::WaitHelper.wait_until} from anywhere in your code.
#
-#
-# wait_until will repeatedly execute the passed in block until either it returns true or a timeout expires. Between
-# executions there is a pause of POLL_SLEEP seconds.
-#
-# wait_until takes two options, a timeout and a message.
-# The timeout defaults to the WaitHelper::TIMEOUT constant. That constant is based off of a WAIT_TIMEOUT
-# environment variable, otherwise it defaults to 240 seconds.
-# If a message is passed in as an option then that message is used when reporting a timeout.
-#
-#
-# Example usage:
-#
-# wait_until( :timeout => 20, :message => 'timed out waiting for splines to reticulate' ) do
-# num_splines_reticulated = reticulate_splines(1,2,3)
-# num_splines_reticulated > 0
-# end
-#
-# Here we will keep calling the reticulate_splines method until either it returns a result
-# greater than 0 or 20 seconds elapses. In the timeout case an exception will be raised
-# saying "timed out waiting for splines to reticulate"
-
module WaitHelper
+ # Default option for how long (in seconds) to keep checking before timing out the entire wait
TIMEOUT = ENV['WAIT_TIMEOUT'].to_i || 240
- POLL_SLEEP = 0.1 #seconds
+ # How long to pause (in seconds) inbetween each spin through the assertion block
+ POLL_SLEEP = 0.1
+ # Repeatedly evaluate the passed in block until either it returns true or a timeout expires. Between
+ # evaluations there is a pause of {POLL_SLEEP} seconds.
+ #
+ # wait_until takes the following options:
+ # :timeout - How long in seconds to keep spinning before timing out of the entire operation. Defaults to TIMEOUT
+ # :message - What to raise in the event of a timeout. Defaults to an empty StandardError
+ #
+ # @yield the assertion to wait for
+ # @yieldreturn whether the assertion was met
+ #
+ #
+ # Here's an example where we will keep calling the reticulate_splines method until either it returns a result
+ # greater than 0 or 20 seconds elapses. In the timeout case an exception will be raised
+ # saying "timed out waiting for splines to reticulate":
+ #
+ # wait_until( :timeout => 20, :message => 'timed out waiting for splines to reticulate' ) do
+ # num_splines_reticulated = reticulate_splines(1,2,3)
+ # num_splines_reticulated > 0
+ # end
def wait_until(opts = {})
timeout = opts[:timeout] || TIMEOUT
message = opts[:message]
Please sign in to comment.
Something went wrong with that request. Please try again.