appium_lib 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +48 -14
  3. data/android_tests/Rakefile +5 -2
  4. data/android_tests/api.apk +0 -0
  5. data/android_tests/lib/android/specs/android/element/alert.rb +1 -1
  6. data/android_tests/lib/android/specs/android/element/button.rb +1 -4
  7. data/android_tests/lib/android/specs/android/element/text.rb +15 -18
  8. data/android_tests/lib/android/specs/android/element/textfield.rb +1 -4
  9. data/android_tests/lib/android/specs/android/helper.rb +4 -6
  10. data/android_tests/lib/android/specs/common/device.rb +16 -6
  11. data/android_tests/lib/android/specs/common/helper.rb +6 -6
  12. data/android_tests/lib/android/specs/common/patch.rb +3 -3
  13. data/android_tests/lib/android/specs/driver.rb +1 -1
  14. data/appium_lib.gemspec +11 -11
  15. data/docs/android_docs.md +193 -210
  16. data/docs/ios_docs.md +505 -177
  17. data/docs/migration.md +27 -0
  18. data/docs_gen/make_docs.rb +17 -17
  19. data/ios_tests/Rakefile +6 -3
  20. data/ios_tests/lib/ios/specs/common/helper.rb +1 -1
  21. data/ios_tests/lib/ios/specs/common/patch.rb +2 -2
  22. data/ios_tests/lib/ios/specs/device/device.rb +3 -2
  23. data/ios_tests/lib/ios/specs/device/multi_touch.rb +1 -1
  24. data/ios_tests/lib/ios/specs/device/touch_actions.rb +2 -2
  25. data/ios_tests/lib/ios/specs/driver.rb +5 -5
  26. data/ios_tests/lib/ios/specs/ios/element/alert.rb +5 -5
  27. data/ios_tests/lib/ios/specs/ios/element/button.rb +2 -5
  28. data/ios_tests/lib/ios/specs/ios/element/text.rb +21 -21
  29. data/ios_tests/lib/ios/specs/ios/element/textfield.rb +1 -8
  30. data/ios_tests/lib/ios/specs/ios/helper.rb +2 -2
  31. data/ios_tests/lib/ios/specs/ios/patch.rb +1 -1
  32. data/ios_tests/lib/run.rb +1 -1
  33. data/ios_tests/upload/sauce_storage.rb +13 -12
  34. data/ios_tests/upload/upload.rb +1 -1
  35. data/lib/appium_lib/android/dynamic.rb +31 -30
  36. data/lib/appium_lib/android/element/button.rb +7 -11
  37. data/lib/appium_lib/android/element/generic.rb +5 -5
  38. data/lib/appium_lib/android/element/text.rb +8 -12
  39. data/lib/appium_lib/android/element/textfield.rb +3 -7
  40. data/lib/appium_lib/android/helper.rb +46 -10
  41. data/lib/appium_lib/common/helper.rb +4 -2
  42. data/lib/appium_lib/common/patch.rb +1 -1
  43. data/lib/appium_lib/common/version.rb +2 -2
  44. data/lib/appium_lib/device/device.rb +34 -27
  45. data/lib/appium_lib/device/multi_touch.rb +1 -1
  46. data/lib/appium_lib/device/touch_actions.rb +30 -28
  47. data/lib/appium_lib/driver.rb +3 -3
  48. data/lib/appium_lib/ios/element/button.rb +4 -8
  49. data/lib/appium_lib/ios/element/text.rb +8 -12
  50. data/lib/appium_lib/ios/element/textfield.rb +3 -7
  51. data/lib/appium_lib/ios/helper.rb +70 -40
  52. data/readme.md +6 -70
  53. data/release_notes.md +26 -0
  54. metadata +3 -2
@@ -74,7 +74,7 @@ module Appium
74
74
  zoom.perform
75
75
  end
76
76
  end
77
-
77
+
78
78
  # Create a new multi-action
79
79
  def initialize
80
80
  @actions = []
@@ -9,20 +9,20 @@ module Appium
9
9
  # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
10
10
  # action.perform
11
11
  class TouchAction
12
- ACTIONS = [:move_to, :press_for_duration, :press, :release, :tap, :wait, :perform]
12
+ ACTIONS = [:move_to, :long_press, :press, :release, :tap, :wait, :perform]
13
13
  COMPLEX_ACTIONS = [:swipe]
14
-
14
+
15
15
  class << self
16
16
  COMPLEX_ACTIONS.each do |action|
17
17
  define_method(action) do |opts|
18
- auto_perform = opts.delete(:auto_perform) {|k| true}
19
- ta = TouchAction.new
18
+ auto_perform = opts.delete(:auto_perform) { |k| true }
19
+ ta = TouchAction.new
20
20
  ta.send(action, opts)
21
21
  return ta unless auto_perform
22
22
  ta.perform
23
23
  end
24
24
  end
25
- end
25
+ end
26
26
 
27
27
  attr_reader :actions
28
28
 
@@ -40,13 +40,14 @@ module Appium
40
40
  end
41
41
 
42
42
  # Press down for a specific duration.
43
- # @param element [WebDriver::Element] the element to press.
44
- # @param x [integer] x co-ordinate to press on.
45
- # @param y [integer] y co-ordinate to press on.
46
- # @param duration [integer] Number of seconds to press.
47
- def press_for_duration(element, x, y, duration)
48
- @actions << {element: element.ref, x: x, y: y, duration: duration}
49
- chain_method(:longPress, args)
43
+ # @option element [WebDriver::Element] the element to press.
44
+ # @option x [integer] x co-ordinate to press on.
45
+ # @option y [integer] y co-ordinate to press on.
46
+ # @option duration [integer] Number of milliseconds to press.
47
+ def long_press(opts)
48
+ args = opts.select { |k, v| [:element, :x, :y, :duration].include? k }
49
+ args = args_with_ele_ref(args)
50
+ chain_method(:longPress, args) # longPress is what the appium server expects
50
51
  end
51
52
 
52
53
  # Press a finger onto the screen. Finger will stay down until you call
@@ -56,7 +57,7 @@ module Appium
56
57
  # @option opts [integer] :x x co-ordinate to press on
57
58
  # @option opts [integer] :y y co-ordinate to press on
58
59
  def press(opts)
59
- args = opts.select {|k, v| [:element, :x, :y].include? k}
60
+ args = opts.select { |k, v| [:element, :x, :y].include? k }
60
61
  args = args_with_ele_ref(args)
61
62
  chain_method(:press, args)
62
63
  end
@@ -78,15 +79,16 @@ module Appium
78
79
  # @option opts [integer] :y y co-ordinate to tap
79
80
  # @option opts [integer] :fingers how many fingers to tap with (Default 1)
80
81
  def tap(opts)
81
- opts[:count] = opts.delete(:fingers) if opts[:fingers]
82
- opts_with_defaults = {count: 1}.merge opts
83
- chain_method(:tap, opts_with_defaults)
82
+ opts[:count] = opts.delete(:fingers) if opts[:fingers]
83
+ opts_with_defaults = { count: 1 }.merge opts
84
+ args = args_with_ele_ref opts
85
+ chain_method(:tap, args)
84
86
  end
85
87
 
86
- # Pause for a number of seconds before the next action
87
- # @param seconds [integer] Number of seconds to pause for
88
- def wait(seconds)
89
- args = {ms: seconds}
88
+ # Pause for a number of milliseconds before the next action
89
+ # @param milliseconds [integer] Number of milliseconds to pause for
90
+ def wait(milliseconds)
91
+ args = { ms: milliseconds }
90
92
  chain_method(:wait, args)
91
93
  end
92
94
 
@@ -95,12 +97,12 @@ module Appium
95
97
  # @option opts [int] :start_y Where to start swiping, on the y axis. Default 0.
96
98
  # @option opts [int] :end_x Where to end swiping, on the x axis. Default 0.
97
99
  # @option opts [int] :end_y Where to end swiping, on the y axis. Default 0.
98
- # @option opts [int] :duration How long the actual swipe takes to complete.
100
+ # @option opts [int] :duration How long the actual swipe takes to complete in milliseconds.
99
101
  def swipe(opts)
100
- start_x = opts.fetch :start_x, 0
101
- start_y = opts.fetch :start_y, 0
102
- end_x = opts.fetch :end_x, 0
103
- end_y = opts.fetch :end_y, 0
102
+ start_x = opts.fetch :start_x, 0
103
+ start_y = opts.fetch :start_y, 0
104
+ end_x = opts.fetch :end_x, 0
105
+ end_y = opts.fetch :end_y, 0
104
106
  duration = opts[:duration]
105
107
 
106
108
  self.press x: start_x, y: start_y
@@ -118,7 +120,7 @@ module Appium
118
120
 
119
121
  # Does nothing, currently.
120
122
  def cancel
121
- @actions << {action: cancel}
123
+ @actions << { action: cancel }
122
124
  $driver.touch_actions @actions
123
125
  self
124
126
  end
@@ -127,9 +129,9 @@ module Appium
127
129
 
128
130
  def chain_method(method, args=nil)
129
131
  if args
130
- @actions << {action: method, options: args}
132
+ @actions << { action: method, options: args }
131
133
  else
132
- @actions << {action: method}
134
+ @actions << { action: method }
133
135
  end
134
136
  self
135
137
  end
@@ -105,7 +105,7 @@ module Appium
105
105
  # ensure files are absolute
106
106
  r.map! do |file|
107
107
  file = File.exists?(file) ? file :
108
- File.join(parent_dir, file)
108
+ File.join(parent_dir, file)
109
109
  file = File.expand_path file
110
110
 
111
111
  File.exists?(file) ? file : nil
@@ -162,7 +162,7 @@ module Appium
162
162
  end
163
163
  # override unless there's an existing method with matching arity
164
164
  end unless const.respond_to?(m) &&
165
- const.method(m).arity == $driver.method(m).arity
165
+ const.method(m).arity == $driver.method(m).arity
166
166
  end
167
167
  end
168
168
  end
@@ -296,7 +296,7 @@ module Appium
296
296
  @@loaded = true
297
297
  # load device methods exactly once
298
298
  extend Appium::Device
299
-
299
+
300
300
  # Promote only on Minitest::Spec (minitest 5) by default
301
301
  Appium.promote_appium_methods ::Minitest::Spec
302
302
  end
@@ -13,10 +13,12 @@ module Appium
13
13
  xpath_visible_contains UIAButton, value
14
14
  end
15
15
 
16
- # Find all UIAButtons containing value
16
+ # Find all UIAButtons containing value.
17
+ # If value is omitted, all UIAButtons are returned.
17
18
  # @param value [String] the value to search for
18
19
  # @return [Array<UIAButton>]
19
- def buttons value
20
+ def buttons value=false
21
+ return tags UIAButton unless value
20
22
  xpaths_visible_contains UIAButton, value
21
23
  end
22
24
 
@@ -45,11 +47,5 @@ module Appium
45
47
  def buttons_exact value
46
48
  xpaths_visible_exact UIAButton, value
47
49
  end
48
-
49
- # Find all UIAButtons.
50
- # @return [Array<UIAButton>]
51
- def e_buttons
52
- tags UIAButton
53
- end
54
50
  end # module Ios
55
51
  end # module Appium
@@ -7,48 +7,44 @@ module Appium
7
7
  # @param value [String, Integer] the value to find.
8
8
  # If int then the UIAStaticText at that index is returned.
9
9
  # @return [UIAStaticText]
10
- def s_text value
10
+ def text value
11
11
  return ele_index UIAStaticText, value if value.is_a? Numeric
12
12
  xpath_visible_contains UIAStaticText, value
13
13
  end
14
14
 
15
15
  # Find all UIAStaticText containing value.
16
+ # If value is omitted, all UIAStaticTexts are returned
16
17
  # @param value [String] the value to search for
17
18
  # @return [Array<UIAStaticText>]
18
- def s_texts value
19
+ def texts value=false
20
+ return tags UIAStaticText unless value
19
21
  xpaths_visible_contains UIAStaticText, value
20
22
  end
21
23
 
22
24
  # Find the first UIAStaticText.
23
25
  # @return [UIAStaticText]
24
- def first_s_text
26
+ def first_text
25
27
  first_ele UIAStaticText
26
28
  end
27
29
 
28
30
  # Find the last UIAStaticText.
29
31
  # @return [UIAStaticText]
30
- def last_s_text
32
+ def last_text
31
33
  last_ele UIAStaticText
32
34
  end
33
35
 
34
36
  # Find the first UIAStaticText that exactly matches value.
35
37
  # @param value [String] the value to match exactly
36
38
  # @return [UIAStaticText]
37
- def s_text_exact value
39
+ def text_exact value
38
40
  xpath_visible_exact UIAStaticText, value
39
41
  end
40
42
 
41
43
  # Find all UIAStaticTexts that exactly match value.
42
44
  # @param value [String] the value to match exactly
43
45
  # @return [Array<UIAStaticText>]
44
- def s_texts_exact value
46
+ def texts_exact value
45
47
  xpaths_visible_exact UIAStaticText, value
46
48
  end
47
-
48
- # Find all UIAStaticTexts.
49
- # @return [Array<UIAStaticText>]
50
- def e_s_texts
51
- tags UIAStaticText
52
- end
53
49
  end # module Ios
54
50
  end # module Appium
@@ -49,9 +49,11 @@ module Appium
49
49
  end
50
50
 
51
51
  # Find all TextFields containing value.
52
+ # If value is omitted, all TextFields are returned.
52
53
  # @param value [String] the value to search for
53
54
  # @return [Array<TextField>]
54
- def textfields value
55
+ def textfields value=false
56
+ return xpaths _textfield_visible_string unless value
55
57
  xpaths _textfield_contains_string value
56
58
  end
57
59
 
@@ -80,11 +82,5 @@ module Appium
80
82
  def textfields_exact value
81
83
  xpaths _textfield_exact_string value
82
84
  end
83
-
84
- # Find all TextFields.
85
- # @return [Array<TextField>]
86
- def e_textfields
87
- xpaths _textfield_visible_string
88
- end
89
85
  end # module Ios
90
86
  end # module Appium
@@ -1,4 +1,4 @@
1
- module Appium
1
+ module Appium
2
2
  module Ios
3
3
  # iOS only. On Android uiautomator always returns an empty string for EditText password.
4
4
  #
@@ -6,7 +6,7 @@
6
6
  # @param length [Integer] the length of the password to generate
7
7
  # @return [String] the returned string is of size length
8
8
  def ios_password length=1
9
- '' * length
9
+ 8226.chr('UTF-8') * length
10
10
  end
11
11
 
12
12
  # Returns a string of interesting elements. iOS only.
@@ -14,10 +14,12 @@
14
14
  # Defaults to inspecting the 1st windows source only.
15
15
  # use get_page(get_source) for all window sources
16
16
  #
17
- # @param element [Object] the element to search. omit to search everything
17
+ # @option element [Object] the element to search. omit to search everything
18
+ # @option class_name [String,Symbol] the class name to filter on. case insensitive include match.
18
19
  # @return [String]
19
20
  def get_page element=source_window(0), class_name=nil
20
21
  lazy_load_strings # populate @strings_xml
22
+ class_name = class_name.to_s.downcase
21
23
 
22
24
  # @private
23
25
  def empty ele
@@ -50,43 +52,54 @@
50
52
  type = fix_space element['type']
51
53
 
52
54
  # if class_name is set, mark non-matches as invisible
53
- visible = (type == class_name).to_s if class_name
54
-
55
- if name == label && name == value
56
- puts "#{type}" if name || label || value || hint
57
- puts " name, label, value: #{name}" if name
58
- puts " hint: #{hint}" if hint
59
- elsif name == label
60
- puts "#{type}" if name || label || value || hint
61
- puts " name, label: #{name}" if name
62
- puts " value: #{value}" if value
63
- puts " hint: #{hint}" if hint
64
- elsif name == value
65
- puts "#{type}" if name || label || value || hint
66
- puts " name, value: #{name}" if name
67
- puts " label: #{label}" if label
68
- puts " hint: #{hint}" if hint
69
- else
70
- puts "#{type}" if name || label || value || hint
71
- puts " name: #{name}" if name
72
- puts " label: #{label}" if label
73
- puts " value: #{value}" if value
74
- puts " hint: #{hint}" if hint
75
- end if visible && visible == 'true'
76
-
77
- # there may be many ids with the same value.
78
- # output all exact matches.
79
- id_matches = @strings_xml.select do |key, val|
80
- val == name || val == label || val == value
81
- end
55
+ visible = (type.downcase.include?(class_name)).to_s if class_name
56
+ if visible && visible == 'true'
57
+ if name == label && name == value
58
+ puts "#{type}" if name || label || value || hint
59
+ puts " name, label, value: #{name}" if name
60
+ puts " hint: #{hint}" if hint
61
+ elsif name == label
62
+ puts "#{type}" if name || label || value || hint
63
+ puts " name, label: #{name}" if name
64
+ puts " value: #{value}" if value
65
+ puts " hint: #{hint}" if hint
66
+ elsif name == value
67
+ puts "#{type}" if name || label || value || hint
68
+ puts " name, value: #{name}" if name
69
+ puts " label: #{label}" if label
70
+ puts " hint: #{hint}" if hint
71
+ else
72
+ puts "#{type}" if name || label || value || hint
73
+ puts " name: #{name}" if name
74
+ puts " label: #{label}" if label
75
+ puts " value: #{value}" if value
76
+ puts " hint: #{hint}" if hint
77
+ end
78
+
79
+ # there may be many ids with the same value.
80
+ # output all exact matches.
81
+ attributes = [name, label, value, hint].select { |attr| !attr.nil? }
82
+ partial = {}
83
+ id_matches = @strings_xml.select do |key, val|
84
+ next if val.nil? || val.empty?
85
+ partial[key] = val if attributes.detect { |attr| attr.include?(val) }
86
+ attributes.detect { |attr| val == attr }
87
+ end
88
+
89
+ # If there are no exact matches, display partial matches.
90
+ id_matches = partial if id_matches.empty?
91
+
92
+ unless id_matches.empty?
93
+ match_str = ''
94
+ max_len = id_matches.keys.max_by(&:length).length
82
95
 
83
- if id_matches && id_matches.length > 0
84
- match_str = ''
85
- # [0] = key, [1] = value
86
- id_matches.each do |match|
87
- match_str += ' ' * 7 + "#{match[0]}\n"
96
+ # [0] = key, [1] = value
97
+ id_matches.each do |key, value|
98
+ arrow_space = ' ' * (max_len - key.length).to_i
99
+ match_str += ' ' * 7 + "#{key} #{arrow_space}=> #{value}\n"
100
+ end
101
+ puts " id: #{match_str.strip}\n"
88
102
  end
89
- puts " id: #{match_str.strip}\n"
90
103
  end
91
104
  end
92
105
 
@@ -96,10 +109,27 @@
96
109
  end
97
110
 
98
111
  # Prints a string of interesting elements to the console.
112
+ #
113
+ # Example
114
+ #
115
+ # ```ruby
116
+ # page class: :UIAButton # filter on buttons
117
+ # page window: 1 # show source for window 1
118
+ # page class: :UIAButton, window: 1
119
+ # ```
120
+ #
121
+ # @option window [Integer] window index. -1 for default
122
+ # @option class [Symbol] class name to filter on
123
+ #
99
124
  # @return [void]
100
125
  def page opts={}
101
- window_number = opts.fetch :window, -1
102
- class_name = opts.fetch :class, nil
126
+ if opts.is_a?(Hash)
127
+ window_number = opts.fetch :window, -1
128
+ class_name = opts.fetch :class, nil
129
+ else
130
+ window_number = -1
131
+ class_name = opts
132
+ end
103
133
 
104
134
  if window_number == -1
105
135
  # if the 0th window has no children, find the next window that does.
data/readme.md CHANGED
@@ -6,11 +6,11 @@
6
6
 
7
7
  Helper methods for writing cross platform (iOS, Android) tests in Ruby using Appium. Note that user waits should not exceed 120 seconds if they're going to run on Sauce Labs.
8
8
 
9
- Make sure you're using Ruby 1.9.3+ with upgraded rubygems and bundler.
9
+ Make sure you're using Appium 1.0.0 or newer and Ruby 1.9.3+ with upgraded rubygems and bundler.
10
10
 
11
11
  #### Start appium server
12
12
 
13
- `node server.js`
13
+ `node .`
14
14
 
15
15
  #### Install / Upgrade
16
16
 
@@ -28,84 +28,20 @@ gem uninstall -aIx appium_lib ;\
28
28
  gem install --no-rdoc --no-ri appium_lib
29
29
  ```
30
30
 
31
- #### Simple Usage
32
-
33
- ```ruby
34
- require 'rubygems'
35
- require 'appium_lib'
36
-
37
- # Start iOS driver
38
-
39
- # use appium's specific capability names
40
- appium_capabilities = { launchTimeout: 123 }
41
- # there are also built in capabilities such as device that don't require 'raw'
42
- caps = { device: :ios, app_path: '/Users/user/woven/ruby_lib_ios/UICatalog.app', raw: appium_capabilities }
43
- Appium::Driver.new(caps).start_driver
44
-
45
- # Start Android driver
46
- apk = {
47
- device: :android,
48
- app_path: '/path/to/the.apk',
49
- app_package: 'com.example.pkg',
50
- app_activity: '.act.Start',
51
- app_wait_activity: '.act.Start'
52
- }
53
- Appium::Driver.new(apk).start_driver
54
-
55
- # Define the methods on all objects.
56
- # Note that this can also be scoped to limit the potential for conflicts.
57
- # Example: Appium.promote_appium_methods ::Minitest::Spec
58
- # Another alternative is to not promote at all. Instead access methods via $driver
59
- Appium.promote_appium_methods Object
60
- ```
61
-
62
- ```ruby
63
- # Example of automating Settings preinstalled app on Android
64
- # Find these values using arc then type current_app
65
- apk = {
66
- device: :android,
67
- app_path: '',
68
- app_package: 'com.android.settings',
69
- app_activity: '.Settings',
70
- app_wait_activity: '.Settings'
71
- }
72
- Appium::Driver.new(apk).start_driver
73
- ```
74
-
75
- #### Other capabilities
76
-
77
- - `no_reset` If true, the app will not be reset
78
- - `full_reset` If true, the app will be uninstalled. When false, fast reset is activated.
79
-
80
- #### iOS env vars
81
-
82
- - `APP_PATH` Path to the .app folder
83
-
84
- #### Android env vars
85
-
86
- - `APP_PATH` Path to the apk
87
- - `APP_PACKAGE` The APK's package
88
- - `APP_ACTIVITY` Activity to start
89
- - `APP_WAIT_ACTIVITY` Optional. Activity to wait for.
90
-
91
31
  #### Sauce Labs env vars
92
32
 
93
- - `APP_NAME` Name of the test run
94
33
  - `SAUCE_USERNAME` Sauce username
95
34
  - `SAUCE_ACCESS_KEY` Sauce API key
96
35
 
97
36
  #### Troubleshooting
98
37
 
99
38
  1. Does `adb kill-server; adb devices` list an active Android device?
100
- 2. Have you defined the proper env vars? `APP_PATH, APP_PACKAGE, APP_ACTIVITY, APP_WAIT_ACTIVITY`
101
- 3. Are you running appium from source? `node server.js`
39
+ 3. Are you running appium from source? `node .`
102
40
 
103
41
  #### Documentation
104
42
 
105
43
  - [Installing Appium on OS X](https://github.com/appium/ruby_console/blob/master/osx.md)
106
44
  - [Overview](https://github.com/appium/ruby_lib/blob/master/docs/docs.md)
107
- - [Android methods](https://github.com/appium/ruby_lib/blob/master/docs/android_docs.md)
108
- - [iOS methods](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md)
109
- - [Appium docs](https://github.com/appium/appium/tree/master/docs)
110
- - [Ruby iOS tests](https://github.com/appium/ruby_lib_ios)
111
- - [Ruby Android tests](https://github.com/appium/ruby_lib_android)
45
+ - [Ruby Android methods](https://github.com/appium/ruby_lib/blob/master/docs/android_docs.md)
46
+ - [Ruby iOS methods](https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md)
47
+ - [Appium Server docs](https://github.com/appium/appium/tree/master/docs)