appium_lib 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTY2ZDQ0ZGExZTAzZjk4ZTU2YzBkMjBlYTdjZTE1MDk4NDJmZmZmZg==
5
+ data.tar.gz: !binary |-
6
+ ZTBjMjc1NzZhY2UzMTQxNjZkZTJhODM3NTE4ZDFlNGEyYmEzY2RkMg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZjU1ODExZDgwZWFhMmNhNjYwOWU0ZGRjMjk2YjAzMmM4NzllZWY0OTMzNDQy
10
+ ODg4ODI3NDQ4OWJlNzgwNzlhYWM1YzllNWM5ZWIyZjM1OTJmYWIwYzI4YTdh
11
+ ZjhkZTQ0NzI2NGMwNjRjZThmMmZmMGFjNWZiY2E2YWY3NzdlNGQ=
12
+ data.tar.gz: !binary |-
13
+ NGIxOWI1MTUzY2IxM2Q3OWFiZmEyNmFkYWI5ODA4M2M5ZTlkYmMwYmU0OTA4
14
+ OWYxNDBhODVlOWEyZjQ0YzA0MmRjMDQ2ZDg1NGZiYmYzNGMwOWYxZjAyYzU2
15
+ N2NjNjQ2NmJmMjMyNTU3NWJiYzJmN2E3NzI0Yzc1N2VkZWQ5YWQ=
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,78 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ # Defines gem name.
6
+ def repo_name; 'appium_lib'; end # ruby_lib published as appium_lib
7
+ def version_file; "lib/#{repo_name}/version.rb"; end
8
+ def version_rgx; /VERSION = '([^']+)'/m; end
9
+
10
+ def version
11
+ @version = @version || File.read(version_file).match(version_rgx)[1]
12
+ end
13
+
14
+ def bump
15
+ data = File.read version_file
16
+
17
+ v_line = data.match version_rgx
18
+ d_line = data.match /DATE = '([^']+)'/m
19
+
20
+ old_v = v_line[0]
21
+ old_d = d_line[0]
22
+
23
+ old_num = v_line[1]
24
+ new_num = old_num.split('.')
25
+ new_num[-1] = new_num[-1].to_i + 1
26
+ new_num = new_num.join '.'
27
+
28
+ new_v = old_v.sub old_num, new_num
29
+ puts "#{old_num} -> #{new_num}"
30
+
31
+ old_date = d_line[1]
32
+ new_date = Date.today.to_s
33
+ new_d = old_d.sub old_date, new_date
34
+ puts "#{old_date} -> #{new_date}" unless old_date == new_date
35
+
36
+ data.sub! old_v, new_v
37
+ data.sub! old_d, new_d
38
+
39
+ File.write version_file, data
40
+ end
41
+
42
+ desc 'Bump the version number and update the date.'
43
+ task :bump do
44
+ bump
45
+ end
46
+
47
+ # Inspired by Gollum's Rakefile
48
+ desc 'Build and release a new gem to rubygems.org'
49
+ task :release => :gem do
50
+ unless `git branch`.include? '* master'
51
+ puts 'Master branch required to release.'
52
+ exit!
53
+ end
54
+
55
+ # Commit then pull before pushing.
56
+ sh "git commit --allow-empty -am 'Release #{version}'"
57
+ sh 'git pull'
58
+ sh "git tag v#{version}"
59
+ sh 'git push origin master'
60
+ sh "git push origin v#{version}"
61
+ sh "gem push #{repo_name}-#{version}.gem"
62
+ end
63
+
64
+ desc 'Build a new gem'
65
+ task :gem do
66
+ `chmod 0600 ~/.gem/credentials`
67
+ sh "gem build #{repo_name}.gemspec"
68
+ end
69
+
70
+ desc 'Build a new gem (same as gem task)'
71
+ task :build => :gem do
72
+ end
73
+
74
+ desc 'Install gem'
75
+ task :install => :gem do
76
+ `gem uninstall -aIx #{repo_name}`
77
+ sh "gem install --no-rdoc --no-ri #{repo_name}-#{version}.gem"
78
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ def self.add_to_path path
4
+ path = File.expand_path "../#{path}/", __FILE__
5
+
6
+ $:.unshift path unless $:.include? path
7
+ end
8
+
9
+ add_to_path 'lib'
10
+
11
+ require 'appium_lib/version'
12
+
13
+ Gem::Specification.new do |s|
14
+ # 1.8.x is not supported
15
+ s.required_ruby_version = '>= 1.9.3'
16
+
17
+ s.name = 'appium_lib'
18
+ s.version = AppiumLib::VERSION
19
+ s.date = AppiumLib::DATE
20
+ s.license = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
21
+ s.description = s.summary = 'Ruby lib for use with Appium'
22
+ s.description += '.' # avoid identical warning
23
+ s.authors = s.email = [ 'code@bootstraponline.com' ]
24
+ s.homepage = 'https://github.com/appium/ruby_lib' # published as appium_lib
25
+ s.require_paths = [ 'lib' ]
26
+
27
+ s.add_runtime_dependency 'selenium-webdriver', '~> 2.31.0'
28
+ s.add_runtime_dependency 'awesome_print', '~> 1.1.0'
29
+
30
+ s.add_development_dependency 'rake', '~> 10.0.3'
31
+
32
+ s.files = `git ls-files`.split "\n"
33
+ end
@@ -0,0 +1,10 @@
1
+ def self.add_to_path file, path=false
2
+ path = path ? "../#{path}/" : '..'
3
+ path = File.expand_path path, file
4
+
5
+ $:.unshift path unless $:.include? path
6
+ end
7
+
8
+ add_to_path __FILE__, 'appium_lib'
9
+
10
+ require 'console'
@@ -0,0 +1,207 @@
1
+ # encoding: utf-8
2
+ =begin
3
+ Run with:
4
+ pry -r ./console.rb
5
+
6
+ Based on simple_test.rb
7
+ https://github.com/appium/appium/blob/82995f47408530c80c3376f4e07a1f649d96ba22/sample-code/examples/ruby/simple_test.rb
8
+ https://github.com/appium/appium/blob/c58eeb66f2d6fa3b9a89d188a2e657cca7cb300f/LICENSE
9
+ =end
10
+
11
+ add_to_path __FILE__
12
+ add_to_path __FILE__, 'element'
13
+
14
+ require 'selenium-webdriver'
15
+
16
+ # Path to the .app or .app.zip.
17
+ # The path can be local or remote for Sauce.
18
+ APP_PATH = ENV['APP_PATH'] unless defined?(APP_PATH)
19
+ raise "APP_PATH must be set." if APP_PATH.nil?
20
+
21
+ # The name to use for the test run on Sauce.
22
+ APP_NAME = ENV['APP_NAME'] unless defined?(APP_NAME)
23
+
24
+ # Android app package
25
+ APP_PACKAGE = ENV['APP_PACKAGE'] unless defined?(APP_PACKAGE)
26
+
27
+ # Android app starting activity.
28
+ APP_ACTIVITY = ENV['APP_ACTIVITY'] unless defined?(APP_ACTIVITY)
29
+
30
+ # Sauce Username
31
+ SAUCE_USERNAME = ENV['SAUCE_USERNAME'] unless defined?(SAUCE_USERNAME)
32
+
33
+ # Sauce Key
34
+ SAUCE_ACCESS_KEY = ENV['SAUCE_ACCESS_KEY'] unless defined?(SAUCE_ACCESS_KEY)
35
+
36
+ PORT = ENV['PORT'] || 4723 unless defined?(PORT)
37
+
38
+ $os = nil
39
+
40
+ if $os.nil?
41
+ $os = :ios
42
+ $os = :android if APP_PATH.end_with?('.apk') || APP_PATH.end_with?('.apk.zip')
43
+ end
44
+
45
+ puts "OS is: #{$os}" if defined?(Pry)
46
+
47
+ if $os == :android
48
+ raise "APP_PACKAGE must be set." if APP_PACKAGE.nil?
49
+ raise "APP_ACTIVITY must be set." if APP_ACTIVITY.nil?
50
+ end
51
+
52
+ # ruby_console files load depending on OS
53
+ require 'helper'
54
+ require 'button'
55
+ require 'text'
56
+ require 'window'
57
+ require 'patch'
58
+ require 'alert'
59
+
60
+ # Android combines secure and textfield.
61
+ # iOS differentiates between secure and textfield.
62
+ # combine secure & textfield on iOS to match Android behavior.
63
+ $os == :ios ? require('ios/textfield') :
64
+ require('android/textfield')
65
+
66
+ # WebDriver capabilities. Must be valid for Sauce to work.
67
+ # https://github.com/jlipps/appium/blob/master/app/android.js
68
+ def android_capabilities
69
+ {
70
+ browserName: 'Android',
71
+ platform: 'LINUX',
72
+ version: '4.1',
73
+ device: 'Android',
74
+ name: APP_NAME || 'Ruby Console Android Appium',
75
+ app: absolute_app_path,
76
+ :'app-package' => APP_PACKAGE,
77
+ :'app-activity' => APP_ACTIVITY
78
+ }
79
+ end
80
+
81
+ # WebDriver capabilities. Must be valid for Sauce to work.
82
+ def ios_capabilities
83
+ {
84
+ browserName: 'iOS 6.0',
85
+ platform: 'Mac 10.8',
86
+ version: '6.0',
87
+ device: 'iPhone Simulator',
88
+ name: APP_NAME || 'Ruby Console iOS Appium',
89
+ app: absolute_app_path
90
+ }
91
+ end
92
+
93
+ def capabilities
94
+ $os == :ios ? ios_capabilities : android_capabilities
95
+ end
96
+
97
+ # Converts environment variable APP_PATH to an absolute path.
98
+ # @return [String] APP_PATH as an absolute path
99
+ def absolute_app_path
100
+ raise 'APP_PATH environment variable not set!' if APP_PATH.nil?
101
+ return APP_PATH if APP_PATH.match(/^http/) # public URL for Sauce
102
+ return APP_PATH if APP_PATH.match(/^\//) # absolute file path
103
+ file = File.join(File.dirname(__FILE__), APP_PATH)
104
+ raise "App doesn't exist #{file}" unless File.exist? file
105
+ file
106
+ end
107
+
108
+ # Get the server url for sauce or local based on env vars.
109
+ # @return [String] the server url
110
+ def server_url
111
+ if !SAUCE_USERNAME.nil? && !SAUCE_ACCESS_KEY.nil?
112
+ "http://#{SAUCE_USERNAME}:#{SAUCE_ACCESS_KEY}@ondemand.saucelabs.com:80/wd/hub"
113
+ else
114
+ "http://127.0.0.1:#{PORT}/wd/hub"
115
+ end
116
+ end
117
+
118
+ # Quits the driver
119
+ # @return [void]
120
+ def driver_quit
121
+ # rescue NoSuchDriverError
122
+ begin; $driver.quit unless $driver.nil?; rescue; end
123
+ end
124
+
125
+ # Creates a new global driver and quits the old one if it exists.
126
+ # @return [Selenium::WebDriver] the new global driver
127
+ def start_driver
128
+ @client = @client || Selenium::WebDriver::Remote::Http::Default.new
129
+ @client.timeout = 999999
130
+
131
+ # If the driver already exists, quit before creating a new driver.
132
+ driver_quit
133
+
134
+ begin
135
+ $driver = Selenium::WebDriver.for(:remote, http_client: @client, desired_capabilities: capabilities, url: server_url)
136
+ rescue Errno::ECONNREFUSED
137
+ puts 'ERROR: Unable to connect to Appium. Is the server running?'
138
+ exit
139
+ end
140
+
141
+ # Set timeout to a large number so that Appium doesn't quit
142
+ # when no commands are entered after 60 seconds.
143
+ $driver.execute_script 'mobile: setCommandTimeout', timeout: 9999
144
+
145
+ # Must set implicit_wait to zero or $ commands will fail.
146
+ # execute_script "$('button')"
147
+ # $ commands fail anyway now so set implicit wait.
148
+ # https://github.com/appium/appium/issues/214
149
+ $driver.manage.timeouts.implicit_wait = 30
150
+
151
+ $driver
152
+ end
153
+
154
+ # Set implicit wait to zero.
155
+ def no_wait
156
+ $driver.manage.timeouts.implicit_wait = 0
157
+ end
158
+
159
+ # Set implicit wait to timeout, defaults to 30.
160
+ # @param timeout [Integer] the timeout in seconds
161
+ # @return [void]
162
+ def set_wait timeout=30
163
+ $driver.manage.timeouts.implicit_wait = timeout
164
+ end
165
+
166
+ # The same as $driver.execute_script
167
+ # @return the object returned by execute_script
168
+ def execute_script script, *args
169
+ $driver.execute_script script, *args
170
+ end
171
+
172
+ # Helper method for mobile gestures
173
+ #
174
+ # https://github.com/appium/appium/wiki/Automating-mobile-gestures
175
+ #
176
+ # $driver.execute_script 'mobile: swipe', endX: 100, endY: 100, duration: 0.01
177
+ #
178
+ # becomes
179
+ #
180
+ # mobile :swipe, endX: 100, endY: 100, duration: 0.01
181
+ def mobile method, *args
182
+ raise "Method must not be nil" if method.nil?
183
+ raise "Method must have .to_s" unless method.respond_to? :to_s
184
+ $driver.execute_script "mobile: #{method.to_s}", *args
185
+ end
186
+
187
+ # Calls $driver.find_elements
188
+ def find_elements *args
189
+ $driver.find_elements *args
190
+ end
191
+
192
+ # Calls $driver.find_elements
193
+ def find_element *args
194
+ $driver.find_element *args
195
+ end
196
+
197
+ # Quit the driver and Pry.
198
+ # quit and exit are reserved by Pry.
199
+ def x
200
+ driver_quit
201
+ exit # exit pry
202
+ end
203
+
204
+ # Paging in Pry is annoying :q required to exit.
205
+ # With pager disabled, the output is similar to IRB
206
+ # Only set if Pry is defined.
207
+ Pry.config.pager = false if defined?(Pry)
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ # iOS only
4
+ # Tap the alert button identified by value.
5
+ # @param value [Integer, String] either an integer index of the button or the button's name
6
+ # @return [void]
7
+ def alert_click value
8
+ $driver.execute_script "UIATarget.localTarget().frontMostApp().alert().buttons()[#{value}].tap();"
9
+ end
10
+
11
+ # Get the alert message text.
12
+ # @return [String]
13
+ def alert_text
14
+ $driver.switch_to.alert.text
15
+ end
16
+
17
+ # Accept the alert.
18
+ # @return [void]
19
+ def alert_accept
20
+ $driver.switch_to.alert.accept
21
+ end
22
+
23
+ # Get the text of the alert's accept button.
24
+ # The last button is considered "accept."
25
+ # @return [String]
26
+ def alert_accept_text
27
+ a = $driver.find_element(:tag_name, :alert)
28
+ return if a.nil?
29
+ b = a.find_elements(:tag_name, :button)
30
+ b.last.text if b && b.size >= 1
31
+ end
32
+
33
+ # Dismiss the alert.
34
+ # @return [void]
35
+ def alert_dismiss
36
+ $driver.switch_to.alert.dismiss
37
+ end
38
+
39
+ # Get the text of the alert's dismiss button.
40
+ # The first button is considered "dismiss."
41
+ # @return [String]
42
+ def alert_dismiss_text
43
+ a = $driver.find_element(:tag_name, :alert)
44
+ return if a.nil?
45
+ b = a.find_elements(:tag_name, :button)
46
+ b.first.text if b && b.size >= 1
47
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ # UIATextField methods
3
+
4
+ if $os == :android
5
+
6
+ # Get an array of textfield texts.
7
+ # @return [Array<String>]
8
+ def textfields
9
+ find_eles_attr :textfield, :text
10
+ end
11
+
12
+ # Get an array of textfield elements.
13
+ # @return [Array<Textfield>]
14
+ def e_textfields
15
+ find_eles :textfield
16
+ end
17
+
18
+ # Get the first textfield element.
19
+ # @return [Textfield]
20
+ def first_textfield
21
+ first_ele :textfield
22
+ end
23
+
24
+ # Get the last textfield element.
25
+ # @return [Textfield]
26
+ def last_textfield
27
+ last_ele :textfield
28
+ end
29
+
30
+ # Get the first textfield that matches text.
31
+ # @param text [String, Integer] the text to match exactly. If int then the textfield at that index is returned.
32
+ # @return [Textfield]
33
+ def textfield text
34
+ return ele_index :textfield, text if text.is_a? Numeric
35
+ find_ele_by_text :textfield, text
36
+ end
37
+
38
+ # Get the first textfield that includes text.
39
+ # @param text [String] the text the textfield must include
40
+ # @return [Textfield]
41
+ def textfield_include text
42
+ find_ele_by_text_include :textfield, text
43
+ end
44
+
45
+ end # if $os
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ # UIAButton methods
3
+
4
+ =begin
5
+ Method Signatures:
6
+
7
+ button( text, number = -1 )
8
+ buttons( text = nil )
9
+ button_include( text )
10
+ buttons_include( text )
11
+ first_button
12
+ last_button
13
+
14
+ Examples:
15
+
16
+ button 'text' # 1st button exactly matching text
17
+ button 'text', 2 # 2nd button exactly matching text
18
+
19
+ buttons # text of all buttons.
20
+ buttons 'text' # all buttons exactly matching text
21
+
22
+ button_include 'text' # the first button that includes text
23
+ buttons_include 'text' # all buttons that include text
24
+
25
+ first_button # the first button
26
+ last_button # the last button
27
+ =end
28
+
29
+ # Find a button by text and optionally number.
30
+ # @param text [String, Integer] the text to exactly match. If int then the button at that index is returned.
31
+ # @param number [Integer] the occurance of the button matching text. Defaults to the first button.
32
+ # @return [Button] the button found with text and matching number
33
+ def button text, number=0
34
+ return ele_index :button, text if text.is_a? Numeric
35
+
36
+ number >= 1 ? button_text_num( text, number ) :
37
+ button_text( text )
38
+ end
39
+
40
+ # Get an array of button texts or button elements if text is provided.
41
+ # @param text [String] the text to exactly match
42
+ # @return [Array<String>, Array<Buttons>] either an array of button texts or an array of button elements if text is provided.
43
+ def buttons text=nil
44
+ text == nil ? find_eles_attr(:button, :text) :
45
+ find_ele_by_text(:button, text)
46
+ end
47
+
48
+ # Get the first button that includes text.
49
+ # @param text [String] the text that the element must include
50
+ # @return [Button]
51
+ def button_include text
52
+ find_ele_by_text_include :button, text
53
+ end
54
+
55
+ # Get all buttons that include text.
56
+ # @param text [String] the text that the element must include
57
+ # @return [Array<Button>]
58
+ def buttons_include text
59
+ find_eles_by_text_include :button, text
60
+ end
61
+
62
+ # Get the first button element.
63
+ # @return [Button]
64
+ def first_button
65
+ first_ele :button
66
+ end
67
+
68
+ # Get the last button element.
69
+ # @return [Button]
70
+ def last_button
71
+ last_ele :button
72
+ end
73
+
74
+ # -- prefer above methods before using these.
75
+ private
76
+
77
+ # Get the first button element that exactly matches text.
78
+ # @param text [String] the text to match exactly
79
+ # @return [Button]
80
+ def button_text text
81
+ find_ele_by_text :button, text
82
+ end
83
+
84
+ # Get the button element exactly matching text and
85
+ # occurrence. number=2 means the 2nd occurrence.
86
+ #
87
+ # find the second Sign In button
88
+ #
89
+ # b = e_button 'Sign In', 2
90
+ #
91
+ # Button order will change in iOS vs Android
92
+ # so if there's no button found at number then
93
+ # return the first button.
94
+ #
95
+ # @param text [String] the text to match exactly
96
+ # @param number [Integer] the button occurance to return. 1 = first button
97
+ # @return [Button] the button that exactly matches text and number
98
+ def button_text_num text, number=1
99
+ raise "Number must be >= 1" if number <= 0
100
+ number = number - 1 # zero indexed
101
+
102
+ result = nil
103
+
104
+ elements = find_eles_by_text :button, text
105
+ elements.size > number ? result = elements[number]
106
+ : result = elements.first
107
+
108
+ result
109
+ end
110
+
111
+ # Get an array of button elements.
112
+ # @return [Array<Button>]
113
+ def e_buttons
114
+ find_eles :button
115
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+ # UIATextField & UIASecureTextField methods
3
+ #
4
+ # Find textfield and then secure elements in one server call
5
+ # to match Android.
6
+
7
+ if $os == :ios
8
+
9
+ # Get an array of textfield texts.
10
+ # @return [Array<String>]
11
+ def textfields
12
+ find_2_eles_attr :textfield, :secure, :text
13
+ end
14
+
15
+ # Get an array of textfield elements.
16
+ # @return [Array<Textfield>]
17
+ def e_textfields
18
+ execute_script textfield_js
19
+ end
20
+
21
+ # Get the first textfield element.
22
+ # @return [Textfield]
23
+ def first_textfield
24
+ js = textfield_js 'r = r.length > 0 ? $(r[0]) : r;'
25
+ execute_script(js).first
26
+ end
27
+
28
+ # Get the last textfield element.
29
+ # @return [Textfield]
30
+ def last_textfield
31
+ js = textfield_js 'r = r.length > 0 ? $(r[r.length - 1]) : r;'
32
+ execute_script(js).first
33
+ end
34
+
35
+ # Get the first textfield that matches text.
36
+ # @param text [String, Integer] the text to match exactly. If int then the textfield at that index is returned.
37
+ # @return [Textfield]
38
+ def textfield text
39
+ # Don't use ele_index because that only works on one element type.
40
+ # iOS needs to combine textfield and secure to match Android.
41
+ if text.is_a? Numeric
42
+ js = textfield_js 'r = r.length > 0 ? $(r[#{text}]) : r;'
43
+ return execute_script(js).first
44
+ end
45
+
46
+ # find_ele_by_text :textfield, text
47
+ js = %Q(
48
+ var t = au.getElementsByXpath('textfield[@text="#{text}"]').value;
49
+ var s = au.getElementsByXpath('secure[@text="#{text}"]').value;
50
+ t.concat(s)[0];
51
+ )
52
+
53
+ puts js if defined?(Pry)
54
+
55
+ execute_script js
56
+ end
57
+
58
+ # Get the first textfield that includes text.
59
+ # @param text [String] the text the textfield must include
60
+ # @return [Textfield]
61
+ def textfield_include text
62
+ js = %Q(
63
+ var t = au.getElementsByXpath('textfield[contains(@text, "#{text}")]').value;
64
+ var s = au.getElementsByXpath('secure[contains(@text, "#{text}")]').value;
65
+ t.concat(s)[0];
66
+ )
67
+
68
+ puts js if defined?(Pry)
69
+
70
+ execute_script js
71
+ end
72
+
73
+ private
74
+
75
+ # Return combined lookup of textfield and secure
76
+ # with an optional filter. $() wrap is required for .each
77
+ def textfield_js filter=''
78
+ %Q(
79
+ var t = au.lookup('textfield');
80
+ var s = au.lookup('secure');
81
+ var r = $(t.concat(s));
82
+ #{filter}
83
+ au._returnElems(r);
84
+ )
85
+ end
86
+
87
+ end # if $os
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ # UIAStaticText methods
3
+
4
+ # Get an array of text texts.
5
+ # @return [Array<String>]
6
+ def texts
7
+ find_eles_attr :text, :text
8
+ end
9
+
10
+ # Get an array of text elements.
11
+ # @return [Array<Text>]
12
+ def e_texts
13
+ find_eles :text
14
+ end
15
+
16
+ # Get the first text element.
17
+ # @return [Text]
18
+ def first_text
19
+ first_ele :text
20
+ end
21
+
22
+ # Get the last text element
23
+ # @return [Text]
24
+ def last_text
25
+ last_ele :text
26
+ end
27
+
28
+ # Get the first element that matches text.
29
+ # @param text [String, Integer] the text to find exactly. If int then the text at that index is returned.
30
+ # @return [Text]
31
+ def text text
32
+ return ele_index :text, text if text.is_a? Numeric
33
+ find_ele_by_text :text, text
34
+ end
35
+
36
+ # Get the first textfield that includes text.
37
+ # @param text [String] the text that the tag must include
38
+ # @return [Text]
39
+ def text_include text
40
+ find_ele_by_text_include :text, text
41
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ # UIAWindow methods
3
+
4
+ # Get the window's size
5
+ #
6
+ # window_size.width
7
+ #
8
+ # window_size.height
9
+ def window_size
10
+ return nil if $driver.nil?
11
+ $driver.manage.window.size
12
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+ # Generic helper methods not specific
3
+ # to a particular tag name
4
+
5
+ # json and ap are required for the source method.
6
+ require 'json'
7
+ require 'ap' # awesome print
8
+ require 'timeout' # for wait
9
+
10
+ # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
11
+ # Android .name returns the accessibility attribute and nothing if it's not set.
12
+ #
13
+ # .text should be cross platform so prefer that over name, unless both
14
+ # Android and iOS have proper accessibility attributes.
15
+ # .text and .value should be the same so use .text over .value.
16
+ #
17
+ # secure tag_name is iOS only because it can't be implemented using uiautomator for Android.
18
+ #
19
+ # find_element :text doesn't work so use XPath to find by text.
20
+
21
+ # Check every 0.5 seconds to see if block.call is true.
22
+ # Give up after 30 seconds.
23
+ # @param block [Block] the block to call
24
+ # @return [Object] the result of block.call
25
+ def wait &block
26
+ # Rescue Timeout::Error: execution expired
27
+ result = nil
28
+ timeout(30) { while(!(result = begin;block.call;rescue;end)) do; sleep(0.5) end }
29
+ result
30
+ end
31
+
32
+ # Presses the back button on Android.
33
+ # @return [void]
34
+ def back
35
+ $driver.navigate.back
36
+ end
37
+
38
+ # Get the element of type tag_name at matching index.
39
+ # @param tag_name [String] the tag name to find
40
+ # @param index [Integer] the index
41
+ # @return [Element] the found element of type tag_name
42
+ def ele_index tag_name, index
43
+ find_eles(tag_name)[index]
44
+ end
45
+
46
+ # Get all elements exactly matching tag name
47
+ # @param tag_name [String] the tag name to find
48
+ # @return [Array<Element>] the found elements of type tag_name
49
+ def find_eles tag_name
50
+ $driver.find_elements :tag_name, tag_name
51
+ end
52
+
53
+ # iOS only. Android uses uiautomator instead of uiautomation.
54
+ # Get an array of attribute values from elements exactly matching tag name.
55
+ # @param tag_name [String] the tag name to find
56
+ # @param attribute [String] the attribute to collect
57
+ # @result [Array<String>] an array of strings containing the attribute from found elements of type tag_name.
58
+ def find_eles_attr tag_name, attribute
59
+ # Use au.lookup(tag_name) instead of $(tag_name)
60
+ # See https://github.com/appium/appium/issues/214
61
+ js = %Q(
62
+ var eles = au.lookup('#{tag_name}');
63
+ var result = [];
64
+ for (var a = 0, length = eles.length; a < length; a++) {
65
+ result.push(eles[a].#{attribute}());
66
+ }
67
+ result
68
+ )
69
+
70
+ $driver.execute_script js
71
+ end
72
+
73
+ # iOS only. Android uses uiautomator instead of uiautomation.
74
+ # Get an array of attribute values from elements exactly matching tag name.
75
+ # @param tag_name_1 [String] the 1st tag name to find
76
+ # @param tag_name_2 [String] the 2nd tag name to find
77
+ # @param attribute [String] the attribute to collect
78
+ # @result [Array<String>] an array of strings containing the attribute from found elements of type tag_name.
79
+ def find_2_eles_attr tag_name_1, tag_name_2, attribute
80
+ # Use au.lookup(tag_name) instead of $(tag_name)
81
+ # See https://github.com/appium/appium/issues/214
82
+ js = %Q(
83
+ var eles = au.lookup('#{tag_name_1}');
84
+ eles = $(eles.concat(au.lookup('#{tag_name_2}')));
85
+ var result = [];
86
+ for (var a = 0, length = eles.length; a < length; a++) {
87
+ result.push(eles[a].#{attribute}());
88
+ }
89
+ result
90
+ )
91
+
92
+ $driver.execute_script js
93
+ end
94
+
95
+ # Get the first tag that exactly matches tag and text.
96
+ # @param tag [String] the tag name to match
97
+ # @param text [String] the text to exactly match
98
+ # @return [Element] the element of type tag exactly matching text
99
+ def find_ele_by_text tag, text
100
+ $driver.find_element :xpath, %Q(#{tag}[@text='#{text}'])
101
+ end
102
+
103
+ # Get all tags that exactly match tag and text.
104
+ # @param tag [String] the tag name to match
105
+ # @param text [String] the text to exactly match
106
+ # @return [Array<Element>] the elements of type tag exactly matching text
107
+ def find_eles_by_text tag, text
108
+ $driver.find_elements :xpath, %Q(#{tag}[@text='#{text}'])
109
+ end
110
+
111
+ # Get the first tag by attribute that exactly matches value.
112
+ # @param tag [String] the tag name to match
113
+ # @param attr [String] the attribute to compare
114
+ # @param value [String] the value of the attribute that the element must include
115
+ # @return [Element] the element of type tag who's attribute includes value
116
+ def find_ele_by_attr_include tag, attr, value
117
+ $driver.find_element :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
118
+ end
119
+
120
+ # Get tags by attribute that include value.
121
+ # @param tag [String] the tag name to match
122
+ # @param attr [String] the attribute to compare
123
+ # @param value [String] the value of the attribute that the element must include
124
+ # @return [Array<Element>] the elements of type tag who's attribute includes value
125
+ def find_eles_by_attr_include tag, attr, value
126
+ $driver.find_elements :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
127
+ end
128
+
129
+ # Get the first tag that includes text.
130
+ # @param tag [String] the tag name to match
131
+ # @param text [String] the text the element must include
132
+ # @return [Element] the element of type tag that includes text
133
+ # element.attribute(:text).include? text
134
+ def find_ele_by_text_include tag, text
135
+ find_ele_by_attr_include tag, :text, text
136
+ end
137
+
138
+ # Get the tags that include text.
139
+ # @param tag [String] the tag name to match
140
+ # @param text [String] the text the element must include
141
+ # @return [Array<Element>] the elements of type tag that includes text
142
+ # element.attribute(:text).include? text
143
+ def find_eles_by_text_include tag, text
144
+ find_eles_by_attr_include tag, :text, text
145
+ end
146
+
147
+ # Get the first tag that matches tag_name
148
+ # @param tag_name [String] the tag to match
149
+ # @return [Element]
150
+ def first_ele tag_name
151
+ tag = find_eles tag_name
152
+ tag = tag.first unless tag.nil?
153
+ end
154
+
155
+ # Get the last tag that matches tag_name
156
+ # @param tag_name [String] the tag to match
157
+ # @return [Element]
158
+ def last_ele tag_name
159
+ tag = find_eles tag_name
160
+ tag = tag.last unless tag.nil?
161
+ end
162
+
163
+ # Prints a JSON view of the current page
164
+ # @return [void]
165
+ def source
166
+ ap JSON.parse($driver.page_source)
167
+ end
168
+
169
+ # iOS only. On Android uiautomator always returns an empty string for EditText password.
170
+ #
171
+ # Password character returned from value of UIASecureTextField
172
+ # @param length [Integer] the length of the password to generate
173
+ # @return [String] the returned string is of size length
174
+ def password length=1
175
+ '•' * length
176
+ end
@@ -0,0 +1,93 @@
1
+ # Implement useful features for element.
2
+ class Selenium::WebDriver::Element
3
+ # Note: For testing .text should be used over value, and name.
4
+
5
+ # Fixes NoMethodError: undefined method `value' for #<Selenium::WebDriver::Element:0x..fa4a9148235390a44 id="1">
6
+ def value
7
+ self.attribute :value
8
+ end
9
+
10
+ # Fixes NoMethodError: undefined method `name' for #<Selenium::WebDriver::Element
11
+ def name
12
+ self.attribute :name
13
+ end
14
+
15
+ # Fixes NoMethodError: undefined method `type' for #<Selenium::WebDriver::Element
16
+ def type
17
+ self.attribute :type
18
+ end
19
+
20
+ # Tag name appears to be the same as type.
21
+ #
22
+ # Fixes Selenium::WebDriver::Error::UnknownError: Not yet implemented
23
+ def tag_name
24
+ type
25
+ end
26
+
27
+ # Cross platform way of entering text into a textfield
28
+ def set_value text
29
+ # enter text then tap window to hide the keyboard.
30
+ js = %Q(
31
+ au.getElement('#{self.ref}').setValue('#{text}');
32
+ au.lookup('window')[0].tap()
33
+ )
34
+ $driver.execute_script js
35
+ end if $os == :ios
36
+
37
+ # Cross platform way of entering text into a textfield
38
+ def set_value text
39
+ self.send_keys text
40
+ end if $os == :android
41
+
42
+ # For use with mobile tap.
43
+ #
44
+ # $driver.execute_script 'mobile: tap', :x => 0.0, :y => 0.98
45
+ #
46
+ # https://github.com/appium/appium/wiki/Automating-mobile-gestures
47
+ # @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
48
+ def location_rel
49
+ xy = self.location
50
+ w = window_size
51
+ OpenStruct.new( x: xy.x.to_f / w.width.to_f,
52
+ y: xy.y.to_f / w.height.to_f )
53
+ end
54
+ end
55
+
56
+ # Print JSON posted to Appium
57
+ #
58
+ # Requires from lib/selenium/webdriver/remote.rb
59
+ require 'selenium/webdriver/remote/capabilities'
60
+ require 'selenium/webdriver/remote/bridge'
61
+ require 'selenium/webdriver/remote/server_error'
62
+ require 'selenium/webdriver/remote/response'
63
+ require 'selenium/webdriver/remote/commands'
64
+ require 'selenium/webdriver/remote/http/common'
65
+ require 'selenium/webdriver/remote/http/default'
66
+
67
+ # Show http calls to the Selenium server.
68
+ #
69
+ # Invaluable for debugging.
70
+ module Selenium::WebDriver::Remote
71
+ class Bridge
72
+ # Code from lib/selenium/webdriver/remote/bridge.rb
73
+ def raw_execute(command, opts = {}, command_hash = nil)
74
+ verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
75
+ path = path.dup
76
+
77
+ path[':session_id'] = @session_id if path.include?(":session_id")
78
+
79
+ begin
80
+ opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
81
+ rescue IndexError
82
+ raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
83
+ end
84
+
85
+ puts verb
86
+ puts path
87
+ puts command_hash.to_json
88
+
89
+ puts "-> #{verb.to_s.upcase} #{path}" if $DEBUG
90
+ http.call verb, path, command_hash
91
+ end # def
92
+ end # class
93
+ end if defined?(Pry)# module
@@ -0,0 +1,4 @@
1
+ module AppiumLib
2
+ VERSION = '0.0.21' unless defined? ::AppiumLib::VERSION
3
+ DATE = '2013-03-22' unless defined? ::AppiumLib::DATE
4
+ end
@@ -0,0 +1,30 @@
1
+ #### appium_lib [![Dependency Status](https://gemnasium.com/appium/ruby_lib.png)](https://gemnasium.com/appium/ruby_lib)
2
+
3
+ - [appium_lib on RubyGems](https://rubygems.org/gems/appium_lib)
4
+ - [Documentation for appium_lib](http://www.rubydoc.info/github/appium/ruby_lib/master/frames)
5
+
6
+ Helper methods for writing cross platform (iPad, iPhone, Android) tests in Ruby using Appium.
7
+
8
+ Make sure you're using Ruby 1.9.3+ with upgraded rubygems and bundler.
9
+
10
+ #### Install / Upgrade
11
+
12
+ Update rubygems and bundler.
13
+
14
+ ```ruby
15
+ gem update --system ;\
16
+ gem update bundler
17
+ ```
18
+
19
+ Install the latest gem release.
20
+
21
+ ```ruby
22
+ gem uninstall -aIx appium_lib ;\
23
+ gem install --no-rdoc --no-ri appium_lib
24
+ ```
25
+
26
+ #### Run from Source
27
+
28
+ `pry -r ./lib/appium_lib.rb`
29
+
30
+ Then `start_driver`
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appium_lib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.21
5
+ platform: ruby
6
+ authors:
7
+ - code@bootstraponline.com
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: selenium-webdriver
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 2.31.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 2.31.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: awesome_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 10.0.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 10.0.3
55
+ description: Ruby lib for use with Appium.
56
+ email:
57
+ - code@bootstraponline.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE-2.0.txt
65
+ - Rakefile
66
+ - appium_lib.gemspec
67
+ - lib/appium_lib.rb
68
+ - lib/appium_lib/console.rb
69
+ - lib/appium_lib/element/alert.rb
70
+ - lib/appium_lib/element/android/textfield.rb
71
+ - lib/appium_lib/element/button.rb
72
+ - lib/appium_lib/element/ios/textfield.rb
73
+ - lib/appium_lib/element/text.rb
74
+ - lib/appium_lib/element/window.rb
75
+ - lib/appium_lib/helper.rb
76
+ - lib/appium_lib/patch.rb
77
+ - lib/appium_lib/version.rb
78
+ - readme.md
79
+ homepage: https://github.com/appium/ruby_lib
80
+ licenses:
81
+ - http://www.apache.org/licenses/LICENSE-2.0.txt
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: 1.9.3
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.3
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Ruby lib for use with Appium
103
+ test_files: []