calabash-cucumber 0.9.138 → 0.9.139

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,7 +22,7 @@ def print_usage
22
22
  setup [<path>]
23
23
  setup your XCode project for calabash-ios (EXPERIMENTAL)
24
24
  download
25
- downloads latest compatible version of calabash.framework
25
+ install latest compatible version of calabash.framework
26
26
  check [{<path to .ipa>|<path to .app>}]
27
27
  check whether an app or ipa is linked with calabash.framework (EXPERIMENTAL)
28
28
  sim locale <lang> [<region>]
@@ -8,7 +8,10 @@ Usage: calabash-ios <command-name> [parameters]
8
8
  sim locale [lang] [regional]?
9
9
  sim reset
10
10
  sim acc
11
- sim device [iPad_Retina, iPhone, iPhone_Retina, iPhone_Retina_4inch]
11
+ sim device {iPad,iPad_Retina,iPhone,iPhone_Retina,iPhone_Retina_4inch}
12
+ sim location {on|off} <bundleid>
13
+
14
+
12
15
 
13
16
  Commands:
14
17
  gen creates a skeleton features dir. This is usually used once when
@@ -16,8 +19,8 @@ Usage: calabash-ios <command-name> [parameters]
16
19
  the right step definitions and environment to run with cucumber.
17
20
  console
18
21
  starts an interactive console to interact with your app via Calabash.
19
- Copies the irb_ios5.sh and irb_ios4.sh scripts and the .irbrc file
20
- then launches irb_ios5.sh.
22
+ Supports setting environment var CALABASH_IRBRC for custom .irbrc file.
23
+
21
24
  setup [path]? (EXPERIMENTAL) Automates setting up your iOS Xcode project
22
25
  with calabash-ios-server. It is your responsibility to ensure
23
26
  that your production build does not link with calabash.framework.
@@ -42,17 +45,20 @@ Usage: calabash-ios <command-name> [parameters]
42
45
  to project.pbxproj inside your .xcodeproj folder.
43
46
 
44
47
  download [opt_path]?
45
- downloads latest compatible version of calabash.framework.
48
+ copies current compatible version of calabash.framework to your project.
46
49
  It should be run from a directory containing an Xcode project,
47
50
  or optionally opt_path should be supplied and pointing to a
48
51
  directory containing an Xcode project.
49
- Download will download the latest version that matches the
52
+ Will copy in the latest version that matches the
50
53
  currently installed calabash-cucumber gem.
51
54
  To update Calabash for your project run
52
55
 
53
- gem update calabash-cucumber
56
+ gem install calabash-cucumber
54
57
  calabash-ios download
55
58
 
59
+ Then clean and rebuild to your project.
60
+ Check the current server version on http://localhost:37265/version
61
+
56
62
  check (EXPERIMENTAL) [.app or .ipa]?
57
63
  check whether an app or ipa is linked with calabash.framework
58
64
  if called without parameter [.app or .ipa] then pwd should be
@@ -66,8 +72,11 @@ Usage: calabash-ios <command-name> [parameters]
66
72
  for the optional regional parameter, for example,
67
73
  da_DK, en_US.
68
74
 
75
+ sim location {on|off} <bundleid>
76
+ set allow location on/off for current project or bundleid
77
+
69
78
  sim reset (EXPERIMENTAL) Will select "Reset Content and Settings"
70
79
  in the iOS Simulators using AppleScript.
71
80
 
72
81
  sim device [device] Will set the default iOS Simulator device.
73
- [device] can be one of iPad, iPhone, iPhone_Retina.
82
+ [device] can be one of iPad iPad_Retina iPhone iPhone_Retina iPhone_Retina_4inch
@@ -0,0 +1,250 @@
1
+ # Cross-platform Acceptance Testing Best Practices
2
+
3
+ Test automation is programming - hence, well-established practices of programming apply to test automation. Ruby is object-oriented, and most Calabash tests should also follow good object-oriented design (e.g., principles of abstraction, separation of concerns, modularity, reuse...).
4
+
5
+ A well-established pattern in test engineering is the *Page-Object Pattern* (POP). While originating in web testing, the ideas of POP apply equally well to native mobile. In this short article, we'll illustrate how to use the page object pattern to better architect test code and obtain better cross-platform code reuse.
6
+
7
+ We've created a sample project: [X-Platform-Example](https://github.com/calabash/x-platform-example) using the open source WordPress app. If you want to follow along and try things out, go to the project page [https://github.com/calabash/x-platform-example](https://github.com/calabash/x-platform-example) and follow install and run instructions. You can also choose to just read about the principles in this article and try to implement them in you own app.
8
+
9
+ LessPainful also provides both on-site and public training courses where we teach the use of Calabash as well as cross-platform and automated testing best practices. If you're interested in a two-day, hands-on course, please contact us at [contact@lesspainful.com](mailto:contact@lesspainful.com).
10
+
11
+ # Page Objects
12
+
13
+ A *page object* is an object that represents a single screen (page) in your application. For mobile, "screen object" would possibly be a better word, but Page Object is an established term that we'll stick with.
14
+
15
+ A page object should abstract a single screen in your application. It should expose methods to query the state and data of the screen as well as methods to take actions on the screen.
16
+
17
+ As a trivial example, a "login screen" consisting of username and password text fields and a "Login" button could expose a method `login(user,pass)` method that would abstract the details of entering username, password, touching the "Login" button, as well as 'transitioning' to another page (after login). A screen with a list of talks for a conference could expose a `talks()` method to return the visible talks and perhaps a `details(talk)` method to navigate to details for a particular talk.
18
+
19
+ The most obvious benefit of this is abstraction and reuse. If you have several steps needing to navigate to details, the code for `details(talk)` is reused. Also, callers of this method need not worry about the details (e.g. query and touch) or navigating to this screen.
20
+
21
+ # Cross-platform Core Idea
22
+
23
+
24
+ Let's go into more detail with this last example. Consider the following sketch of a class (don't do it exactly like this - read on a bit):
25
+
26
+ ```ruby
27
+
28
+ class TalksScreen
29
+ def talks
30
+ # query all talks...
31
+ end
32
+
33
+ def details(talk)
34
+ #touch talk…
35
+ end
36
+ end
37
+ ```
38
+
39
+
40
+ Suppose you're building the same app for iPhone and Android phones. Most likely the interface of the `TalksScreen` class makes complete sense on both platforms. This means that the calling code, which is usually in a step definition, is independent of platform - hence it can be reused across platforms.
41
+
42
+ Working this way gets you complete reuse of Cucumber features as well as step definitions: the details of interacting with the screen is pushed to page object implementations.
43
+
44
+ The idea is that you provide an implementation of page objects for each platform you need to support (e.g. iPhone, iPad, Android phone, Android tablet, mobile web, desktop web,…).
45
+
46
+ # Cross-platform in practice
47
+
48
+ So… The idea and design looks good. The question now is how to implement this is practice. Here we describe the mechanics and below you'll find an example extracted from [X-Platform-Example](https://github.com/calabash/x-platform-example).
49
+
50
+ There are a couple of ingredients we need.
51
+
52
+ 1. For each screen you want to automate, decide on an interface for a page object class (e.g. like `TalksScreen` above).
53
+ 2. Use only custom steps, and in each step definition *only* use page objects and their methods (no direct calls to Calabash iOS or Calabash Android APIs).
54
+ 3. For each supported platform, define a class with implementations of the page-object methods.
55
+ 4. Create a Cucumber profile (`config/cucumber.yml`). Define a profile for each platform (e.g. `android` and `ios`), and ensure that the profile *only* loads the page object classes for the platform.
56
+ 5. Rejoice and profit!
57
+
58
+ Let's see what these steps look like in a concrete example on the [X-Platform-Example](https://github.com/calabash/x-platform-example).
59
+
60
+ # Example
61
+
62
+ ## Step 1 - Interface
63
+ For the wordpress app, let's focus on the Login/Add-WordPress Blog screen. This method has a single method: `login(user)` which takes a hash `{:email => 'username', :password => 'somepass'}` representing a user:
64
+
65
+ ```ruby
66
+
67
+ def login(user)
68
+ #…
69
+ end
70
+
71
+ def assert_invalid_login_message()
72
+ #…
73
+ end
74
+ ```
75
+
76
+ For this simple screen the interface consists of just these two methods.
77
+
78
+ ## Step 2 - Step definitions
79
+
80
+ We have a feature alà
81
+
82
+ Scenario: Invalid login to WordPress.com blog
83
+ Given I am about to login
84
+ When I enter invalid credentials
85
+ Then I am presented with an error message to correct credentials
86
+
87
+ Below are step definitions that *only use the page objects* and no Calabash methods like touch, query…
88
+
89
+ For the following, assume we have also a Page Object class `WelcomePage` with a method `wordpress_blog` that transitions to the `AddWordPressBlog` screen:
90
+
91
+ ```ruby
92
+
93
+ ## Invalid login ##
94
+ Given /^I am about to login$/ do
95
+
96
+ welcome = page(WelcomePage).await
97
+ @page = welcome.wordpress_blog
98
+
99
+ end
100
+
101
+ When /^I enter invalid credentials$/ do
102
+ @page = @page.login(USERS[:invalid])
103
+ end
104
+
105
+ Then /^I am presented with an error message to correct credentials$/ do
106
+ @page.assert_invalid_login_message
107
+ screenshot_embed
108
+ end
109
+ ```
110
+
111
+ The `page` method is a helper method in Calabash which initializes a page object from a class. The `await` method just returns the page object after waiting for the page to be loaded.
112
+
113
+ We store the page object in an instance variable in the cucumber world (`@page`) and use it in the subsequent steps.
114
+
115
+ Notice how the steps only use page-object methods. This feature, as well as the step definitions, can be 100% reused across platforms. Great!
116
+
117
+ ## Step 3 - Platform implementations
118
+
119
+ Now we need to give an implementation of the `WordPressComPage` on iOS and Android (and all other supported platforms). We put those implementations in separte directories `features/ios/pages` and `features/android/pages` and name them `word_press_com_page_ios.rb` and `word_press_com_android.rb`.
120
+
121
+ Here is the implementation for iOS. It uses an abstract Page Object Class defined in Calabash iOS (`Calabash::IBase`).
122
+
123
+ ```ruby
124
+ require 'calabash-cucumber/ibase'
125
+
126
+ class WordPressComPage < Calabash::IBase
127
+
128
+ def title
129
+ "Sign In"
130
+ end
131
+
132
+ def login(user)
133
+ touch("view marked:'Username'")
134
+ await_keyboard
135
+
136
+ keyboard_enter_text user[:email]
137
+
138
+ touch("view marked:'Password'")
139
+
140
+ keyboard_enter_text user[:password]
141
+ done
142
+
143
+ wait_for_elements_do_not_exist(["tableViewCell activityIndicatorView"],
144
+ :timeout => 120)
145
+
146
+
147
+ if element_exists(invalid_login_query)
148
+ self
149
+ else
150
+ page(MainPage).await
151
+ end
152
+ end
153
+
154
+ def assert_invalid_login_message
155
+ check_element_exists(trait)
156
+ check_element_exists(invalid_login_query)
157
+ end
158
+
159
+ def invalid_login_query
160
+ "label {text LIKE '*Sign in failed*'}"
161
+ end
162
+
163
+ end
164
+
165
+ ```
166
+
167
+ And for Android:
168
+
169
+ ```ruby
170
+ class WordPressComPage < Calabash::ABase
171
+
172
+ def trait
173
+ "* id:'username'"
174
+ end
175
+
176
+ def await(opts={})
177
+ wait_for_elements_exist([trait])
178
+ self
179
+ end
180
+
181
+
182
+ def login(user)
183
+ query("* id:'username'",{:setText => user[:email]})
184
+ query("* id:'password'",{:setText => user[:password]})
185
+
186
+ performAction('scroll_down')
187
+
188
+ touch(login_button_query)
189
+
190
+ sleep(1)#Chance to show Dialog
191
+
192
+ wait_for(:timeout => 60, :timeout_message => "Timed out logging in") do
193
+ current_dialogs = query("DialogTitle",:text)
194
+
195
+ empty_dialog = current_dialogs.empty?
196
+ error_dialog = current_dialogs.include?("Error")
197
+ no_network_dialog = current_dialogs.include?("No network available")
198
+
199
+ empty_dialog or error_dialog or no_network_dialog
200
+ end
201
+
202
+ main_page = page(MainPage)
203
+
204
+ if main_page.current_page?
205
+ main_page.await
206
+ else
207
+ self
208
+ end
209
+ end
210
+
211
+ def invalid_login_query
212
+ login_button_query
213
+ end
214
+
215
+ def login_button_query
216
+ "android.widget.Button marked:'Log In'"
217
+ end
218
+
219
+ def assert_invalid_login_message
220
+ check_element_exists(invalid_login_query)
221
+ end
222
+
223
+
224
+ end
225
+ ```
226
+
227
+ ## Step 4 - Conditional loading
228
+
229
+ The final missing part is conditionally loading page-object implementations based on which platform we're running. This is done using Cucumber *profiles*. We create a file `config/cucumber.yml`
230
+
231
+ ---
232
+ android: RESET_BETWEEN_SCENARIOS=1 PLATFORM=android -r features/support -r features/android/support -r features/android/helpers -r features/step_definitions -r features/android/pages/
233
+
234
+ ios: APP_BUNDLE_PATH=ios-source/3.3.1/build/Applications/WordPress.app RESET_BETWEEN_SCENARIOS=1 PLATFORM=ios -r features/support -r features/ios/support -r features/ios/helpers -r features/step_definitions -r features/ios/pages
235
+
236
+ We're using Cucumbers `-r` option to only load a subset of Ruby files. We can then execute the tests as specified [here](https://github.com/calabash/x-platform-example).
237
+
238
+ iOS:
239
+
240
+ cucumber -p ios features/login.feature
241
+
242
+ Android:
243
+
244
+ calabash-android run path_to.apk -p android features/login.feature
245
+
246
+ ## Conclusion
247
+
248
+ We've described how to improve the architecture of your test code base: using page objects you get better abstraction, reuse and cross-platform comes more easily. We've created an open source sample project that you can use for inspiration: [X-Platform-Example](https://github.com/calabash/x-platform-example).
249
+
250
+ Comments and improvements welcome!
@@ -1,6 +1,6 @@
1
1
  module Calabash
2
2
  module Cucumber
3
- VERSION = '0.9.138'
4
- FRAMEWORK_VERSION = '0.9.138'
3
+ VERSION = '0.9.139'
4
+ FRAMEWORK_VERSION = '0.9.139'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calabash-cucumber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.138
4
+ version: 0.9.139
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-27 00:00:00.000000000 Z
12
+ date: 2013-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cucumber
@@ -195,6 +195,7 @@ files:
195
195
  - bin/calabash-ios-sim.rb
196
196
  - calabash-cucumber.gemspec
197
197
  - doc/calabash-ios-help.txt
198
+ - doc/x-platform-testing.md
198
199
  - epl-v10.html
199
200
  - features-skeleton/my_first.feature
200
201
  - features-skeleton/step_definitions/calabash_steps.rb