└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Calabash iOS Tutorial 2 | 3 | * Command Line 4 | * Predefined Steps 5 | * Custom Steps 6 | * Resourcess 7 | 8 | ## Command Line 9 | 10 | 11 | Setup your project for Calabash-iOS 12 | 13 | calabash-ios setup 14 | 15 | Generate a skeleton features folder for your tests 16 | 17 | calabash-ios gen 18 | 19 | Enable accessibility in the iOS Simulator 20 | 21 | calabash-ios sim acc 22 | 23 | Start up the calabash console 24 | 25 | calabash-ios console 26 | 27 | Run cucumber without launching or closing down the simulator 28 | 29 | NO_LAUNCH=1 cucumber 30 | 31 | Setting the simulator version 32 | 33 | SDK_VERSION=5.0 cucumber 34 | 35 | Run a single feature 36 | 37 | cucumber features/masthead.feature 38 | 39 | Run a feature with a tag 40 | 41 | cucumber -t @wip 42 | 43 | Run all features without a tag 44 | 45 | cucumber -t ~@wip 46 | 47 | Output the view in an easy to read format from a step definition 48 | 49 | puts query("view").to_yaml 50 | 51 | 52 | Reset the app in-between tests 53 | 54 | NO_STOP=1 RESET_BETWEEN_SCENARIOS=1 SDK_VERSION=5.1 cucumber -t @wip 55 | 56 | ## Predefined Steps 57 | 58 | Things you can do: 59 | 60 | * see 61 | * fill in 62 | * enter 63 | * clear 64 | * touch 65 | * toggle 66 | * swipe 67 | * scroll 68 | * pinch 69 | * wait 70 | * go back 71 | * take picture 72 | * playback recording 73 | * rotate 74 | 75 | Uses the Accessibility Labels (which can be seen using the Accessibility Inspector) 76 | 77 | ### Examples 78 | 79 | Step | Descripiton | Notes | 80 | ---- | ----------- | ----------- | 81 | Then I should see "First View" | Confirm the presence of some text | insert 82 | Then I should not see "foo" | insert | insert 83 | Then I should see a "login" button | insert | insert 84 | Then I should see a "Name" input field | insert | insert 85 | Then I fill in "Name" with "Alistair" | insert | insert 86 | Then I clear "Name" | insert | insert 87 | Then I clear input field number 1 | insert | insert 88 | Then I touch "login" | Touch an arbitrary view with the accessibility label "login" | 89 | Then I touch the "login" button | Touch a button with the accessibility label "login" | insert 90 | Then I touch button number 1 | Touch the first button | insert 91 | Then I touch done | insert | insert 92 | Then I touch search | insert | insert 93 | Then I touch the user location | insert | insert 94 | Then I touch on screen 100 from the left and 250 from the top | insert | insert 95 | Then I toggle the switch | insert | insert 96 | Then I toggle the "switch" switch | insert | insert 97 | Then take picture | Take a screenshot | This will generate a .png prefixed with the step number 98 | Then I wait to see "text or label" | insert | insert 99 | Then I wait for "text or label" to appear | insert | insert 100 | Then I wait until I don't see "text or label" | insert | insert 101 | Then I wait to not see "text or label" | insert | insert 102 | Then I wait for the "login" button to appear | insert | insert 103 | Then I wait to see a navigation bar titled "title" | insert | insert 104 | Then I wait for the "label" input field | insert | insert 105 | Then I wait for 2 input fields | insert | insert 106 | Then I wait | Wait for 2 seconds | insert 107 | Then I wait and wait | Wait for 4 seconds | insert 108 | Then I wait and wait and wait... | Wait for 10 seconds | insert 109 | Then I wait for 2.3 seconds | Wait for 2.3 seconds | specify any arbitrary number of seconds 110 | Then I go back | insert | insert 111 | Then I swipe left | insert | insert 112 | Then I swipe right | insert | insert 113 | Then I swipe up | insert | insert 114 | Then I swipe down | insert | insert 115 | Then I swipe left on number 2 | insert | insert 116 | Then I swipe left on number 2 at x 20 and y 10 | insert | insert 117 | Then I swipe left on "accLabel" | insert | insert 118 | Then I swipe on cell number 2 | insert | insert 119 | Then I pinch to zoom in | insert | insert 120 | Then I pinch to zoom in on "accLabel" | insert | insert 121 | Then I scroll :direction | insert | insert 122 | Then I scroll :direction on "accLabel" | insert | insert 123 | Then I playback recording "mytouch" | insert | insert 124 | Then I playback recording "mytouch on "accLabel" | insert | insert 125 | Then I playback recording "mytouch on "accLabel" with offset 10,22 | insert | insert 126 | Then I rotate device left | insert | insert 127 | Then I rotate device right | insert | insert 128 | insert | insert | insert 129 | 130 | 131 | To see how these have been implement: [calabash_steps.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/features/step_definitions/calabash_steps.rb) 132 | 133 | 134 | ## Custom Steps 135 | 136 | ### Macro Steps 137 | 138 | The simplest way of writing custom steps is to combine one or more existing steps. You do this using the macro function. 139 | 140 | Then /^the First page should display the correct components$/ do 141 | macro 'I should see "First View"' 142 | macro 'I see 2 input field' 143 | macro 'I should see a "Name" input field' 144 | macro 'I should see "switch"' 145 | macro 'I should see a "login" button' 146 | macro 'I should see a "Alert" button' 147 | end 148 | 149 | If a step fails then you will get a useful error message 150 | 151 | Expected at least 2 text/input fields, found 1 (RuntimeError) 152 | 153 | ### Ruby API 154 | 155 | Things you can do 156 | 157 | * touch 158 | * retrieve label 159 | * query 160 | * check if something exists in the view 161 | * use the keyboard 162 | * rotate the device 163 | * traverse views (using Directions) 164 | 165 | #### Methods 166 | * touch() 167 | * label() 168 | * query() 169 | * element_exists() 170 | * element_does_not_exist() 171 | * view_with_mark_exists() 172 | * sleep() 173 | * wait_for() 174 | * scroll() 175 | * scroll_to_row() 176 | * check_element_exists() 177 | * keyboard_enter_char() 178 | * done() 179 | * rotate() 180 | * screenshot() 181 | 182 | #### UI Elements 183 | 184 | * view 185 | * label 186 | * textField 187 | * button 188 | 189 | 190 | 191 | #### Selectors 192 | * index:0 193 | * marked:'London' 194 | * placeholder:'username' 195 | * accessibilityIdentifier:'location_name' 196 | * accessibilityLabel:'London' 197 | * isEnabled:1 198 | * text:'Hello' 199 | * view:'MyClassName' 200 | * webView css:'#header' 201 | 202 | 203 | ##### NSPredicate examples 204 | * {text LIKE 'Hel*'} 205 | 206 | 207 | #### Arguments 208 | * numberOfRowsInSection:0 209 | * :up 210 | * :down 211 | * :right 212 | * :left 213 | 214 | 215 | #### Directions / Traversal 216 | 217 | * parent 218 | * child 219 | 220 | #### Properties 221 | * :accessibilityLabel 222 | * :accessibilityIdentifier 223 | * :placeholder 224 | * :text 225 | 226 | 227 | query("button", :titleLabel, :text) 228 | query("button buttonLabel text:'Foo Bar') 229 | 230 | #### Examples 231 | 232 | 233 | 2 ways to check if an element exists with an specific accessibilityIdentifier 234 | 235 | element_exists("view marked:'location_name'") 236 | element_exists("view accessibilityIdentifier:'location_name'") 237 | 238 | 2 ways to retrieve the text of a view with a specific accessibilityIdentifier 239 | 240 | query("view marked:'location_name'", :text)[0] 241 | query("view accessibilityIdentifier:'location_name'", :text)[0] 242 | 243 | 244 | Ways to output properties in the IRC 245 | 246 | classes "view" 247 | label "view" 248 | 249 | 250 | Example | Descripiton | Notes | 251 | ---- | ----------- | ----------- | 252 | touch("button index:0") | touch the first button | insert 253 | touch("tabBarButton index:1") | touch the second tabBarButton | insert 254 | touch("tabBarButton marked:'Second'") | though the tabBarButton with the accessibility id or label 'Second' | insert 255 | touch("webView css:'a'") | insert | insert 256 | label "tableViewCell index:0" | insert | insert 257 | query("tabBarButton") | Returns an array of all the tabBarButtons | insert 258 | query("tabBarButton", :accessibilityLabel) | Returns an array of all the tabBarButton accessibility labels | insert 259 | query("tabBarButton index:0", :accessibilityLabel) | insert | insert 260 | query("tabBarButton index:0 label", :text) | Returns all the labels inside the first tabBarButton | insert 261 | query("TabBar", :selectedItem, "title")[0] | insert | insert 262 | query("button marked:'Player play icon'", :isSelected) | insert | insert 263 | query "label index:0" | Returns the first label | insert 264 | query "label text:'Hello'" | insert | insert 265 | query "label marked:'Map'" | Returns the label with the accessibility label 'Map' | insert 266 | query "label {text LIKE 'Cell 1*'}" | Returns the labels that start with 'Cell 1' | * Uses a [NSPredicate](https://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html) 267 | query("imageView {accessibilityLabel LIKE '*.png'}") | Returns the images with an accessibility label that contains '.png' | insert 268 | query("webView css:'*'") | Get all the HTML associated with the webview | insert 269 | query("webView css:'a'").first['html'] | insert | insert 270 | query "button isEnabled:1" | insert | insert 271 | query("view marked:'switch'") | Returns a view with accessibility id or label 'switch' | insert 272 | query("button")[0]["class"] | Returns the class of the first button | insert 273 | query("tableView",numberOfRowsInSection:0) | insert | insert 274 | query("webView css:'#header'") | insert | insert 275 | query("view:'MKMapView'") | matches a view based on the className 'MKMapView'| 276 | query "webView", :request | Get the page url | insert 277 | element_exists("view") | insert | insert 278 | element_exists("button marked:'#{name}'") | insert | insert 279 | element_does_not_exist("button marked:'#{name}'") | insert | insert 280 | view_with_mark_exists("Logout") | insert | insert 281 | sleep(STEP_PAUSE) | insert | insert 282 | wait_for(WAIT_TIMEOUT) | insert | insert 283 | wait_for(5) | insert | insert 284 | scroll_to_row "tableView", 3 | insert | insert 285 | set_text "webView css:'input.login'", "ruk" | insert | insert 286 | scroll "webView", :up | insert | insert 287 | scroll "webView", :down | insert | insert 288 | scroll "webView", :left | insert | insert 289 | scroll "webView", :right | insert | insert 290 | scroll_to_row "tableView", 2 | insert | insert 291 | check_element_exists("view marked:'#{expected_mark}'") | insert | insert 292 | keyboard_enter_char "a" | insert | insert 293 | keyboard_enter_char "Dictation" | insert | insert 294 | keyboard_enter_char "Shift" | insert | insert 295 | keyboard_enter_char "Delete" | insert | insert 296 | keyboard_enter_char "Return" | insert | insert 297 | keyboard_enter_char "International" | insert | insert 298 | keyboard_enter_char "More" | insert | insert 299 | keyboard_enter_text "The Quick Brown Fox" | insert | insert 300 | done | Enters "Done" or "Search" or "Return" | insert 301 | rotate :left | insert | insert 302 | rotate :right | insert | insert 303 | screenshot "/Users/krukow/tmp", "my.png" | insert | insert 304 | screenshot_embed( :label => 'Foo bar') | insert | insert 305 | insert | insert | insert 306 | 307 | * In general you use a [NSPredicate](https://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html) 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](https://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Predicates/Articles/pSyntax.html#//apple_ref/doc/uid/TP40001795-CJBDBHCB) 308 | 309 | 310 | ## Resources 311 | 312 | ### Docs 313 | * [Calabash](http://calaba.sh/) 314 | * [calabash-ios](https://github.com/calabash/calabash-ios) 315 | * [01 Getting started guide](https://github.com/calabash/calabash-ios/wiki/01-Getting-started-guide) 316 | * [02 Predefined steps](https://github.com/calabash/calabash-ios/wiki/02-Predefined-steps) 317 | * [03 Writing custom steps](https://github.com/calabash/calabash-ios/wiki/03-Writing-custom-steps) 318 | * [03.5 Calabash iOS Ruby API](https://github.com/calabash/calabash-ios/wiki/03.5-Calabash-iOS-Ruby-API) 319 | * [04 Touch recording and playback](https://github.com/calabash/calabash-ios/wiki/04-Touch-recording-and-playback) 320 | * [05 Query syntax](https://github.com/calabash/calabash-ios/wiki/05-Query-syntax) 321 | * [06 WebView Support](https://github.com/calabash/calabash-ios/wiki/06-WebView-Support) 322 | * [calabash-cucumber - ruby files](https://github.com/calabash/calabash-ios/tree/master/calabash-cucumber/lib/calabash-cucumber) 323 | * Predefined steps 324 | * [calabash_steps.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/features/step_definitions/calabash_steps.rb) 325 | * Calabash iOS Ruby API 326 | * [core.rb - iOS api](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/core.rb) 327 | * [operations.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/operations.rb) 328 | * [keyboard_helpers.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/keyboard_helpers.rb) 329 | * [location.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/location.rb) 330 | * [tests_helpers.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/tests_helpers.rb) 331 | * [wait_helpers.rb](https://github.com/calabash/calabash-ios/blob/master/calabash-cucumber/lib/calabash-cucumber/wait_helpers.rb) 332 | * [calabash-ios forum](https://groups.google.com/forum/?fromgroups=#!forum/calabash-ios) 333 | 334 | * [lesspainful](https://www.lesspainful.com/) 335 | * [AN OVERVIEW OF CALABASH IOS](http://blog.lesspainful.com/2012/03/07/Calabash-iOS/) 336 | * [CALABASH: FUNCTIONAL TESTING FOR MOBILE APPS](http://blog.lesspainful.com/2012/03/07/Calabash/* ) 337 | 338 | ### Tutorials 339 | * [iOS Automated Testing With Calabash, Cucumber, and Ruby](http://www.moncefbelyamani.com/ios-automated-testing-with-calabash-cucumber-ruby/) 340 | 341 | ### Videos 342 | * [Calabash, an open-source automated testing technology for native mobile, by Karl Krukow](http://www.youtube.com/watch?v=0an8l1RAe0M) 343 | * [iOS Automated Testing with Calabash: Tips and Tricks](http://www.youtube.com/watch?v=mvzGAs9aD20&feature=plcp) 344 | * [Calabash, an open-source automated testing technology for iOS and Android](http://skillsmatter.com/podcast/home/calabash-an-open-source-automated-testing-technology-for-ios-and-android) 345 | * [Karl Krukow presents Calabash: Automated Acceptance Testing for Android](http://www.youtube.com/watch?v=9FAjxMLyTco), 6 October 2012, 73 mins 346 | 347 | ### Related 348 | * [uispec - Behavior Driven Development for the iPhone](http://www.hans-eric.com/share/getting-started-with-uispec/) --------------------------------------------------------------------------------