- Command Line
 - Predefined Steps
 - Custom Steps
 - Resourcess
 
Setup your project for Calabash-iOS
calabash-ios setup
Generate a skeleton features folder for your tests
calabash-ios gen
Enable accessibility in the iOS Simulator
calabash-ios sim acc
Start up the calabash console
calabash-ios console
Run cucumber without launching or closing down the simulator
NO_LAUNCH=1 cucumber
Setting the simulator version
SDK_VERSION=5.0 cucumber
Run a single feature
cucumber features/masthead.feature
Run a feature with a tag
cucumber -t @wip
Run all features without a tag
cucumber -t ~@wip
Output the view in an easy to read format from a step definition
puts query("view").to_yaml 
Reset the app in-between tests
NO_STOP=1 RESET_BETWEEN_SCENARIOS=1 SDK_VERSION=5.1 cucumber -t @wip
Things you can do:
- see
 - fill in
 - enter
 - clear
 - touch
 - toggle
 - swipe
 - scroll
 - pinch
 - wait
 - go back
 - take picture
 - playback recording
 - rotate
 
Uses the Accessibility Labels (which can be seen using the Accessibility Inspector)
| Step | Descripiton | Notes | 
|---|---|---|
| Then I should see "First View" | Confirm the presence of some text | insert | 
| Then I should not see "foo" | insert | insert | 
| Then I should see a "login" button | insert | insert | 
| Then I should see a "Name" input field | insert | insert | 
| Then I fill in "Name" with "Alistair" | insert | insert | 
| Then I clear "Name" | insert | insert | 
| Then I clear input field number 1 | insert | insert | 
| Then I touch "login" | Touch an arbitrary view with the accessibility label "login" | |
| Then I touch the "login" button | Touch a button with the accessibility label "login" | insert | 
| Then I touch button number 1 | Touch the first button | insert | 
| Then I touch done | insert | insert | 
| Then I touch search | insert | insert | 
| Then I touch the user location | insert | insert | 
| Then I touch on screen 100 from the left and 250 from the top | insert | insert | 
| Then I toggle the switch | insert | insert | 
| Then I toggle the "switch" switch | insert | insert | 
| Then take picture | Take a screenshot | This will generate a .png prefixed with the step number | 
| Then I wait to see "text or label" | insert | insert | 
| Then I wait for "text or label" to appear | insert | insert | 
| Then I wait until I don't see "text or label" | insert | insert | 
| Then I wait to not see "text or label" | insert | insert | 
| Then I wait for the "login" button to appear | insert | insert | 
| Then I wait to see a navigation bar titled "title" | insert | insert | 
| Then I wait for the "label" input field | insert | insert | 
| Then I wait for 2 input fields | insert | insert | 
| Then I wait | Wait for 2 seconds | insert | 
| Then I wait and wait | Wait for 4 seconds | insert | 
| Then I wait and wait and wait... | Wait for 10 seconds | insert | 
| Then I wait for 2.3 seconds | Wait for 2.3 seconds | specify any arbitrary number of seconds | 
| Then I go back | insert | insert | 
| Then I swipe left | insert | insert | 
| Then I swipe right | insert | insert | 
| Then I swipe up | insert | insert | 
| Then I swipe down | insert | insert | 
| Then I swipe left on number 2 | insert | insert | 
| Then I swipe left on number 2 at x 20 and y 10 | insert | insert | 
| Then I swipe left on "accLabel" | insert | insert | 
| Then I swipe on cell number 2 | insert | insert | 
| Then I pinch to zoom in | insert | insert | 
| Then I pinch to zoom in on "accLabel" | insert | insert | 
| Then I scroll :direction | insert | insert | 
| Then I scroll :direction on "accLabel" | insert | insert | 
| Then I playback recording "mytouch" | insert | insert | 
| Then I playback recording "mytouch on "accLabel" | insert | insert | 
| Then I playback recording "mytouch on "accLabel" with offset 10,22 | insert | insert | 
| Then I rotate device left | insert | insert | 
| Then I rotate device right | insert | insert | 
| insert | insert | insert | 
To see how these have been implement: calabash_steps.rb
The simplest way of writing custom steps is to combine one or more existing steps. You do this using the macro function.
Then /^the First page should display the correct components$/ do
  macro 'I should see "First View"'
  macro 'I see 2 input field'
  macro 'I should see a "Name" input field'
  macro 'I should see "switch"'
  macro 'I should see a "login" button'
  macro 'I should see a "Alert" button'
end
If a step fails then you will get a useful error message
Expected at least 2 text/input fields, found 1 (RuntimeError)
Things you can do
- touch
 - retrieve label
 - query
 - check if something exists in the view
 - use the keyboard
 - rotate the device
 - traverse views (using Directions)
 
- touch()
 - label()
 - query()
 - element_exists()
 - element_does_not_exist()
 - view_with_mark_exists()
 - sleep()
 - wait_for()
 - scroll()
 - scroll_to_row()
 - check_element_exists()
 - keyboard_enter_char()
 - done()
 - rotate()
 - screenshot()
 
- view
 - label
 - textField
 - button
 
- index:0
 - marked:'London'
 - placeholder:'username'
 - accessibilityIdentifier:'location_name'
 - accessibilityLabel:'London'
 - isEnabled:1
 - text:'Hello'
 - view:'MyClassName'
 - webView css:'#header'
 
- {text LIKE 'Hel*'}
 
- numberOfRowsInSection:0
 - :up
 - :down
 - :right
 - :left
 
- parent
 - child
 
- :accessibilityLabel
 - :accessibilityIdentifier
 - :placeholder
 - :text
 
query("button", :titleLabel, :text) query("button buttonLabel text:'Foo Bar')
2 ways to check if an element exists with an specific accessibilityIdentifier
element_exists("view marked:'location_name'")
element_exists("view accessibilityIdentifier:'location_name'")
2 ways to retrieve the text of a view with a specific accessibilityIdentifier
query("view marked:'location_name'", :text)[0]
query("view accessibilityIdentifier:'location_name'", :text)[0]
Ways to output properties in the IRC
classes "view" 
label "view"
| Example | Descripiton | Notes | 
|---|---|---|
| touch("button index:0") | touch the first button | insert | 
| touch("tabBarButton index:1") | touch the second tabBarButton | insert | 
| touch("tabBarButton marked:'Second'") | though the tabBarButton with the accessibility id or label 'Second' | insert | 
| touch("webView css:'a'") | insert | insert | 
| label "tableViewCell index:0" | insert | insert | 
| query("tabBarButton") | Returns an array of all the tabBarButtons | insert | 
| query("tabBarButton", :accessibilityLabel) | Returns an array of all the tabBarButton accessibility labels | insert | 
| query("tabBarButton index:0", :accessibilityLabel) | insert | insert | 
| query("tabBarButton index:0 label", :text) | Returns all the labels inside the first tabBarButton | insert | 
| query("TabBar", :selectedItem, "title")[0] | insert | insert | 
| query("button marked:'Player play icon'", :isSelected) | insert | insert | 
| query "label index:0" | Returns the first label | insert | 
| query "label text:'Hello'" | insert | insert | 
| query "label marked:'Map'" | Returns the label with the accessibility label 'Map' | insert | 
| query "label {text LIKE 'Cell 1*'}" | Returns the labels that start with 'Cell 1' | * Uses a NSPredicate | 
| query("imageView {accessibilityLabel LIKE '*.png'}") | Returns the images with an accessibility label that contains '.png' | insert | 
| query("webView css:'*'") | Get all the HTML associated with the webview | insert | 
| query("webView css:'a'").first['html'] | insert | insert | 
| query "button isEnabled:1" | insert | insert | 
| query("view marked:'switch'") | Returns a view with accessibility id or label 'switch' | insert | 
| query("button")[0]["class"] | Returns the class of the first button | insert | 
| query("tableView",numberOfRowsInSection:0) | insert | insert | 
| query("webView css:'#header'") | insert | insert | 
| query("view:'MKMapView'") | matches a view based on the className 'MKMapView' | |
| query "webView", :request | Get the page url | insert | 
| element_exists("view") | insert | insert | 
| element_exists("button marked:'#{name}'") | insert | insert | 
| element_does_not_exist("button marked:'#{name}'") | insert | insert | 
| view_with_mark_exists("Logout") | insert | insert | 
| sleep(STEP_PAUSE) | insert | insert | 
| wait_for(WAIT_TIMEOUT) | insert | insert | 
| wait_for(5) | insert | insert | 
| scroll_to_row "tableView", 3 | insert | insert | 
| set_text "webView css:'input.login'", "ruk" | insert | insert | 
| scroll "webView", :up | insert | insert | 
| scroll "webView", :down | insert | insert | 
| scroll "webView", :left | insert | insert | 
| scroll "webView", :right | insert | insert | 
| scroll_to_row "tableView", 2 | insert | insert | 
| check_element_exists("view marked:'#{expected_mark}'") | insert | insert | 
| keyboard_enter_char "a" | insert | insert | 
| keyboard_enter_char "Dictation" | insert | insert | 
| keyboard_enter_char "Shift" | insert | insert | 
| keyboard_enter_char "Delete" | insert | insert | 
| keyboard_enter_char "Return" | insert | insert | 
| keyboard_enter_char "International" | insert | insert | 
| keyboard_enter_char "More" | insert | insert | 
| keyboard_enter_text "The Quick Brown Fox" | insert | insert | 
| done | Enters "Done" or "Search" or "Return" | insert | 
| rotate :left | insert | insert | 
| rotate :right | insert | insert | 
| screenshot "/Users/krukow/tmp", "my.png" | insert | insert | 
| screenshot_embed( :label => 'Foo bar') | insert | insert | 
| insert | insert | insert | 
- In general you use a NSPredicate by writing a filter: {selector OP comp}, where selector is the name of a selector you want to perform on the object and OP and comp are an operation and something to compare with. See also Predicate Programming Guide
 
- Calabash, an open-source automated testing technology for native mobile, by Karl Krukow
 - iOS Automated Testing with Calabash: Tips and Tricks
 - Calabash, an open-source automated testing technology for iOS and Android
 - Karl Krukow presents Calabash: Automated Acceptance Testing for Android, 6 October 2012, 73 mins