Module: Calabash::Cucumber::Core

Includes:
EnvironmentHelpers, FailureHelpers, KeyboardHelpers, QueryHelpers, StatusBarHelpers, UIA
Included in:
DatePicker, Operations, WaitHelpers
Defined in:
lib/calabash-cucumber/core.rb

Overview

A collection of methods that provide the core calabash behaviors.

Instance Method Summary collapse

Methods included from KeyboardHelpers

#docked_keyboard_visible?, #keyboard_visible?, #lookup_key_name, #split_keyboard_visible?, #undocked_keyboard_visible?, #wait_for_keyboard, #wait_for_no_keyboard

Methods included from StatusBarHelpers

#device_orientation, #landscape?, #portrait?, #status_bar_details, #status_bar_orientation

Methods included from UIA

#uia, #uia_call, #uia_call_windows, #uia_keyboard_visible?, #uia_names, #uia_orientation, #uia_query, #uia_query_windows, #uia_rotate, #uia_rotate_home_button_to, #uia_set_responder_value, #uia_wait_for_keyboard

Methods included from FailureHelpers

#fail, #screenshot, #screenshot_and_raise, #screenshot_embed

Methods included from QueryHelpers

#escape_backslashes, #escape_newlines, #escape_quotes, #escape_string

Methods included from EnvironmentHelpers

#default_device, #device_family_iphone?, #ios10?, #ios11?, #ios5?, #ios6?, #ios7?, #ios8?, #ios9?, #ios_gte_11?, #ios_version, #ipad?, #ipad_pro?, #iphone?, #iphone_35in?, #iphone_4in?, #iphone_6?, #iphone_6_plus?, #iphone_app_emulated_on_ipad?, #ipod?, #screen_dimensions, #simulator?, #uia_available?, #uia_not_available?, #xamarin_test_cloud?

Instance Method Details

#await_page(clz, *args) ⇒ Object

Instantiates a page using ‘page` and calls the page’s ‘await` method.

Examples:

Instantiating and waiting a ‘LoginPage` from a step definition

Given(/^I am about to login to a self-hosted site$/) do
    @current_page = await_page(LoginPage)
    @current_page.self_hosted_site
end

Parameters:

  • clz (Class)

    the page object class to instantiate (passing the cucumber world and ‘args`)

  • args (Array)

    optional additional arguments to pass to the page object constructor

Returns:

  • (Object)

    a fresh instance of ‘Class clz` which has been passed a reference to the cucumber World object. Calls await on the page object.

See Also:



1619
1620
1621
# File 'lib/calabash-cucumber/core.rb', line 1619

def await_page(clz,*args)
  clz.new(self,*args).await
end

#backdoor(selector, *arguments) ⇒ Object

Note:

For methods that take arguments, don’t forget to include the trailing “:”

Calls a method on the app’s AppDelegate object.

Use this to call an arbitrary Objective-C or Swift method in your app’s UIApplicationDelegate.

Commonly used to “go around” the UI speed purposes or reset the app to a good known state.

Parameters:

  • selector (String)

    the selector to perform on the app delegate

  • arguments (Object)

    the arguments to pass to the selector

Returns:

  • (Object)

    the result of performing the selector with the argument



1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
# File 'lib/calabash-cucumber/core.rb', line 1464

def backdoor(selector, *arguments)
  parameters = {
        :selector => selector,
        :arguments => arguments
  }

  begin
    body = http({:method => :post, :path => "backdoor"}, parameters)
    result = response_body_to_hash(body)
  rescue RuntimeError => e
    raise RuntimeError, e
  end

  if result["outcome"] != "SUCCESS"
     raise RuntimeError,
%Q{backdoor call failed:
 selector => '#{selector}'
arguments => '#{arguments}'
   reason => '#{result["reason"]}'

#{result["details"]}

}
  end
  result["results"]
end

#calabash_exit(opts = {}) ⇒ Object

TODO:

Shutdown the CalabashServer and close connections.

Attempts to shut the app down gracefully by simulating the transition to closed steps. The server will attempt to ensure that the following UIApplicationDelegate methods methods are called (in order).

“‘

- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationWillTerminate:(UIApplication *)application

“‘

Parameters:

  • opts (Hash) (defaults to: {})

    Options for controlling the app shutdown process.

Options Hash (opts):

  • :post_resign_active_delay (Float) — default: 0.4

    How long to wait after calling ‘application will resign active’ before calling ‘app will terminate’.

  • :post_will_terminate_delay (Float) — default: 0.4

    How long to wait after calling ‘application will resign active’ before calling ‘exit’.

  • :exit_code (Integer)

    What code should the application exit with? This exit code may or may not be used! If the UIApplication responds to ‘terminateWithSuccess`, then that method will be called. The exit code for `terminateWithSuccess` is undefined.



1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
# File 'lib/calabash-cucumber/core.rb', line 1512

def calabash_exit(opts={})
  default_opts = {:post_resign_active_delay => 0.4,
                  :post_will_terminate_delay => 0.4,
                  :exit_code => 0}
  merged_opts = default_opts.merge(opts)
  # Exiting the app shuts down the HTTP connection and generates ECONNREFUSED,
  # or HTTPClient::KeepAliveDisconnected
  # which needs to be suppressed.
  begin
    http({
               :method => :post,
               :path => 'exit',
               :retryable_errors => Calabash::Cucumber::HTTPHelpers::RETRYABLE_ERRORS - [Errno::ECONNREFUSED, HTTPClient::KeepAliveDisconnected]
         },  {
               :post_resign_active_delay => merged_opts[:post_resign_active_delay],
               :post_will_terminate_delay => merged_opts[:post_will_terminate_delay],
               :exit_code => merged_opts[:exit_code]
         }
    )

  rescue Errno::ECONNREFUSED, HTTPClient::KeepAliveDisconnected, SocketError
    []
  end

  if launcher.automator
    if launcher.automator.name == :device_agent
      delay = merged_opts[:post_resign_active_delay] +
        merged_opts[:post_will_terminate_delay] + 0.4
      sleep(delay)
      launcher.automator.send(:session_delete)
    end
  end
  true
end

#calabash_info(msg) ⇒ void

This method returns an undefined value.

Prints a green info message.

Parameters:

  • msg (String)

    the message to print



59
60
61
62
# File 'lib/calabash-cucumber/core.rb', line 59

def calabash_info(msg)
  require "run_loop/logging"
  RunLoop.log_info2(msg)
end

#calabash_warn(msg) ⇒ void

This method returns an undefined value.

Prints a blue warning message.

Parameters:

  • msg (String)

    the message to print



51
52
53
54
# File 'lib/calabash-cucumber/core.rb', line 51

def calabash_warn(msg)
  require "run_loop/logging"
  RunLoop.log_warn(msg)
end

#clear_text(uiquery) ⇒ Array<String>

Sets the text value of the views matched by uiquery to '' (the empty string)

Using this sparingly and with caution. We recommend using queries and touches to replicate what the _user would do_.

@raise If the uiquery finds no matching queries or finds a view that does not respond to the objc selector ‘setText’

Parameters:

  • uiquery (String)

    used to find the text input views

Returns:

  • (Array<String>)

    The text fields that were modified.



1724
1725
1726
1727
1728
1729
# File 'lib/calabash-cucumber/core.rb', line 1724

def clear_text(uiquery)
  views_modified = Map.map(uiquery, :setText, '')
  msg = "query '#{uiquery}' returned no matching views that respond to 'setText'"
  Map.assert_map_results(views_modified, msg)
  views_modified
end

#client_versionString

Returns the version of the loaded Calabash library.

Returns:

  • (String)

    the version of the loaded Calabash library.

See Also:



180
181
182
# File 'lib/calabash-cucumber/core.rb', line 180

def client_version
  Calabash::Cucumber::VERSION
end

#console_attach(uia_strategy = nil) ⇒ Calabash::Cucumber::Launcher?

Attach the current calabash launcher to a console.

Examples:

You have encountered a failing cucumber Scenario.
You open the console and want to start investigating the cause of the failure.

Use

> console_attach

to connect to the current launcher

Parameters:

  • uia_strategy (Symbol) (defaults to: nil)

    Optionally specify the uia strategy, which can be one of :shared_element, :preferences, :host. If you don’t know which to choose, don’t specify one and calabash will try deduce the correct strategy to use based on the environment variables used when starting the console.

Returns:

Raises:

  • (RuntimeError)

    This method is not available on the Xamarin Test Cloud



1807
1808
1809
1810
1811
1812
# File 'lib/calabash-cucumber/core.rb', line 1807

def console_attach(uia_strategy = nil)
  if Calabash::Cucumber::Environment.xtc?
    raise "This method is not available on the Xamarin Test Cloud"
  end
  launcher.attach({:uia_strategy => uia_strategy})
end

#deprecated(version, msg, type) ⇒ void

This method returns an undefined value.

Prints a deprecated message that includes the line number.

Parameters:

  • version (String)

    indicates when the feature was deprecated

  • msg (String)

    deprecation message (possibly suggesting alternatives)

  • type (Symbol)

    { :warn | :pending } - :pending will raise a cucumber pending error



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/calabash-cucumber/core.rb', line 71

def deprecated(version, msg, type)
  allowed = [:pending, :warn]
  unless allowed.include?(type)
    raise ArgumentError, "Expected type '#{type}' to be one of #{allowed.join(", ")}"
  end

  stack = Kernel.caller(0, 6)[1..-1].join("\n")

  msg = "deprecated '#{version}' - #{msg}\n#{stack}"

  if type.eql?(:pending)
    pending(msg)
  else
    calabash_warn(msg)
  end
end

#device_agentCalabash::Cucumber::DeviceAgent

Returns an object that provides an interface to the DeviceAgent public query and gesture API.

Examples:

device_agent.query({marked: "Cancel"})
device_agent.touch({marked: "Cancel"})

Returns:

Raises:

  • (RuntimeError)

    If the application has not been launched.

  • (RuntimeError)

    If there is no automator attached to the current launcher

  • (RuntimeError)

    If the automator attached the current launcher is not DeviceAgent

  • (RuntimeError)

    If the automator is not running.

See Also:



1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
# File 'lib/calabash-cucumber/core.rb', line 1831

def device_agent
  launcher = Calabash::Cucumber::Launcher.launcher_if_used
  if !launcher
    raise RuntimeError, %Q[
There is no launcher.

If you are in the Calabash console, you can try to attach to an already running
Calabash test using:

> console_attach

If you are running from Cucumber or rspec, call Launcher#relaunch before calling
this method.

]
  end

  if !launcher.automator
    raise RuntimeError, %Q[
The launcher is not attached to an automator.

If you are in the Calabash console, you can try to attach to an already running
Calabash test using:

> console_attach

If you are running from Cucumber or rspec, call Launcher#relaunch before calling
this method.

]
  end

  if launcher.automator.name != :device_agent
    raise RuntimeError, %Q[
The launcher automator is not DeviceAgent:

#{launcher.automator}

#device_agent is only available for Xcode 8.

In your tests, use this pattern to branch on the availability of DeviceAgent.

if uia_available?
   # Make a UIA call
else
   # Make a DeviceAgent call
end

]
  end
  automator = launcher.automator

  if !automator.running?
    raise RuntimeError, %Q[The DeviceAgent is not running.]
  else
    require "calabash-cucumber/device_agent"
    Calabash::Cucumber::DeviceAgent.new(automator.client, self)
  end
end

#dismiss_ipad_keyboardObject

Note:

The dismiss keyboard key does not exist on the iPhone or iPod

Dismisses a iPad keyboard by touching the ‘Hide keyboard’ button and waits for the keyboard to disappear.

Raises:



824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
# File 'lib/calabash-cucumber/core.rb', line 824

def dismiss_ipad_keyboard
  # TODO Maybe relax this restriction; turn it into a nop on iPhones?
  # TODO Support iPhone 6 Plus form factor dismiss keyboard key.
  if device_family_iphone?
    screenshot_and_raise %Q[
There is no Hide Keyboard key on an iPhone.

Use `ipad?` to branch in your test.

]
  end

  expect_keyboard_visible!

  launcher.automator.dismiss_ipad_keyboard

  wait_for_no_keyboard
end

#double_tap(uiquery, options = {}) ⇒ Array<Hash>

Note:

This assumes the view is visible and not animating.

Performs the “double tap” gesture on the (first) view that matches query ‘uiquery`.

If the view is not visible it will fail with an error. If the view is animating it will silently fail.

By default, taps the center of the view.

Examples:

double_tap "view marked:'Third'", offset:{x:100}

Parameters:

  • uiquery (String)

    query describing view to touch.

  • options (Hash) (defaults to: {})

    option for modifying the details of the touch

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the touch to be offset with `(x,y)` relative to the center (`center + (offset, offset)`).

Returns:

  • (Array<Hash>)

    array containing the serialized version of the tapped view.



319
320
321
# File 'lib/calabash-cucumber/core.rb', line 319

def double_tap(uiquery, options={})
  query_action_with_options(:double_tap, uiquery, options)
end

#flash(uiquery, *args) ⇒ Array

Causes all views matched by the ‘uiquery` to briefly change colors making them visually identifiable.

Parameters:

  • uiquery (String)

    a query specifying which objects to flash

  • args (Array)

    argument is ignored and should be deprecated

Returns:

  • (Array)

    an array of that contains all the view matched.



165
166
167
168
169
# File 'lib/calabash-cucumber/core.rb', line 165

def flash(uiquery, *args)
  # todo deprecate the *args argument in the flash method
  # todo :flash operation should return views as JSON objects
  Map.map(uiquery, :flash, *args).compact
end

#flick(uiquery, delta, options = {}) ⇒ Array<Hash>

Performs the “flick” gesture on the first view that matches ‘uiquery`.

If the view is not visible it will fail with an error.

If the view is animating it will silently fail.

By default, the gesture starts at the center of the view and “flicks” according to ‘delta`.

A flick is a swipe with velocity.

Examples:

# Flick left: move screen to the right
delta = {:x => -124.0, :y => 0.0}

# Flick right: move screen to the left
delta = {:x => 124.0, :y => 0.0}

# Flick up: move screen to the bottom
delta = {:x => 0, :y => -124.0}

# Flick down: move screen to the top
delta = {:x => 0, :y => 124.0}

# Flick up and to the left: move the screen to the lower right corner
delta = {:x => -88, :y => -88}

flick("MKMapView", delta)

Parameters:

  • uiquery (String)

    query describing view to flick.

  • delta (Hash)

    coordinate describing the direction to flick

  • options (Hash) (defaults to: {})

    option for modifying the details of the flick.

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the first touch to be offset with `(x,y)` relative to the center.

Returns:

  • (Array<Hash>)

    array containing the serialized version of the touched view.

Raises:

  • (ArgumentError)

    If query is nil.



463
464
465
466
467
468
469
470
471
472
473
# File 'lib/calabash-cucumber/core.rb', line 463

def flick(uiquery, delta, options={})
  if uiquery.nil?
    raise ArgumentError, "Query argument cannot be nil"
  end

  merged_options = {
    :delta => delta
  }.merge(options)

  query_action_with_options(:flick, uiquery, merged_options)
end

#html(q) ⇒ Array<String>

returns the ‘html’ property of all objects matching the query ‘q`

Parameters:

  • q (String)

    the query to execute (should be a webView query)

Returns:

  • (Array<String>)

    array containing html of all elements matching the query



1659
1660
1661
# File 'lib/calabash-cucumber/core.rb', line 1659

def html(q)
  query(q).map { |e| e['html'] }
end

#identifier(uiquery) ⇒ Array<String>

Returns all accessibilityIdentifiers of objects matching ‘uiquery`.

Parameters:

  • uiquery (String)

    query to match

Returns:

  • (Array<String>)

    Returns all accessibilityIdentifiers of objects matching ‘uiquery`.



1638
1639
1640
# File 'lib/calabash-cucumber/core.rb', line 1638

def identifier(uiquery)
  query(uiquery, :accessibilityIdentifier)
end

#keyboard_enter_char(char, options = {}) ⇒ Object

Deprecated.

0.21.0 Use #keyboard_enter_text

Note:

There are several special ‘characters’, some of which do not appear on all keyboards; e.g. ‘Delete`, `Return`.

Use keyboard to enter a character.

Parameters:

  • char (String)

    The character to type

  • options (Hash) (defaults to: {})

    Controls the behavior of the method.

  • opts (Hash)

    a customizable set of options

Raises:

  • (RuntimeError)

    If there is no visible keyboard

  • (RuntimeError)

    If the keyboard (layout) is not supported

See Also:



679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
# File 'lib/calabash-cucumber/core.rb', line 679

def keyboard_enter_char(char, options={})
  expect_keyboard_visible!

  default_opts = {:wait_after_char => 0.05}
  merged_options = default_opts.merge(options)

  special_char = launcher.automator.char_for_keyboard_action(char)

  if special_char
    launcher.automator.enter_char_with_keyboard(special_char)
  elsif char.length == 1
    launcher.automator.enter_char_with_keyboard(char)
  else
    raise ArgumentError, %Q[
Expected '#{char}' to be a single character or a special string like:

* Return
* Delete

To type strings with more than one character, use keyboard_enter_text.
]
  end

  duration = merged_options[:wait_after_char]
  if duration > 0
    Kernel.sleep(duration)
  end

  []
end

#keyboard_enter_text(text) ⇒ Object

Uses the keyboard to enter text.

Parameters:

  • text (String)

    the text to type.

Raises:

  • (RuntimeError)

    If the keyboard is not visible.



742
743
744
745
746
747
# File 'lib/calabash-cucumber/core.rb', line 742

def keyboard_enter_text(text)
  expect_keyboard_visible!
  existing_text = text_from_first_responder
  escaped = existing_text.gsub("\n","\\n")
  launcher.automator.enter_text_with_keyboard(text, escaped)
end

#label(uiquery) ⇒ Array<String>

Returns all accessibilityLabels of objects matching ‘uiquery`.

Parameters:

  • uiquery (String)

    query to match

Returns:

  • (Array<String>)

    Returns all accessibilityLabels of objects matching ‘uiquery`.



1631
1632
1633
# File 'lib/calabash-cucumber/core.rb', line 1631

def label(uiquery)
  query(uiquery, :accessibilityLabel)
end

#location_for_place(place) ⇒ Geocoder::Result::Google

Returns a geo-location search result (via Google). Requires internet.

Parameters:

  • place (String)

    a description of the place to search for

Returns:

  • (Geocoder::Result::Google)

    result of the search - see /.



1371
1372
1373
1374
1375
# File 'lib/calabash-cucumber/core.rb', line 1371

def location_for_place(place)
  search_results = locations_for_place(place)
  raise "Got no results for #{place}" if search_results.empty?
  search_results.first
end

#page(clz, *args) ⇒ Object

Helper method to easily create page object instances from a cucumber execution context.

The advantage of using ‘page` to instantiate a page object class is that it will automatically store a reference to the current Cucumber world which is needed in the page object methods to call Cucumber-specific methods like puts or embed.

Examples:

Instantiating a ‘LoginPage` from a step definition

Given(/^I am about to login to a self-hosted site$/) do
    @current_page = page(LoginPage).await(timeout: 30)
    @current_page.self_hosted_site
end

Parameters:

  • clz (Class)

    the page object class to instantiate (passing the Cucumber world and ‘args`)

  • args (Array)

    optional additional arguments to pass to the page object constructor

Returns:

  • (Object)

    a fresh instance of ‘Class clz` which has been passed a reference to the cucumber World object.

See Also:



1601
1602
1603
# File 'lib/calabash-cucumber/core.rb', line 1601

def page(clz,*args)
  clz.new(self,*args)
end

#pan(from_query, to_query, options = {}) ⇒ Array<Hash>

Performs the pan gesture between two coordinates.

Swipes, scrolls, drag-and-drop, and flicks are all pan gestures.

Examples:

# Reorder table view rows.
q1="* marked:'Reorder Apple'"
q2="* marked:'Reorder Google'"
pan q1, q2, duration:4

Parameters:

  • from_query (String)

    query describing view to start the gesture

  • to_query (String)

    query describing view to end the gesture

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the pan to be offset with `(x,y)` relative to the center.

  • :duration (Numeric) — default: 1.0

    duration of the ‘pan’. The minimum value of pan in UIAutomation is 0.5. For DeviceAgent, the duration must be > 0.

  • :first_touch_hold_duration (Numeric) — default: 0.0

    How long the first touch holds before starting the pan. Only available for iOS 9 or greater (requires DeviceAgent)

Returns:

  • (Array<Hash>)

    array containing the serialized version of the touched views. The first element is the first view matched by the from_query and the second element is the first view matched by the to_query.

Raises:

  • (ArgumentError)

    If duration is < 0.5 for UIAutomation and <= 0 for DeviceAgent.



503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/calabash-cucumber/core.rb', line 503

def pan(from_query, to_query, options={})
  merged_options = {
    # Minimum value for UIAutomation is 0.5.
    # DeviceAgent duration must be > 0.
    :duration => 1.0
  }.merge(options)

  duration = merged_options[:duration]

  if uia_available? && duration < 0.5
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.5

]
  elsif duration <= 0.0
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.0.

]
  end

  # TODO validate first_touch_hold_duration

  launcher.automator.pan(from_query, to_query, merged_options)
end

#pan_coordinates(from_point, to_point, options = {}) ⇒ Object

Performs the pan gesture between two coordinates.

Swipes, scrolls, drag-and-drop, and flicks are all pan gestures.

Examples:

# Pan to go back in UINavigationController
element = query("*").first
y = element["rect"]["center_y"]
pan_coordinates({10, y}, {160, y})

# Pan to reveal Today and Notifications
element = query("*").first
x = element["rect"]["center_x"]
pan_coordinates({x, 0}, {x, 240})

# Pan to reveal Control Panel
element = query("*").first
x = element["rect"]["center_x"]
y = element["rect"]["height"]
pan_coordinates({x, height}, {x, 240})

Parameters:

  • from_point (Hash)

    where to start the pan.

  • to_point (Hash)

    where to end the pan.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :duration (Numeric) — default: 1.0

    duration of the ‘pan’. The minimum value of pan in UIAutomation is 0.5. For DeviceAgent, the duration must be > 0.

  • :first_touch_hold_duration (Numeric) — default: 0.0

    How long the first touch holds before starting the pan. Only available for iOS 9 or greater (requires DeviceAgent).

Raises:

  • (ArgumentError)

    If duration is < 0.5 for UIAutomation and <= 0 for DeviceAgent.



565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# File 'lib/calabash-cucumber/core.rb', line 565

def pan_coordinates(from_point, to_point, options={})
  merged_options = {
    # Minimum value for UIAutomation is 0.5.
    # DeviceAgent duration must be > 0.
    :duration => 1.0
  }.merge(options)

  duration = merged_options[:duration]

  if uia_available? && duration < 0.5
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.5

]
  elsif duration <= 0.0
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.0.

]
  end

  # TODO validate first_touch_hold_duration

  launcher.automator.pan_coordinates(from_point, to_point, merged_options)
end

#pinch(in_out, options = {}) ⇒ Array<Hash>

Performs a “pinch” gesture.

By default, the gesture starts at the center of the screen.

Examples:

# Zoom in
pinch :out

# Zoom out
pinch :in, query:"MKMapView", offset:{x:42}

Parameters:

  • in_out (String, Symbol)

    the direction to pinch (‘in’ or ‘out’)

  • options (Hash) (defaults to: {})

    option for modifying the details of the touch.

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point.

  • :query (String) — default: nil

    The view to pinch on. If this value is nil, the pinch happens at the center of the screen.

  • :amount (Numeric) — default: 100

    How large (in points) the pinch should be. This option is ignored when running with UIAutomation.

  • :duration (Numeric) — default: 1.0

    duration of the ‘pinch’. The minimum value of pan in UIAutomation is 0.5. For DeviceAgent, the duration must be > 0.

Returns:

  • (Array<Hash>)

    array containing the serialized version of the view touched.

Raises:

  • (ArgumentError)

    If duration is < 0.5 for UIAutomation and <= 0 for DeviceAgent.

  • (ArgumentError)

    If in_out argument is invalid.



622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/calabash-cucumber/core.rb', line 622

def pinch(in_out, options={})
  merged_options = {
    :query => nil,
    # Ignored by UIAutomation
    :amount => 100,
    :duration => 0.5
  }.merge(options)

  symbol = in_out.to_sym

  if ![:in, :out].include?(symbol)
    raise ArgumentError, %Q[
Invalid pinch direction: '#{symbol}'.  Valid directions are:

"in", "out", :in, :out

]
  end

  duration = merged_options[:duration]

  if uia_available? && duration < 0.5
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.5

]
  elsif duration <= 0.0
    raise ArgumentError, %Q[
Invalid duration: #{duration}

The minimum duration is 0.0.

]
  end

  launcher.automator.pinch(in_out.to_sym, merged_options)
end

#query(uiquery, *args) ⇒ Object

The core method for querying into the current visible view of the app under test. The query method takes as first parameter a String ‘:uiquery`. This string must follow the query syntax described in: / Query Syntax.

Optionally ‘query` takes a variable number of “invocation” arguments (`args` below). # If called with an empty list of `*args`, `query` will find the views specified by `uiquery` and return a serialized view (see Examples below).

If ‘*args` are given, then they should describe a valid selector invocation on the queried views. For example `query(’UILabel’, :text)‘ would perform the `:text` selector on all visible `UILabel` objects and return those as an Array of Strings.

The ‘query` method provide a powerful mechanism for `querying` app view state and can be used to reflectively call arbitrary methods on objects reachable from the view. For a full specification of `*args` see / Query Syntax.

Examples:

Basic view query

irb(main):009:0> query("UITabBarButton index:0")
[
    [0] {
          "class" => "UITabBarButton",
    "id" => nil,
    "rect" => {
        "center_x" => 40,
        "y" => 520,
        "width" => 76,
        "x" => 2,
        "center_y" => 544,
        "height" => 48
   },
    "frame" => {
        "y" => 1,
        "width" => 76,
        "x" => 2,
        "height" => 48
    },
    "label" => "Reader",
    "description" => "<UITabBarButton: 0xdabb510; frame = (2 1; 76 48); opaque = NO; layer = <CALayer: 0xdabd8e0>>"
  }
]

Simple selector

irb(main):010:0> query("UILabel", :text)
[
    [0] "The Ugly Volvo",
    [1] "Why Having a Baby Reminds me of Garfield Minus Garfield",
    [2] "I love the site Garfield Minus Garfield. If you don’t know the site Garfield minus Garfield  it’s a website run by a guy named Dan Walsh who takes Garfield comic strips and digitally erases Garfield from them.   more",
    [3] "Freshly Pressed",
    [4] "Reader",
    [5] "Notifications",
    [6] "Me"
]

Parameters:

  • uiquery (String)

    the query to perform. Must follow the query syntax: / Query Syntax.

  • args (Array)

    optional var-args list describing a chain of method selectors. Full details / Query Syntax.



148
149
150
# File 'lib/calabash-cucumber/core.rb', line 148

def query(uiquery, *args)
  Map.map(uiquery, :query, *args)
end

#rotate(direction) ⇒ Symbol

Rotates the device in the direction indicated by ‘direction`.

Examples:

rotate left

rotate :left

rotate right

rotate :right

Parameters:

  • direction (Symbol)

    The direction to rotate. Can be :left or :right.

Returns:

  • (Symbol)

    The position of the home button relative to the status bar after the rotation. Will be one of ‘{:down | :left | :right | :up }`.

Raises:

  • (ArgumentError)

    If direction is not :left or :right.



241
242
243
244
245
246
247
248
249
250
# File 'lib/calabash-cucumber/core.rb', line 241

def rotate(direction)
  as_symbol = direction.to_sym

  if as_symbol != :left && as_symbol != :right
    raise ArgumentError,
          "Expected '#{direction}' to be :left or :right"
  end

  launcher.automator.send(:rotate, as_symbol)
end

#rotate_home_button_to(position) ⇒ Symbol

Note:

A rotation will only occur if your view controller and application support the target orientation.

Rotates the home button to a position relative to the status bar.

Refer to Apple’s documentation for clarification about left vs. right landscape orientations.

For legacy support the ‘dir` argument can be a String or Symbol. Please update your code to pass a Symbol.

For legacy support ‘:top` and `top` are synonyms for `:up`. Please update your code to pass `:up`.

For legacy support ‘:bottom` and `bottom` are synonyms for `:down`. Please update your code to pass `:down`.

Examples:

portrait

rotate_home_button_to :down

upside down

rotate_home_button_to :up

landscape with left home button AKA: right landscape

rotate_home_button_to :left

landscape with right home button AKA: left landscape

rotate_home_button_to :right

Parameters:

  • position (Symbol)

    The position of the home button after the rotation. Can be one of ‘{:down | :left | :right | :up }`.

Returns:

  • (Symbol)

    The position of the home button relative to the status bar when all rotations have been completed.



218
219
220
221
222
223
224
225
226
# File 'lib/calabash-cucumber/core.rb', line 218

def rotate_home_button_to(position)

  normalized_symbol = expect_valid_rotate_home_to_arg(position)
  current_orientation = status_bar_orientation.to_sym

  return current_orientation if current_orientation == normalized_symbol

  launcher.automator.send(:rotate_home_button_to, normalized_symbol)
end

#scroll(uiquery, direction) ⇒ Object

Note:

this is implemented by calling the Obj-C ‘setContentOffset:animated:` method and can do things users cant.

Scroll a scroll view in a direction. By default scrolls half the frame size.

Examples:

scroll("UITableView", :down)

Parameters:

  • uiquery (String)

    query describing view scroll (should be UIScrollView or a web view).

  • direction (Symbol)

    The direction to scroll. Valid directions are: :up, :down, :left, and :right



851
852
853
854
855
856
857
858
859
860
861
862
# File 'lib/calabash-cucumber/core.rb', line 851

def scroll(uiquery, direction)
  allowed_directions = [:up, :down, :left, :right]
  dir_symbol = direction.to_sym
  unless allowed_directions.include?(dir_symbol)
    raise ArgumentError, "Expected '#{direction} to be one of #{allowed_directions}"
  end

  views_touched = Map.map(uiquery, :scroll, dir_symbol)
  msg = "could not find view to scroll: '#{uiquery}', args: #{dir_symbol}"
  Map.assert_map_results(views_touched, msg)
  views_touched
end

#scroll_to_cell(options = {:query => "UITableView index:0", :row => 0, :section => 0, :scroll_position => :top, :animate => true}) ⇒ Object

TODO:

should expose a non-option first argument query and required parameters ‘section`, `row`

Scroll a table view to a section and row.

Make sure your query matches exactly one UITableView. If multiple views are matched, the results can be unpredictable.

Examples:

scroll_to_cell  row:4, section:0, animate: false

Parameters:

  • options (Hash) (defaults to: {:query => "UITableView index:0", :row => 0, :section => 0, :scroll_position => :top, :animate => true})

    specifies details of the scroll

Options Hash (options):

  • :query (String) — default: "UITableView index:0"

    query specifying which table view to scroll

  • :section (Fixnum)

    section to scroll to

  • :row (Fixnum)

    row to scroll to

  • :scroll_position (String)

    position to scroll to

  • :animated (Boolean) — default: true

    animate or not

Raises:

  • (ArgumentError)

    If row or section is nil

  • (ArgumentError)

    If the :query value is nil, “”, or “*”.

See Also:



968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
# File 'lib/calabash-cucumber/core.rb', line 968

def scroll_to_cell(options={:query => "UITableView index:0",
                            :row => 0,
                            :section => 0,
                            :scroll_position => :top,
                            :animate => true})
  uiquery = options[:query] || 'tableView'
  row = options[:row]
  sec = options[:section]
  if row.nil? || sec.nil?
    raise ArgumentError, 'You must supply both :row and :section keys to scroll_to_cell'
  end

  args = []
  if options.has_key?(:scroll_position)
    args << options[:scroll_position]
  else
    args << 'top'
  end
  if options.has_key?(:animate)
    args << options[:animate]
  end
  views_touched = Map.map(uiquery, :scrollToRow, row.to_i, sec.to_i, *args)
  msg = "unable to scroll: '#{uiquery}' to '#{options}'"
  Map.assert_map_results(views_touched, msg)
  views_touched
end

#scroll_to_collection_view_item(item_index, section_index, options = {}) ⇒ Object

Note:

item and section are zero-indexed

Scrolls to an item in a section of a UICollectionView.

Make sure your query matches exactly one UICollectionView. If multiple views are matched, the results can be unpredictable.

Examples:

Scroll to item 0 in section 2 to top.

scroll_to_collection_view_item(0, 2, {:scroll_position => :top})

Scroll to item 5 in section 0 to bottom.

scroll_to_collection_view_item(5, 0, {:scroll_position => :bottom})

The following are the allowed :scroll_position values.

{:top | :center_vertical | :bottom | :left | :center_horizontal | :right}

Parameters:

  • item_index (Integer)

    the index of the item to scroll to. Must be >= 0.

  • section_index (Integer)

    the section of the item to scroll to. Must be > 0.

  • options (Hash) (defaults to: {})

    options for controlling the collection view query and scroll behavior

  • opts (Hash)

    a customizable set of options

Raises:

  • (RuntimeError)

    if the scroll cannot be performed

  • (RuntimeError)

    :query finds no collection view

  • (RuntimeError)

    the collection view does not contain a cell at item/section

  • (ArgumentError)

    :scroll_position is invalid

  • (ArgumentError)

    item or section is < 0.

  • (ArgumentError)

    If the :query value is nil, “”, or “*”.



1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
# File 'lib/calabash-cucumber/core.rb', line 1109

def scroll_to_collection_view_item(item_index, section_index, options={})
  default_options = {:query => "UICollectionView index:0",
                     :scroll_position => :top,
                     :animate => true,
                     :failure_message => nil}
  merged_options = default_options.merge(options)
  uiquery = merged_options[:query]

  if uiquery.nil?
    raise ArgumentError, "The :query option cannot be nil"
  end

  if uiquery == ""
    raise ArgumentError, "The :query option cannot be the empty string"
  end

  if uiquery == "*"
    raise ArgumentError, "The :query option cannot be the wildcard '*'"
  end

  if item_index < 0
    raise ArgumentError, "Invalid item index: '#{item_index}' - must be >= 0"
  end

  if section_index < 0
    raise ArgumentError, "Invalid section index: '#{section_index}' - must be >= 0"
  end

  scroll_position = merged_options[:scroll_position]
  candidates = [:top, :center_vertical, :bottom, :left, :center_horizontal, :right]
  if !candidates.include?(scroll_position)
    raise ArgumentError, %Q[

Invalid :scroll_position option '#{scroll_position}'.  Valid options are:

#{candidates.join(", ")}

    ]
  end

  animate = merged_options[:animate]

  views_touched = Map.map(uiquery, :collectionViewScroll,
                          item_index.to_i, section_index.to_i,
                          scroll_position, animate)

  message = merged_options[:failure_message]
  if !message
    message = %Q[
Unable to scroll to item index '#{item_index}' in section index '#{section_index}'
in CollectionView matched by:

#{uiquery}

with options:

#{merged_options}

]
  end

  Map.assert_map_results(views_touched, message)
  views_touched
end

#scroll_to_collection_view_item_with_mark(mark, options = {}) ⇒ Object

Scrolls to mark in a UICollectionView.

Make sure your query matches exactly one UICollectionView. If multiple views are matched, the results can be unpredictable.

Examples:

Scroll to the top of the item with the given mark.

scroll_to_collection_view_item_with_mark('cat', {:scroll_position => :top})

Scroll to the bottom of the item with the given mark.

scroll_to_collection_view_item_with_mark('dog', {:scroll_position => :bottom})

The following are the allowed :scroll_position values.

{:top | :center_vertical | :bottom | :left | :center_horizontal | :right}

Parameters:

  • mark (String)

    an accessibility ‘| identifier` or text in or on the item

  • options (Hash) (defaults to: {})

    options for controlling the collection view query and scroll behavior

  • opts (Hash)

    a customizable set of options

Raises:

  • (RuntimeError)

    if the scroll cannot be performed

  • (RuntimeError)

    :query finds no collection view

  • (RuntimeError)

    the collection view does not contain a cell with the mark

  • (RuntimeError)

    :scroll_position is invalid

  • (ArgumentError)

    If the :query value is nil, “”, or “*”.

  • (ArgumentError)

    if the mark is nil



1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
# File 'lib/calabash-cucumber/core.rb', line 1210

def scroll_to_collection_view_item_with_mark(mark, options={})
  default_options = {:query => "UICollectionView index:0",
                     :scroll_position => :top,
                     :animate => true,
                     :failure_message => nil}
  merged_options = default_options.merge(options)
  uiquery = merged_options[:query]

  if mark.nil?
    raise ArgumentError, "The mark cannot be nil"
  end

  if uiquery.nil?
    raise ArgumentError, "The :query option cannot be nil"
  end

  if uiquery == ""
    raise ArgumentError, "The :query option cannot be the empty string"
  end

  if uiquery == "*"
    raise ArgumentError, "The :query option cannot be the wildcard '*'"
  end

  scroll_position = merged_options[:scroll_position]
  candidates = [:top, :center_vertical, :bottom, :left, :center_horizontal, :right]
  if !candidates.include?(scroll_position)
    raise ArgumentError, %Q[

Invalid :scroll_position option '#{scroll_position}'.  Valid options are:

#{candidates.join(", ")}

    ]
  end

  args = [scroll_position, merged_options[:animate]]

  views_touched = Map.map(uiquery,
                          :collectionViewScrollToItemWithMark,
                          mark, *args)

  message = merged_options[:failure_message]
  if !message
    message = %Q[
Unable to scroll to item with mark '#{mark}' in UICollectionView matching query:

#{uiquery}

with options:

#{merged_options}

]
  end

  Map.assert_map_results(views_touched, message)
  views_touched
end

#scroll_to_mark(mark, options = {}) ⇒ Object

Scrolls to a mark in a UIScrollView.

Make sure your query matches exactly one UIScrollView. If multiple scroll views are matched, the results can be unpredictable.

Examples:

scroll_to_mark("settings")
scroll_to_mark("Android", {:animated => false})
scroll_to_mark("Alarm", {:query => "UIScrollView marked:'Settings'"})

Parameters:

  • mark (String)

    an accessibility label or identifier or text

  • options (Hash) (defaults to: {})

    controls the query and and scroll behavior

Options Hash (options):

  • :query (String) — default: "UIScrollView index:0"

    A query to uniquely identify the scroll view if there are multiple scroll views.

  • :animate (Boolean) — default: true

    should the scrolling be animated

  • :failure_message (String) — default: nil

    If nil, a default failure message will be shown if this scroll scroll cannot be performed.

Raises:

  • (RuntimeError)

    If the scroll cannot be performed

  • (RuntimeError)

    If the :query finds no scroll view

  • (ArgumentError)

    If the mark is nil

  • (ArgumentError)

    If the :query value is nil, “”, or “*”.

See Also:



889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# File 'lib/calabash-cucumber/core.rb', line 889

def scroll_to_mark(mark, options={})
  if mark.nil?
    raise ArgumentError, "The mark cannot be nil"
  end

  merged_options = {:query => "UIScrollView index:0",
                    :animate => true,
                    :failure_message => nil}.merge(options)

  uiquery = merged_options[:query]

  if uiquery.nil?
    raise ArgumentError, "The :query option cannot be nil"
  end

  if uiquery == ""
    raise ArgumentError, "The :query option cannot be the empty string"
  end

  if uiquery == "*"
    raise ArgumentError, "The :query option cannot be the wildcard '*'"
  end

  args = [merged_options[:animate]]

  views_touched = Map.map(uiquery, :scrollToMark, mark, *args)

  message = merged_options[:failure_message]

  if !message
    message = %Q[

Unable to scroll to mark '#{mark}' in UIScrollView matching #{uiquery}"

]
  end

  Map.assert_map_results(views_touched, message)
  views_touched
end

#scroll_to_row(uiquery, number) ⇒ Object

Scroll a table view to a row. Table view should have only one section.

Make sure your query matches exactly one UITableView. If multiple views are matched, the results can be unpredictable.

Examples:

scroll_to_row "UITableView index:0", 2

Parameters:

  • uiquery (String)

    Should match a UITableView

See Also:



941
942
943
944
945
946
# File 'lib/calabash-cucumber/core.rb', line 941

def scroll_to_row(uiquery, number)
  views_touched = Map.map(uiquery, :scrollToRow, number)
  msg = "Unable to scroll to row #{number} in table view with '#{uiquery}'"
  Map.assert_map_results(views_touched, msg)
  views_touched
end

#scroll_to_row_with_mark(mark, options = {}) ⇒ Object

Scrolls to a mark in a UITableView.

Make sure your query matches exactly one UITableView. If multiple views are matched, the results can be unpredictable.

Examples:

Scroll to the top of the item with the given mark.

scroll_to_row_with_mark('settings', {:scroll_position => :top})

Scroll to the bottom of the item with the given mark.

scroll_to_row_with_mark('about', {:scroll_position => :bottom})

Parameters:

  • mark (String)

    an accessibility label or identifier or text in row

  • options (Hash) (defaults to: {})

    controls the query and and scroll behavior

Options Hash (options):

  • :query (String) — default: 'tableView'

    the query that should be used to location the table

  • :scroll_position (Symbol) — default: :middle

    the table position to scroll the row to - allowed values ‘| :top | :bottom`

  • :animate (Boolean) — default: true

    should the scrolling be animated

  • :failure_message (String) — default: nil

    If nil, a default failure message will be shown if this scroll scroll cannot be performed.

Raises:

  • (RuntimeError)

    if the scroll cannot be performed

  • (RuntimeError)

    if the table query finds no table view

  • (RuntimeError)

    if the scroll position is invalid

  • (ArgumentError)

    if the mark is nil

  • (ArgumentError)

    If the :query value is nil, “”, or “*”.



1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
# File 'lib/calabash-cucumber/core.rb', line 1024

def scroll_to_row_with_mark(mark, options={})
  merged_options = {:query => "UITableView index:0",
                    :scroll_position => :middle,
                    :animate => true,
                    :failure_message => nil}.merge(options)

  if mark.nil?
    raise ArgumentError, "The mark cannot be nil"
  end

  uiquery = merged_options[:query]

  if uiquery.nil?
    raise ArgumentError, "The :query option cannot be nil"
  end

  if uiquery == ""
    raise ArgumentError, "The :query option cannot be the empty string"
  end

  if uiquery == "*"
    raise ArgumentError, "The :query option cannot be the wildcard '*'"
  end

  args = [merged_options[:scroll_position], merged_options[:animate]]

  views_touched = Map.map(uiquery, :scrollToRowWithMark, mark, *args)

  message = merged_options[:failure_message]
  if !message
    message = %Q[
Unable to scroll to mark: '#{mark}' in table view matched by query:

#{uiquery}

with options:

#{merged_options}

]
  end
  Map.assert_map_results(views_touched, message)
  views_touched
end

#send_app_to_background(seconds) ⇒ Object

Sends the app to the background.

Sending the app to the background for more than 60 seconds may cause unpredictable results.

Parameters:

  • seconds (Numeric)

    How long to send the app to the background.

Raises:

  • (ArgumentError)

    if ‘seconds` argument is < 1.0



1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
# File 'lib/calabash-cucumber/core.rb', line 1277

def send_app_to_background(seconds)
  if seconds < 1.0
    raise ArgumentError, "Seconds '#{seconds}' must be >= 1.0"
  end

  parameters = {
    :duration => seconds
  }

  begin
    body = http({:method => :post, :path => "suspend"}, parameters)
    result = response_body_to_hash(body)
  rescue RuntimeError => e
    raise RuntimeError, e
  end

  if result["outcome"] != "SUCCESS"
    raise RuntimeError,
      %Q{Could not send app to background:
 reason => '#{result["reason"]}'
details => '#{result["details"]}'
      }
  end
  result["results"]
end

#server_log_levelString

Get the Calabash server log level.

Returns:

  • (String)

    the current log level



1549
1550
1551
# File 'lib/calabash-cucumber/core.rb', line 1549

def server_log_level
  _debug_level_response(http(:method => :get, :path => 'debug'))
end

#server_versionString

Returns the version of the running calabash server.

Returns:

  • (String)

    version of the running calabash server.



173
174
175
# File 'lib/calabash-cucumber/core.rb', line 173

def server_version
  JSON.parse(http(:path => 'version'))
end

#set_location(options) ⇒ Object

Note:

Seems UIAutomation is broken here on physical devices on iOS 7.1

Simulates gps location of the device/simulator.

Examples:

set_location place:'Tower of London'

Parameters:

  • options (Hash)

    specifies which location to simulate

Options Hash (options):

  • :place (String)

    a description of a place (resolved via Google maps api), e.g. “Tower of London”

  • :latitude (Numeric)

    latitude of a gps coordinate (same coordinate system as Google maps)

  • :longitude (Numeric)

    longitude of a gps coordinate (same coordinate system as Google maps)



1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
# File 'lib/calabash-cucumber/core.rb', line 1341

def set_location(options)
  if uia_available?
    uia_set_location(options)
  else
    if options[:place]
      res = location_for_place(options[:place])
      lat = res.latitude
      lon = res.longitude
    else
      lat = options[:latitude]
      lon = options[:longitude]
    end
    body_data = {:action => :change_location,
                 :latitude => lat,
                 :longitude => lon}

    body = http({:method => :post, :path => 'location'}, body_data)

    res = JSON.parse(body)
    if res['outcome'] != 'SUCCESS'
      screenshot_and_raise "Set location change failed, for #{lat}, #{lon} (#{body})."
    end
    res['results']

  end
end

#set_server_log_level(level) ⇒ Object

Set the Calabash server log level.

Parameters:

  • level (String)

    the log level to set (debug, info, warn, error)



1555
1556
1557
# File 'lib/calabash-cucumber/core.rb', line 1555

def set_server_log_level(level)
  _debug_level_response(http({:method => :post, :path => 'debug'}, {:level => level}))
end

#set_text(uiquery, txt) ⇒ Array<String>

Sets the text value of the views matched by uiquery to txt.

You should always try to enter text “like the user would” using the ‘keyboard_enter_text` method. There are cases, however, when this does not work or is very slow.

Please note that if you use this method, the UITextFieldDelegate and UITextViewDelegate methods ***will not be called*** if you use this method of text entry. This means that if you have UI elements that respond to text changes, they ***will not be updated***.

UIAutomation’s keyboard.typeString is incredibly buggy. Calabash goes to great lengths to provide a stable typing interface. However, there are cases where our patches cause problems. If your app crashes or hangs when calling ‘keyboard_enter_text` there are a couple of options.

  1. Try ‘fast_enter_text`. This may or may not cause delegate methods to be called (see the note above).

  2. Call ‘keyboard.typeString` directly. This will bypass the Calabash fixes (which sometimes cause hanging and/or crashes).

“‘ touch(“ < touch a text field or text view > ”) wait_for_keyboard uia(“UIATarget.localTarget().frontMostApp().keyboard().typeString(’your string’)”) “‘

Please be aware that keyboard.typeString is prone to errors. We recommend using ‘keyboard_enter_text` or `fast_enter_text` whenever possible.

One valid use of this method is on WebViews. Find examples in the [CalWebApp features/steps/set_text_steps.rb](github.com/calabash/ios-webview-test-app/blob/master/CalWebViewApp/features/steps/set_text_steps.rb).

@raise If the uiquery finds no matching queries or finds a view that does not respond to the objc selector ‘setText’

Parameters:

  • uiquery (String)

    used to find the text input views

  • txt (String)

    the new text

Returns:

  • (Array<String>)

    The text fields that were modified.



1704
1705
1706
1707
1708
1709
1710
# File 'lib/calabash-cucumber/core.rb', line 1704

def set_text(uiquery, txt)
  text_fields_modified = Map.map(uiquery, :setText, txt)

  msg = "query '#{uiquery}' returned no matching views that respond to 'setText'"
  Map.assert_map_results(text_fields_modified, msg)
  text_fields_modified
end

#set_user_pref(key, val) ⇒ Object

Sets user preference (NSUserDefaults) value of key ‘key` to `val`.

Examples:

set_user_pref 'foo', {lastname: "Krukow"}
# returns
[
    {
    "lastname" => "Krukow"
    },
   {
    "firstname" => "Karl"
   }
]

Parameters:

  • key (String)

    the set to set

  • val (Object)

    the (JSON_ serializable) value to set

Returns:

  • (Object)

    the current user preferences



1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
# File 'lib/calabash-cucumber/core.rb', line 1747

def set_user_pref(key, val)
  res = http({:method => :post, :path => 'userprefs'},
             {:key=> key, :value => val})
  res = JSON.parse(res)
  if res['outcome'] != 'SUCCESS'
    screenshot_and_raise "set_user_pref #{key} = #{val} failed because: #{res['reason']}\n#{res['details']}"
  end

  res['results']
end

#shake(seconds) ⇒ Object

Cause the device to shake.

Parameters:

  • seconds (Numeric)

    How long to shake the device

Raises:

  • (ArgumentError)

    if ‘seconds` argument is <= 0.0



1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
# File 'lib/calabash-cucumber/core.rb', line 1307

def shake(seconds)
  if seconds <= 0.0
    raise ArgumentError, "Seconds '#{seconds}' must be >= 0.0"
  end

  parameters = {
    :duration => seconds
  }

  begin
    body = http({:method => :post, :path => "shake"}, parameters)
    result = response_body_to_hash(body)
  rescue RuntimeError => e
    raise RuntimeError, e
  end

  if result["outcome"] != "SUCCESS"
    raise RuntimeError,
%Q{Could not shake the device:
 reason => '#{result["reason"]}'
details => '#{result["details"]}'
      }
  end
  result["results"]
end

#slider_set_value(uiquery, value, options = {}) ⇒ Array<String>

Set the sliders indicated by ‘uiquery` to `value`.

Examples:

slider_set_value "UISlider marked:'office slider'", 2
slider_set_value "slider marked:'weather slider'", -1
slider_set_value "* marked:'science slider'", 3
slider_set_value "UISlider", 11

Parameters:

  • uiquery (String)

    A query.

  • value (Number)

    The value to set the slider to. value.to_s should produce a String representation of a Number.

  • options (options) (defaults to: {})

    Options to control the behavior of the gesture.

Options Hash (options):

  • :animate (Boolean) — default: true

    Animate the change.

  • :notify_targets (Boolean) — default: true

    Simulate a UIEvent by calling every target/action pair defined on the UISliders matching ‘uiquery`.

Returns:

  • (Array<String>)

    An array of query results.

Raises:

  • (RuntimeError)

    When setting the value of the sliders match by ‘uiquery` is not successful.



1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
# File 'lib/calabash-cucumber/core.rb', line 1435

def slider_set_value(uiquery, value,  options={})
  default_options =  {:animate => true,
                      :notify_targets => true}
  merged_options = default_options.merge(options)

  value_str = value.to_s

  args = [merged_options[:animate], merged_options[:notify_targets]]
  views_touched = Map.map(uiquery, :changeSlider, value_str, *args)

  msg = "Could not set value of slider to '#{value}' using query '#{uiquery}'"
  Map.assert_map_results(views_touched, msg)
  views_touched
end

#start_test_server_in_background(args = {}) ⇒ Calabash::Cucumber::Launcher

Note:

It is not recommended to call this method outside of the calabash console. Call ‘Calabash::Cucumber::Launcher#relaunch instead.

Starts the app and Calabash test server in the console.

Returns:

See Also:



1573
1574
1575
1576
1577
1578
# File 'lib/calabash-cucumber/core.rb', line 1573

def start_test_server_in_background(args={})
  stop_test_server
  launcher = Calabash::Cucumber::Launcher.new
  launcher.relaunch(args)
  launcher
end

#swipe(direction, options = {}) ⇒ Array<Hash>

Performs a “swipe” gesture.

Examples:


# Swipe left on first view match by "*"
swipe(:left)

# Swipe up on 'my scroll view'
swipe(:up, {:query => "* marked:'my scroll view'"})

Parameters:

  • direction (String, Symbol)

    The direction to swipe

  • options (Hash) (defaults to: {})

    Options for modifying the details of the swipe.

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the touch to be offset with `(x,y)` relative to the center.

  • :force (Symbol) — default: normal

    Indicates the force of the swipe. Valid values are :strong, :normal, :light.

  • :query (String) — default: nil

    If specified, the swipe will be made on the first view matching this query. If this option is nil (the default), the swipe will happen at the center of the screen.

Returns:

  • (Array<Hash>)

    An array with one element; the view that was swiped.

Raises:

  • (ArgumentError)

    If :force is invalid.

  • (ArgumentError)

    If direction is invalid



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/calabash-cucumber/core.rb', line 396

def swipe(direction, options={})
  merged_options = {
    :query => nil,
    :force => :normal
  }.merge(options)

  merged_options[:direction] = direction.to_sym

  if ![:up, :down, :left, :right].include?(merged_options[:direction])
    raise ArgumentError, %Q[
Invalid direction argument: '#{direction}'.

Valid directions are: :up, :down, :left, and :right

]
  end

   if ![:light, :strong, :normal].include?(merged_options[:force])
     raise ArgumentError, %Q[
Invalid force option: '#{merged_options[:force]}'.

Valid forces are: :strong, :normal, :light

]
   end

  launcher.automator.swipe(merged_options)
end

#tap_keyboard_action_keyObject

Note:

Not all keyboards have an action key. For example, numeric keyboards do not have an action key.

Touches the keyboard action key.

The action key depends on the keyboard. Some examples include:

  • Return

  • Next

  • Go

  • Join

  • Search

Raises:

  • (RuntimeError)

    If the keyboard is not visible.



725
726
727
728
# File 'lib/calabash-cucumber/core.rb', line 725

def tap_keyboard_action_key
  expect_keyboard_visible!
  launcher.automator.tap_keyboard_action_key
end

#tap_keyboard_delete_keyObject

Touches the keyboard delete key.

Raises:

  • (RuntimeError)

    If the keyboard is not visible.



733
734
735
736
# File 'lib/calabash-cucumber/core.rb', line 733

def tap_keyboard_delete_key
  expect_keyboard_visible!
  launcher.automator.tap_keyboard_delete_key
end

#tap_mark(label, *args) ⇒ Array<Hash>

taps a view with mark ‘label`. Equivalent to `touch(“* marked:’##label‘”)`

Parameters:

  • label (String)

    the mark of the view to tap

  • args (Array)

    optional additional arguments to pass to ‘touch`.

Returns:

  • (Array<Hash>)

    array containing the serialized version of the tapped view.



1652
1653
1654
# File 'lib/calabash-cucumber/core.rb', line 1652

def tap_mark(label, *args)
  touch("view marked:'#{label}'", *args)
end

#tap_point(x, y) ⇒ Boolean

Performs the ‘tap` gesture on an absolute coordinate.

Parameters:

  • x (Numeric)

    x-coordinate to tap

  • y (Numeric)

    y-coordinate to tap

Returns:

  • (Boolean)

    ‘true`

See Also:



300
301
302
# File 'lib/calabash-cucumber/core.rb', line 300

def tap_point(x,y)
  touch(nil, offset: {x:x, y:y})
end

#touch(uiquery, options = {}) ⇒ Array<Hash>

Performs the ‘tap` gesture on the (first) view that matches query `uiquery`. Note that `touch` assumes the view is visible and not animating. If the view is not visible `touch` will fail. If the view is animating `touch` will silently fail.

By default, taps the center of the view. tapped view.

Parameters:

  • uiquery (String)

    query describing view to tap. If this value is ‘nil` then an :offset must be passed as an option. This can be used to tap a specific coordinate.

  • options (Hash) (defaults to: {})

    option for modifying the details of the touch

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the touch to be offset with `(x,y)` relative to the center.

Returns:

  • (Array<Hash>)

    array containing the serialized version of the

Raises:

  • (RuntimeError)

    If query is non nil and matches no views.

  • (ArgumentError)

    If query is nil and there is no :offset in the the options. The offset must contain both an :x and :y value.

See Also:



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/calabash-cucumber/core.rb', line 276

def touch(uiquery, options={})
  if uiquery.nil?
    offset = options[:offset]

    if !(offset && offset[:x] && offset[:y])
      raise ArgumentError, %Q[
If query is nil, there must be a valid offset in the options.

Expected: options[:offset] = {:x => NUMERIC, :y => NUMERIC}
  Actual: options[:offset] = #{offset ? offset : "nil"}

      ]
    end
  end
  query_action_with_options(:touch, uiquery, options)
end

#touch_hold(uiquery, options = {}) ⇒ Array<Hash>

Note:

This assumes the view is visible and not animating.

Performs the “long press” or “touch and hold” gesture on the (first) view that matches query ‘uiquery`.

If the view is not visible it will fail with an error. If the view is animating it will silently fail.

By default, the gesture starts at the center of the view.

Examples:

touch_hold "webView css:'input'", duration:10, offset:{x: -40}

Parameters:

  • uiquery (String)

    query describing view to touch.

  • options (Hash) (defaults to: {})

    option for modifying the details of the touch.

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the touch to be offset with `(x,y)` relative to the center (`center + (offset, offset)`).

  • :duration (Numeric) — default: 3

    duration of the ‘hold’.

Returns:

  • (Array<Hash>)

    array containing the serialized version of the touched view.



366
367
368
# File 'lib/calabash-cucumber/core.rb', line 366

def touch_hold(uiquery, options={})
  query_action_with_options(:touch_hold, uiquery, options)
end

#two_finger_tap(uiquery, options = {}) ⇒ Array<Hash>

Note:

This assumes the view is visible and not animating.

Performs the “two-finger tap” gesture on the (first) view that matches query ‘uiquery`.

If the view is not visible it will fail with an error. If the view is animating it will silently fail.

By default, taps the center of the view.

Examples:

two_finger_tap "view marked:'Third'", offset:{x:100}

Parameters:

  • uiquery (String)

    query describing view to touch.

  • options (Hash) (defaults to: {})

    option for modifying the details of the touch.

Options Hash (options):

  • :offset (Hash) — default: nil

    optional offset to touch point. Offset supports an ‘:x` and `:y` key and causes the touch to be offset with `(x,y)` relative to the center (`center + (offset, offset)`).

Returns:

  • (Array<Hash>)

    array containing the serialized version of the tapped view.



342
343
344
# File 'lib/calabash-cucumber/core.rb', line 342

def two_finger_tap(uiquery,options={})
  query_action_with_options(:two_finger_tap, uiquery, options)
end

#user_pref(key) ⇒ Object

Gets the user preference (NSUserDefaults) value for a key.

Parameters:

  • key (String)

    the read

Returns:

  • (Object)

    the current user preferences value for ‘key`



1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
# File 'lib/calabash-cucumber/core.rb', line 1761

def user_pref(key)
  res = http({:method => :get, :raw => true, :path => 'userprefs'},
             {:key=> key})
  res = JSON.parse(res)
  if res['outcome'] != 'SUCCESS'
    screenshot_and_raise "get user_pref #{key} failed because: #{res['reason']}\n#{res['details']}"
  end

  res['results'].first
end