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?, #ios5?, #ios6?, #ios7?, #ios8?, #ios9?, #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:



1560
1561
1562
# File 'lib/calabash-cucumber/core.rb', line 1560

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



1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
# File 'lib/calabash-cucumber/core.rb', line 1405

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.



1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
# File 'lib/calabash-cucumber/core.rb', line 1453

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.



1665
1666
1667
1668
1669
1670
# File 'lib/calabash-cucumber/core.rb', line 1665

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



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

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:



1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
# File 'lib/calabash-cucumber/core.rb', line 1772

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:



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
# File 'lib/calabash-cucumber/core.rb', line 765

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[:x], offset[:y])).

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



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

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.



1579
1580
1581
# File 'lib/calabash-cucumber/core.rb', line 1579

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:



620
621
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
# File 'lib/calabash-cucumber/core.rb', line 620

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.



683
684
685
686
687
688
# File 'lib/calabash-cucumber/core.rb', line 683

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.



1572
1573
1574
# File 'lib/calabash-cucumber/core.rb', line 1572

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:



1312
1313
1314
1315
1316
# File 'lib/calabash-cucumber/core.rb', line 1312

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:



1542
1543
1544
# File 'lib/calabash-cucumber/core.rb', line 1542

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.

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.



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

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

  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.

Raises:

  • (ArgumentError)

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



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
# File 'lib/calabash-cucumber/core.rb', line 557

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

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

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

TODO:

pinch is an old style API which doesn't take a query as its first argument. We should migrate this.

Performs a “pinch” gesture. By default, the gesture starts at the center of the screen.

Examples:

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

Parameters:

  • in_out (String)

    the direction to pinch ('in' or 'out') (symbols can also be used).

  • 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[:x], offset[:y])).

  • :query (String) — default: nil

    if specified, the pinch will be made relative to this query.

Returns:

  • (Array<Hash>, String)

    array containing the serialized version of the touched view if options[:query] is given.



599
600
601
# File 'lib/calabash-cucumber/core.rb', line 599

def pinch(in_out, options={})
  launcher.automator.pinch(in_out.to_sym, 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



792
793
794
795
796
797
798
799
800
801
802
803
# File 'lib/calabash-cucumber/core.rb', line 792

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:



909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
# File 'lib/calabash-cucumber/core.rb', line 909

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 “*”.



1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
# File 'lib/calabash-cucumber/core.rb', line 1050

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 {label | 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



1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
# File 'lib/calabash-cucumber/core.rb', line 1151

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:



830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# File 'lib/calabash-cucumber/core.rb', line 830

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:



882
883
884
885
886
887
# File 'lib/calabash-cucumber/core.rb', line 882

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 {:middle | :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 “*”.



965
966
967
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
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
# File 'lib/calabash-cucumber/core.rb', line 965

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



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
# File 'lib/calabash-cucumber/core.rb', line 1218

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



1490
1491
1492
# File 'lib/calabash-cucumber/core.rb', line 1490

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)



1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
# File 'lib/calabash-cucumber/core.rb', line 1282

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)



1496
1497
1498
# File 'lib/calabash-cucumber/core.rb', line 1496

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.

@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.



1645
1646
1647
1648
1649
1650
1651
# File 'lib/calabash-cucumber/core.rb', line 1645

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



1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
# File 'lib/calabash-cucumber/core.rb', line 1688

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



1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
# File 'lib/calabash-cucumber/core.rb', line 1248

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.



1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
# File 'lib/calabash-cucumber/core.rb', line 1376

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:



1514
1515
1516
1517
1518
1519
# File 'lib/calabash-cucumber/core.rb', line 1514

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>, String

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.

  • :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 on the first view matched by “*”.

  • :force (Symbol) — default: normal

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

Returns:

  • (Array<Hash>, String)

    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.



666
667
668
669
# File 'lib/calabash-cucumber/core.rb', line 666

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.



674
675
676
677
# File 'lib/calabash-cucumber/core.rb', line 674

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.



1593
1594
1595
# File 'lib/calabash-cucumber/core.rb', line 1593

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[:x], offset[:y])).

  • :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[:x], offset[:y])).

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



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

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