appium_lib 0.0.27 → 0.0.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/appium_lib.gemspec +1 -1
- data/docs.md +229 -0
- data/lib/appium_lib/console.rb +4 -1
- data/lib/appium_lib/element/android/generic.rb +42 -1
- data/lib/appium_lib/element/ios/generic.rb +100 -15
- data/lib/appium_lib/helper.rb +50 -1
- data/lib/appium_lib/version.rb +2 -2
- data/readme.md +5 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZWUwOTFmNDhjOWQ4YzBhYTVhZmQ4N2YyZDUxZWUyYmE4YTk1ZmY5OQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZGU2MjI1OWE0M2JjNDZjNzRhYzBiNGE0NWYyYjhlYmViMGI4NjQwMQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTM0NzQxNzdkNjc3YzhlMDJmMTEzNTViNzRmN2ZhNjFmMThhMGMzNzhmNGVk
|
10
|
+
NWRiMTg4M2IyZTE5ZWM1ZDdlM2NkNTEzMTJlMWVhYTU0OTczNDU4NDEyZGRk
|
11
|
+
MjVjYzY0M2ViYjg2MThkNGVmOTJlNjQxMDI0MDYwYjAwNmM4MmQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzYyNTk0NmMwMDlmYmEzM2RjN2Q0MzMwNDQ2ZDM5MTU5MTlmYzgwMzY0MWEw
|
14
|
+
NmY5NzA4OWYzYTAyMGVhMDBkMzYzNDJhMDFhYzIwYTI0OWI5Nzc3YzRiMjNj
|
15
|
+
YWU1ZmI3ZWUzZWJkOGY3MWUwMjRlZDhkZTRlZWViNjZiNDY3MjI=
|
data/appium_lib.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.homepage = 'https://github.com/appium/ruby_lib' # published as appium_lib
|
25
25
|
s.require_paths = [ 'lib' ]
|
26
26
|
|
27
|
-
s.add_runtime_dependency 'selenium-webdriver', '~> 2.
|
27
|
+
s.add_runtime_dependency 'selenium-webdriver', '~> 2.32.0'
|
28
28
|
s.add_runtime_dependency 'awesome_print', '~> 1.1.0'
|
29
29
|
|
30
30
|
s.add_development_dependency 'rake', '~> 10.0.3'
|
data/docs.md
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
#### Documentation
|
2
|
+
|
3
|
+
- find_elements returns an empty array [] when no elements are found.
|
4
|
+
|
5
|
+
##### [app_lib on rubydoc.info](http://www.rubydoc.info/github/appium/ruby_lib/master/toplevel)
|
6
|
+
|
7
|
+
- [iOS UI Automation](http://developer.apple.com/library/ios/#documentation/DeveloperTools/Reference/UIAutomationRef/_index.html) Example use `@driver.execute_script "UIATarget.localTarget().frontMostApp().mainWindow().rect()"
|
8
|
+
`
|
9
|
+
- [Android UIAutomator](http://developer.android.com/tools/help/uiautomator/index.html)
|
10
|
+
- [UiSelector.java](https://android.googlesource.com/platform/frameworks/testing/+/master/uiautomator/library/src/com/android/uiautomator/core/UiSelector.java)
|
11
|
+
- [Ruby selenium-webdriver](http://selenium.googlecode.com/svn/trunk/docs/api/rb/index.html)
|
12
|
+
- [Appium](https://github.com/appium/appium/blob/master/README.md)
|
13
|
+
- [Appium extension](https://github.com/appium/appium/wiki/Automating-mobile-gestures)
|
14
|
+
- [mechanic names of elements](https://github.com/jaykz52/mechanic/blob/8c490e1d225f384847e47ffdafb47cc2248bb96c/src/mechanic-core.js#L28)
|
15
|
+
- [All methods supported by Appium](https://github.com/appium/appium/wiki/JSON-Wire-Protocol:-Supported-Methods)
|
16
|
+
- [Appium's mobile gesture docs](https://github.com/appium/appium/wiki/Automating-mobile-gestures)
|
17
|
+
-
|
18
|
+
Example use of Appium's mobile gesture.
|
19
|
+
|
20
|
+
> @driver.execute_script 'mobile: tap', :x => 0, :y => 500
|
21
|
+
|
22
|
+
`console.rb` uses some code from [simple_test.rb](
|
23
|
+
https://github.com/appium/appium/blob/82995f47408530c80c3376f4e07a1f649d96ba22/sample-code/examples/ruby/simple_test.rb) and is released under the [same license](https://github.com/appium/appium/blob/c58eeb66f2d6fa3b9a89d188a2e657cca7cb300f/LICENSE) as Appium. The [Accessibility Inspector](https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/iPhoneAccessibility/Testing_Accessibility/Testing_Accessibility.html) is helpful for discovering button names and textfield values.
|
24
|
+
|
25
|
+
--
|
26
|
+
|
27
|
+
Tag Name | UIA
|
28
|
+
--:|:--
|
29
|
+
button | UIAButton
|
30
|
+
textfield | UIATextField
|
31
|
+
secure | UIASecureTextField
|
32
|
+
text | UIAStaticText
|
33
|
+
|
34
|
+
|
35
|
+
--
|
36
|
+
|
37
|
+
#### generic
|
38
|
+
|
39
|
+
- `source` Prints a JSON view of the current page.
|
40
|
+
- `page` Prints the content descriptions and text values on the current page.
|
41
|
+
- `(Element) find(value)` Returns the first element that contains value.
|
42
|
+
- `(Element) finds(value)` Returns all elements containing value (iOS only for now).
|
43
|
+
- `(Element) name(name)` Returns the first element containing name. Android name is the content description.
|
44
|
+
iOS uses accessibility label with a fallback to text.
|
45
|
+
- `(Array<Element>) names(name)` Returns all elements containing name.
|
46
|
+
- `(Element) text(text)` Returns the first element containing text.
|
47
|
+
- `(Array<Element>) texts(text)` Returns all elements containing text.
|
48
|
+
--
|
49
|
+
|
50
|
+
#### alert
|
51
|
+
0. `(void) alert_accept` Accept the alert.
|
52
|
+
0. `(String) alert_accept_text` Get the text of the alert's accept button.
|
53
|
+
0. `(void) alert_click(value)` iOS only Tap the alert button identified by value.
|
54
|
+
0. `(void) alert_dismiss` Dismiss the alert.
|
55
|
+
0. `(String) alert_dismiss_text` Get the text of the alert's dismiss button.
|
56
|
+
0. `(String) alert_text` Get the alert message text.
|
57
|
+
|
58
|
+
#### button
|
59
|
+
0. `(Button) button(index)` Find a button by index.
|
60
|
+
0. `(Button) button(text, number = 0)` Find a button by text and optionally number.
|
61
|
+
0. `(Button) button_include(text)` Get the first button that includes text.
|
62
|
+
0. `(Array<String>, Array<Buttons>) buttons(text = nil)` Get an array of button texts or button elements if text is provided.
|
63
|
+
0. `(Array<Button>) buttons_include(text)` Get all buttons that include text.
|
64
|
+
0. `(Button) first_button` Get the first button element.
|
65
|
+
0. `(Button) last_button` Get the last button element.
|
66
|
+
|
67
|
+
#### textfield
|
68
|
+
0. `(Textfield) textfield(index)` Find a textfield by index.
|
69
|
+
0. `(Array<Textfield>) e_textfields` Get an array of textfield elements.
|
70
|
+
0. `(Textfield) first_textfield` Get the first textfield element.
|
71
|
+
0. `(Textfield) last_textfield` Get the last textfield element.
|
72
|
+
0. `(Textfield) textfield(text)` Get the first textfield that matches text.
|
73
|
+
0. `(Textfield) textfield_include(text)` Get the first textfield that includes text.
|
74
|
+
0. `(Array<String>) textfields` Get an array of textfield texts.
|
75
|
+
|
76
|
+
#### text
|
77
|
+
|
78
|
+
The Static Text methods have been prefixed with `s_` to avoid conflicting with the generic text methods.
|
79
|
+
|
80
|
+
0. `(Text) s_text(index)` Find a text by index.
|
81
|
+
0. `(Array<Text>) s_e_texts` Get an array of text elements.
|
82
|
+
0. `(Text) s_first_text` Get the first text element.
|
83
|
+
0. `(Text) s_last_text` Get the last text element.
|
84
|
+
0. `(Text) s_text(text)` Get the first element that matches text.
|
85
|
+
0. `(Text) s_text_include(text)` Get the first textfield that includes text.
|
86
|
+
0. `(Array<String>) s_texts` Get an array of text texts.
|
87
|
+
|
88
|
+
#### window
|
89
|
+
0. `(Object) window_size` Get the window's size.
|
90
|
+
|
91
|
+
--
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
e.name # button, text
|
95
|
+
e.value # secure, textfield
|
96
|
+
e.type
|
97
|
+
e.tag_name # calls .type (patch.rb)
|
98
|
+
e.text
|
99
|
+
e.size
|
100
|
+
e.location
|
101
|
+
e.rel_location
|
102
|
+
e.click
|
103
|
+
e.send_keys 'keys to send'
|
104
|
+
e.set_value 'value to set' # ruby_console specific
|
105
|
+
|
106
|
+
# alert example without helper methods
|
107
|
+
alert = $driver.switch_to.alert
|
108
|
+
alert.text
|
109
|
+
alert.accept
|
110
|
+
alert.dismiss
|
111
|
+
|
112
|
+
# Secure textfield example.
|
113
|
+
#
|
114
|
+
# Find using default value
|
115
|
+
s = secure 'Password'
|
116
|
+
# Enter password
|
117
|
+
s.send_keys 'hello'
|
118
|
+
# Check value
|
119
|
+
s.value == password('hello'.length)
|
120
|
+
```
|
121
|
+
|
122
|
+
[routing.js](https://github.com/appium/appium/blob/master/app/routing.js#L69) lists not yet implemented end points.
|
123
|
+
|
124
|
+
--
|
125
|
+
|
126
|
+
#### Driver
|
127
|
+
|
128
|
+
`start_driver` will restart the driver.
|
129
|
+
|
130
|
+
`x` will quit the driver and exit Pry.
|
131
|
+
|
132
|
+
`execute_script` calls `$driver.execute_script`
|
133
|
+
|
134
|
+
`find_element` calls `$driver.find_element`
|
135
|
+
|
136
|
+
`find_elements` calls `$driver.find_elements`
|
137
|
+
|
138
|
+
`mobile :swipe, endX: 100, endY: 100, duration: 0.01` calls `$driver.execute_script 'mobile: swipe', endX: 100, endY: 100, duration: 0.01`
|
139
|
+
|
140
|
+
`no_wait` will set implicit wait to 0. `$driver.manage.timeouts.implicit_wait = 0`
|
141
|
+
|
142
|
+
`set_wait` will set implicit wait to default 30 seconds. `$driver.manage.timeouts.implicit_wait = 30`
|
143
|
+
|
144
|
+
`set_wait(timeout_seconds)` will set implicit wait to desired timeout. `$driver.manage.timeouts.implicit_wait = timeout`
|
145
|
+
|
146
|
+
.click to tap an element.
|
147
|
+
.send_keys to type on an element.
|
148
|
+
|
149
|
+
#### Raw UIAutomation
|
150
|
+
|
151
|
+
`execute_script "au.lookup('button')[0].tap()"` is the same as
|
152
|
+
`execute_script 'UIATarget.localTarget().frontMostApp().buttons()[0].tap()'`
|
153
|
+
|
154
|
+
See [app.js](https://github.com/appium/appium/blob/master/app/uiauto/appium/app.js#L3) for more au methods.
|
155
|
+
Note that raw UIAutomation commands are not offically supported.
|
156
|
+
|
157
|
+
Advanced au.
|
158
|
+
|
159
|
+
In this example we lookup two tags, combine the results, wrap with $, and then return the elements.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
s = %(
|
163
|
+
var t = au.lookup('textfield');
|
164
|
+
var s = au.lookup('secure');
|
165
|
+
var r = $(t.concat(s));
|
166
|
+
au._returnElems(r);
|
167
|
+
)
|
168
|
+
|
169
|
+
execute_script s
|
170
|
+
```
|
171
|
+
|
172
|
+
#### XPath
|
173
|
+
|
174
|
+
See [#194](https://github.com/appium/appium/pull/194/files) for details.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
find_element :xpath, 'button'
|
178
|
+
find_elements :xpath, 'button'
|
179
|
+
|
180
|
+
find_element :xpath, 'button[@name="Sign In"]'
|
181
|
+
find_elements :xpath, 'button[@name="Sign In"]'
|
182
|
+
|
183
|
+
find_element :xpath, 'button[contains(@name, "Sign In")]'
|
184
|
+
find_elements :xpath, 'button[contains(@name, "Sign")]'
|
185
|
+
|
186
|
+
find_element :xpath, 'textfield[@value="Email"]'
|
187
|
+
find_element :xpath, 'textfield[contains(@value, "Email")]'
|
188
|
+
|
189
|
+
find_element :xpath, 'text[contains(@name, "Reset")]'
|
190
|
+
find_elements :xpath, 'text[contains(@name, "agree")]'
|
191
|
+
```
|
192
|
+
|
193
|
+
#### Cucumber Sauce Integration
|
194
|
+
|
195
|
+
Reset after each test and when done report the result to Sauce after quiting the driver.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
require 'rest_client' # https://github.com/archiloque/rest-client
|
199
|
+
require 'json' # for .to_json
|
200
|
+
|
201
|
+
$passed = true
|
202
|
+
|
203
|
+
After do |scenario|
|
204
|
+
# Reset scenario unless the feature was tagged @keep
|
205
|
+
$driver.execute_script 'mobile: reset' unless scenario.feature.source_tag_names.include? '@keep'
|
206
|
+
|
207
|
+
if $passed
|
208
|
+
$passed = false if scenario.failed?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
at_exit do
|
213
|
+
ID = $driver.send(:bridge).session_id
|
214
|
+
$driver.quit
|
215
|
+
|
216
|
+
if !SAUCE_USERNAME.nil? && !SAUCE_ACCESS_KEY.nil?
|
217
|
+
URL = "https://#{SAUCE_USERNAME}:#{SAUCE_ACCESS_KEY}@saucelabs.com/rest/v1/#{SAUCE_USERNAME}/jobs/#{ID}"
|
218
|
+
|
219
|
+
# Keep trying until passed is set correctly. Give up after 30 seconds.
|
220
|
+
wait do
|
221
|
+
response = RestClient.put URL, { 'passed' => $passed }.to_json, :content_type => :json, :accept => :json
|
222
|
+
response = JSON.parse(response)
|
223
|
+
|
224
|
+
# Check that the server responded with the right value.
|
225
|
+
response['passed'] == $passed
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
```
|
data/lib/appium_lib/console.rb
CHANGED
@@ -112,7 +112,10 @@ end
|
|
112
112
|
def absolute_app_path
|
113
113
|
raise 'APP_PATH environment variable not set!' if APP_PATH.nil?
|
114
114
|
return APP_PATH if APP_PATH.match(/^http/) # public URL for Sauce
|
115
|
-
|
115
|
+
if APP_PATH.match(/^\//) # absolute file path
|
116
|
+
raise "App doesn't exist. #{APP_PATH}" unless File.exist? APP_PATH
|
117
|
+
return APP_PATH
|
118
|
+
end
|
116
119
|
file = File.join(File.dirname(__FILE__), APP_PATH)
|
117
120
|
raise "App doesn't exist #{file}" unless File.exist? file
|
118
121
|
file
|
@@ -10,6 +10,47 @@ find_element :name by default uses a partial case insensitive match.
|
|
10
10
|
On iOS the default is an exact name match.
|
11
11
|
=end
|
12
12
|
|
13
|
+
=begin
|
14
|
+
// iOS version
|
15
|
+
// https://github.com/appium/ruby_lib/blob/37bb4e90b29e5adb4438b287b6387a504c94b5c4/lib/appium_lib/element/ios/generic.rb#L23
|
16
|
+
var search = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'";
|
17
|
+
var a = w.secureTextFields().firstWithPredicate(search);
|
18
|
+
if ( isNil(a) ) {
|
19
|
+
a = w.textFields().firstWithPredicate(search);
|
20
|
+
if ( isNil(a) ) {
|
21
|
+
a = w.buttons().firstWithPredicate(search);
|
22
|
+
if ( isNil(a) ) {
|
23
|
+
a = w.elements().firstWithPredicate(search);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
Android considers both a textfield and a secure textfield to be "EditText".
|
29
|
+
Name (the content desc) is searched first and then we search for value (text).
|
30
|
+
There's no label in Android.
|
31
|
+
|
32
|
+
Android buttons have different class names (android.widget.Button, android.widget.ImageButton)
|
33
|
+
so we consider the element a button if the class name contains the word button.
|
34
|
+
|
35
|
+
After looking for textfields and buttons, then we search all elements. Find will return
|
36
|
+
the first element that matches.
|
37
|
+
=end
|
38
|
+
def find val
|
39
|
+
# s.className('android.widget.EditText').descriptionContains(value);
|
40
|
+
args = [ [4, 'android.widget.EditText'], [7, val] ],
|
41
|
+
# s.className('android.widget.EditText').textContains(value);
|
42
|
+
[ [4, 'android.widget.EditText'], [3, val] ],
|
43
|
+
# s.classNameMatches('(?i).*button.*').descriptionContains(value);
|
44
|
+
[ [26, '(?i).*button.*'], [7, val] ],
|
45
|
+
# s.classNameMatches('(?i).*button.*').textContains(value);
|
46
|
+
[ [26, '(?i).*button.*'], [3, val] ],
|
47
|
+
# s.descriptionContains(value);
|
48
|
+
[ [7, val] ],
|
49
|
+
# s.textContains(value);
|
50
|
+
[ [3, val] ]
|
51
|
+
mobile :find, args
|
52
|
+
end
|
53
|
+
|
13
54
|
# Return the first element matching text.
|
14
55
|
# @param text [String] the text to search for
|
15
56
|
# @return [Element] the first matching element
|
@@ -44,4 +85,4 @@ def names name
|
|
44
85
|
$driver.find_elements :name, name
|
45
86
|
end
|
46
87
|
|
47
|
-
end # if $os == :android
|
88
|
+
end # if $os == :android
|
@@ -5,17 +5,76 @@ name, names, text, text should match substring and case insensitive.
|
|
5
5
|
|
6
6
|
iOS .name() is the accessibility attribute. If not defined, then .label() is used instead.
|
7
7
|
This differs from Android where name (the content description) is empty when not set.
|
8
|
+
|
9
|
+
name defaults to label when undefined. value is never a default so that must be
|
10
|
+
included in a new search.
|
11
|
+
|
12
|
+
Find - search everything.
|
13
|
+
|
14
|
+
The search order is:
|
15
|
+
1. name
|
16
|
+
2. label (implied by name)
|
17
|
+
3. value
|
18
|
+
|
19
|
+
Android name = iOS name & label
|
20
|
+
Android text = iOS value
|
8
21
|
=end
|
9
22
|
|
23
|
+
def first_ele_js predicate
|
24
|
+
# returnElems requires a wrapped $(element).
|
25
|
+
# set to empty array when length is zero to prevent hang.
|
26
|
+
#
|
27
|
+
# UIAElementNil when not matched
|
28
|
+
#
|
29
|
+
# 1. secureTextFields
|
30
|
+
# 2. textFields
|
31
|
+
# 3. buttons
|
32
|
+
# 4. elements
|
33
|
+
%Q(
|
34
|
+
function isNil( a ) {
|
35
|
+
return a.type() === 'UIAElementNil';
|
36
|
+
}
|
37
|
+
|
38
|
+
var w = au.mainWindow;
|
39
|
+
var search = #{predicate};
|
40
|
+
var a = w.secureTextFields().firstWithPredicate(search);
|
41
|
+
if ( isNil(a) ) {
|
42
|
+
a = w.textFields().firstWithPredicate(search);
|
43
|
+
if ( isNil(a) ) {
|
44
|
+
a = w.buttons().firstWithPredicate(search);
|
45
|
+
if ( isNil(a) ) {
|
46
|
+
a = w.elements().firstWithPredicate(search);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
if ( a.length === 0 ) {
|
52
|
+
a = [];
|
53
|
+
}
|
54
|
+
|
55
|
+
au._returnElems($(a));
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def all_ele_js predicate
|
60
|
+
%Q(
|
61
|
+
var w = au.mainWindow;
|
62
|
+
var search = #{predicate};
|
63
|
+
var a = w.elements().withPredicate(search).toArray();
|
64
|
+
|
65
|
+
if ( a.length === 0 ) {
|
66
|
+
a = [];
|
67
|
+
}
|
68
|
+
|
69
|
+
au._returnElems($(a));
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
10
73
|
# Return the first element matching text.
|
11
74
|
# @param text [String] the text to search for
|
12
75
|
# @return [Element] the first matching element
|
13
|
-
def
|
14
|
-
#
|
15
|
-
js = %Q(
|
16
|
-
var element = $(au.mainWindow.elements().firstWithPredicate("name contains[c] '#{text}'"));
|
17
|
-
au._returnElems(element);
|
18
|
-
)
|
76
|
+
def find text
|
77
|
+
js = first_ele_js "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
|
19
78
|
|
20
79
|
execute_script(js).first
|
21
80
|
end
|
@@ -23,13 +82,32 @@ end
|
|
23
82
|
# Return all elements matching text.
|
24
83
|
# @param text [String] the text to search for
|
25
84
|
# @return [Array<Element>] all matching elements
|
26
|
-
def
|
85
|
+
def finds text
|
27
86
|
# returnElems requires a wrapped $(element).
|
28
87
|
# must call toArray when using withPredicate instead of firstWithPredicate.
|
29
|
-
js =
|
30
|
-
|
31
|
-
|
32
|
-
|
88
|
+
js = all_ele_js "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
|
89
|
+
|
90
|
+
execute_script js
|
91
|
+
end
|
92
|
+
|
93
|
+
# Return the first element matching text.
|
94
|
+
# @param text [String] the text to search for
|
95
|
+
# @return [Element] the first matching element
|
96
|
+
def text text
|
97
|
+
# TODO: Use XPath index once it's implemented
|
98
|
+
# https://github.com/appium/appium/issues/295
|
99
|
+
js = first_ele_js "value contains[c] '#{text}'"
|
100
|
+
|
101
|
+
execute_script(js).first
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return all elements matching text.
|
105
|
+
# @param text [String] the text to search for
|
106
|
+
# @return [Array<Element>] all matching elements
|
107
|
+
def texts text
|
108
|
+
# XPath //* is not implemented on iOS
|
109
|
+
# https://github.com/appium/appium/issues/430
|
110
|
+
js = all_ele_js "value contains[c] '#{text}'"
|
33
111
|
|
34
112
|
execute_script js
|
35
113
|
end
|
@@ -39,8 +117,10 @@ end
|
|
39
117
|
# on iOS name is the accessibility label or the text.
|
40
118
|
# @param name [String] the name to search for
|
41
119
|
# @return [Element] the first matching element
|
42
|
-
def name
|
43
|
-
text
|
120
|
+
def name text
|
121
|
+
js = first_ele_js "name contains[c] '#{text}' || label contains[c] '#{text}'"
|
122
|
+
|
123
|
+
execute_script(js).first
|
44
124
|
end
|
45
125
|
|
46
126
|
# Return all elements matching name.
|
@@ -48,8 +128,13 @@ end
|
|
48
128
|
# on iOS name is the accessibility label or the text.
|
49
129
|
# @param name [String] the name to search for
|
50
130
|
# @return [Array<Element>] all matching elements
|
51
|
-
def names
|
52
|
-
|
131
|
+
def names text
|
132
|
+
# find_elements :name is not the same as on Android.
|
133
|
+
# it's case sensitive and exact on iOS and not on Android.
|
134
|
+
# https://github.com/appium/appium/issues/379
|
135
|
+
js = all_ele_js "name contains[c] '#{text}' || label contains[c] '#{text}''"
|
136
|
+
|
137
|
+
execute_script js
|
53
138
|
end
|
54
139
|
|
55
140
|
end # if ios
|
data/lib/appium_lib/helper.rb
CHANGED
@@ -219,11 +219,60 @@ def get_inspect
|
|
219
219
|
out += " name: #{e[:desc]}\n" unless e[:desc].nil?
|
220
220
|
}
|
221
221
|
out
|
222
|
-
end
|
222
|
+
end if $os == :android
|
223
223
|
|
224
224
|
# Android only. Intended for use with console.
|
225
225
|
# Inspects and prints the current page.
|
226
226
|
def page
|
227
227
|
puts get_inspect
|
228
228
|
nil
|
229
|
+
end if $os == :android
|
230
|
+
|
231
|
+
def page element
|
232
|
+
|
233
|
+
def empty ele
|
234
|
+
(ele['name'] || ele['label'] || ele['value']) == nil
|
235
|
+
end
|
236
|
+
|
237
|
+
def fix_space s
|
238
|
+
# char code 160 (name, label) vs 32 (value) will break comparison.
|
239
|
+
# convert string to binary and remove 160.
|
240
|
+
# \xC2\xA0
|
241
|
+
s.force_encoding('binary').gsub("\xC2\xA0".force_encoding('binary'), ' ') if s
|
242
|
+
end
|
243
|
+
|
244
|
+
if ! empty( element )
|
245
|
+
puts "#{element['type']}"
|
246
|
+
name = fix_space element['name']
|
247
|
+
label = fix_space element['label']
|
248
|
+
value = fix_space element['value']
|
249
|
+
|
250
|
+
if name == label && name == value
|
251
|
+
puts " name, label, value: #{name}" if name
|
252
|
+
elsif name == label
|
253
|
+
puts " name, label: #{name}" if name
|
254
|
+
puts " value: #{value}" if value
|
255
|
+
elsif name == value
|
256
|
+
puts " name, value: #{name}" if name
|
257
|
+
puts " label: #{label}" if label
|
258
|
+
else
|
259
|
+
puts " name: #{name}" if name
|
260
|
+
puts " label: #{label}" if label
|
261
|
+
puts " value: #{value}" if value
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
children = element['children']
|
266
|
+
children.each { |c| page c } if children
|
267
|
+
nil
|
268
|
+
end if $os == :ios
|
269
|
+
|
270
|
+
# JavaScript code from https://github.com/appium/appium/blob/master/app/android.js
|
271
|
+
#
|
272
|
+
# Math.round((duration * 1000) / 200)
|
273
|
+
# (.20 * 1000) / 200 = 1
|
274
|
+
#
|
275
|
+
# We want steps to be exactly 1. If it's zero then a tap is used instead of a swipe.
|
276
|
+
def fast_duration
|
277
|
+
0.20
|
229
278
|
end
|
data/lib/appium_lib/version.rb
CHANGED
data/readme.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
- [appium_lib on RubyGems](https://rubygems.org/gems/appium_lib)
|
4
4
|
- [Documentation for appium_lib](http://www.rubydoc.info/github/appium/ruby_lib/master/frames)
|
5
|
+
- [Appium Ruby Console](https://github.com/appium/ruby_console)
|
5
6
|
|
6
7
|
Helper methods for writing cross platform (iPad, iPhone, Android) tests in Ruby using Appium.
|
7
|
-
There's also an [Appium Ruby Console](https://github.com/appium/ruby_console) which uses this lib.
|
8
8
|
|
9
9
|
Make sure you're using Ruby 1.9.3+ with upgraded rubygems and bundler.
|
10
10
|
|
@@ -29,3 +29,7 @@ gem install --no-rdoc --no-ri appium_lib
|
|
29
29
|
`pry -r ./lib/appium_lib.rb`
|
30
30
|
|
31
31
|
Then `start_driver`
|
32
|
+
|
33
|
+
#### Documentation
|
34
|
+
|
35
|
+
See [docs.md](https://github.com/appium/ruby_lib/blob/master/docs.md)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appium_lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.28
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- code@bootstraponline.com
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.32.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: 2.32.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: awesome_print
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- LICENSE-2.0.txt
|
65
65
|
- Rakefile
|
66
66
|
- appium_lib.gemspec
|
67
|
+
- docs.md
|
67
68
|
- lib/appium_lib.rb
|
68
69
|
- lib/appium_lib/console.rb
|
69
70
|
- lib/appium_lib/element/android/alert.rb
|