wda_lib 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfdde1a94a7e89b876fd905f1db859231e2cd73b
4
+ data.tar.gz: 37a66250c8f8f125ef8294fbceff4669599e4ac0
5
+ SHA512:
6
+ metadata.gz: 1691ebedf044e9e1bb4d2a197ee179c91bb846ebe05d9a3809179fa2d12c8fbe21a15ac9258b4c3828cf2d6037c1a23b7a07a11380abb944ad5c8c49eef157ac
7
+ data.tar.gz: 77982675f07d2486c1a5e8f261399d8495171b84c6b01091e48ebc5af48b2baa08091ce8213f28da70e35fdc6bad4f69b483cce15127c5715621f4939a9904fd
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /*.gem
9
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ ### wda_lib
2
+
3
+ A simple ruby lib of binding methods for WebDriverAgent
4
+
5
+ ## Install
6
+
7
+ ```
8
+ gem install wda_lib
9
+ ```
10
+
11
+ ## Usage example
12
+ A simple test to show all actions on WDA IntegrationApp
13
+
14
+ ```ruby
15
+ require 'wda_lib'
16
+
17
+ app = WDA.new
18
+
19
+ app.x
20
+
21
+ app.homescreen
22
+
23
+ app.launch_app('com.facebook.IntegrationApp')
24
+
25
+ app.status
26
+
27
+ app.session
28
+
29
+ app.button('Alerts')
30
+
31
+ app.button('Alerts').ref
32
+
33
+ app.button('Alerts').name
34
+
35
+ app.button('Alerts').click
36
+
37
+ app.partial_texts('Create')[1].click
38
+
39
+ app.alert_text
40
+
41
+ app.accept_alert
42
+
43
+ app.button('Back').click
44
+
45
+ app.partial_text('Attri').click
46
+
47
+ app.xpath_search('StaticText', 'label', 'Label')
48
+
49
+ app.xpath_search('Button', 'name', 'Second')[0].click
50
+
51
+ app.textfield('Value').click
52
+
53
+ app.textfield('Value').send_keys('test')
54
+
55
+ app.textfield('Valuetest').clear
56
+
57
+ location = app.textfield('Value2').location
58
+
59
+ app.tap_on(location[:x], location[:y])
60
+
61
+ app.keys('Type more keys')
62
+
63
+ app.button('Back').click
64
+
65
+ sleep 1
66
+
67
+ app.find(:xpath, "//XCUIElementTypeButton[@name='Scrolling']").click
68
+
69
+ app.text('ScrollView').click
70
+
71
+ app.text('7').scroll('down')
72
+
73
+ app.text('7').scroll('down')
74
+
75
+ app.text('7').scroll('up')
76
+
77
+ app.swipe(180, 180, 330, 100)
78
+
79
+ app.swipe(180, 180, 100, 330)
80
+
81
+ app.button('Back').click
82
+
83
+ app.button('Back').click
84
+
85
+ app.x
86
+
87
+ ```
88
+
89
+ ## Example of multiple devices
90
+
91
+ ```ruby
92
+ iphone_testing = true
93
+ simulator_testing = true
94
+
95
+ thread_iphone = Thread.new{
96
+ start_time = Time.now
97
+ app = WDA.new(device_url: 'http://192.168.1.56:8100/')
98
+ app.x
99
+ app.homescreen
100
+ app.launch_app('com.facebook.IntegrationApp')
101
+ app.find(:xpath, "//XCUIElementTypeButton[@name='Scrolling']").click
102
+ app.text('ScrollView').click
103
+ app.text('7').scroll('down')
104
+ app.text('7').scroll('down')
105
+ app.text('7').scroll('up')
106
+ app.swipe(180, 180, 330, 100)
107
+ app.swipe(180, 180, 100, 330)
108
+ app.button('Back').click
109
+ app.x
110
+ end_time = Time.now
111
+ p "Testing time: #{end_time-start_time}"
112
+ iphone_testing = false
113
+ }
114
+
115
+ thread_simulator = Thread.new{
116
+ start_time = Time.now
117
+ sim = WDA.new
118
+ sim.x
119
+ sim.homescreen
120
+ sim.launch_app('com.facebook.IntegrationApp')
121
+ sim.find(:xpath, "//XCUIElementTypeButton[@name='Scrolling']").click
122
+ sim.text('ScrollView').click
123
+ sim.text('7').scroll('down')
124
+ sim.text('7').scroll('down')
125
+ sim.text('7').scroll('up')
126
+ sim.swipe(180, 180, 330, 100)
127
+ sim.swipe(180, 180, 100, 330)
128
+ sim.button('Back').click
129
+ sim.x
130
+ end_time = Time.now
131
+ p "Testing time: #{end_time-start_time}"
132
+ simulator_testing = false
133
+ }
134
+
135
+ while iphone_testing || simulator_testing do
136
+ sleep 5
137
+ end
138
+
139
+ ```
140
+
141
+ ## Options
142
+
143
+ This lib is also providing access of selenium-webdriver method find_element and find_elements.
144
+ You can do:
145
+
146
+ ```ruby
147
+ element = app.find_element(:link_text, 'label=Attributes')
148
+ ```
149
+
150
+ Then you can use all methods for selenium element object:
151
+ ```
152
+ element.click
153
+ element.name
154
+ element.size
155
+ element.rect
156
+ element.location
157
+ ```
158
+
159
+ ## TODO
160
+
161
+ Add more tests...
162
+
163
+ ## Contributing
164
+
165
+ Welcome to get your contributions, to help improving the lib.
166
+
167
+ 1. Fork it
168
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
169
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
170
+ 4. Push to the branch (`git push origin my-new-feature`)
171
+ 5. Create new Pull Request
@@ -0,0 +1,136 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module Remote
23
+ class W3CBridge
24
+ #
25
+ # http://www.w3.org/TR/2015/WD-webdriver-20150918/#list-of-endpoints
26
+ #
27
+
28
+ #
29
+ # session handling
30
+ #
31
+
32
+ command :newSession, :post, 'session'
33
+ command :deleteSession, :delete, 'session/:session_id'
34
+
35
+ #
36
+ # basic driver
37
+ #
38
+
39
+ command :get, :post, 'session/:session_id/url'
40
+ command :getCurrentUrl, :get, 'session/:session_id/url'
41
+ command :back, :post, 'session/:session_id/back'
42
+ command :forward, :post, 'session/:session_id/forward'
43
+ command :refresh, :post, 'session/:session_id/refresh'
44
+ command :getTitle, :get, 'session/:session_id/title'
45
+
46
+ #
47
+ # window and Frame handling
48
+ #
49
+
50
+ command :getWindowHandle, :get, 'session/:session_id/window'
51
+ command :closeWindow, :delete, 'session/:session_id/window'
52
+ command :switchToWindow, :post, 'session/:session_id/window'
53
+ command :getWindowHandles, :get, 'session/:session_id/window/handles'
54
+ command :fullscreenWindow, :post, 'session/:session_id/window/fullscreen'
55
+ command :maximizeWindow, :post, 'session/:session_id/window/maximize'
56
+ command :setWindowSize, :post, 'session/:session_id/window/size'
57
+ command :getWindowSize, :get, 'session/:session_id/window/size'
58
+ command :switchToFrame, :post, 'session/:session_id/frame'
59
+ command :switchToParentFrame, :post, 'session/:session_id/frame/parent'
60
+
61
+ #
62
+ # element
63
+ #
64
+
65
+ command :findElement, :post, 'session/:session_id/element'
66
+ command :findElements, :post, 'session/:session_id/elements'
67
+ command :findChildElement, :post, 'session/:session_id/element/:id/element'
68
+ command :findChildElements, :post, 'session/:session_id/element/:id/elements'
69
+ command :getActiveElement, :get, 'session/:session_id/element/active'
70
+ command :isElementSelected, :get, 'session/:session_id/element/:id/selected'
71
+ command :getElementAttribute, :get, 'session/:session_id/element/:id/attribute/:name'
72
+ command :getElementProperty, :get, 'session/:session_id/element/:id/property/:name'
73
+ command :getElementCssValue, :get, 'session/:session_id/element/:id/css/:property_name'
74
+ command :getElementText, :get, 'session/:session_id/element/:id/text'
75
+ command :getElementTagName, :get, 'session/:session_id/element/:id/name'
76
+ command :getElementRect, :get, 'session/:session_id/element/:id/rect'
77
+ command :isElementEnabled, :get, 'session/:session_id/element/:id/enabled'
78
+
79
+ #
80
+ # document handling
81
+ #
82
+
83
+ command :getPageSource, :get, '/session/:session_id/source'
84
+ command :executeScript, :post, 'session/:session_id/execute/sync'
85
+ command :executeAsyncScript, :post, 'session/:session_id/execute/async'
86
+
87
+ #
88
+ # cookies
89
+ #
90
+
91
+ command :getAllCookies, :get, 'session/:session_id/cookie'
92
+ command :getCookie, :get, 'session/:session_id/cookie/:name'
93
+ command :addCookie, :post, 'session/:session_id/cookie'
94
+ command :deleteCookie, :delete, 'session/:session_id/cookie/:name'
95
+
96
+ #
97
+ # timeouts
98
+ #
99
+
100
+ command :setTimeout, :post, 'session/:session_id/timeouts'
101
+
102
+ #
103
+ # actions
104
+ #
105
+
106
+ command :actions, :post, 'session/:session_id/actions'
107
+
108
+ #
109
+ # Element Operations
110
+ #
111
+
112
+ command :elementClick, :post, 'session/:session_id/element/:id/click'
113
+ command :elementTap, :post, 'session/:session_id/element/:id/tap'
114
+ command :elementClear, :post, 'session/:session_id/element/:id/clear'
115
+ command :elementSendKeys, :post, 'session/:session_id/element/:id/value'
116
+ command :elementScroll, :post, 'session/:session_id/uiaElement/:id/scroll'
117
+
118
+ #
119
+ # alerts
120
+ #
121
+
122
+ command :dismissAlert, :post, 'session/:session_id/alert/dismiss'
123
+ command :acceptAlert, :post, 'session/:session_id/alert/accept'
124
+ command :getAlertText, :get, 'session/:session_id/alert/text'
125
+ command :sendAlertText, :post, 'session/:session_id/alert/text'
126
+
127
+ #
128
+ # screenshot
129
+ #
130
+
131
+ command :takeScreenshot, :get, 'session/:session_id/screenshot'
132
+ command :takeElementScreenshot, :get, 'session/:session_id/element/:id/screenshot'
133
+ end
134
+ end # Remote
135
+ end # WebDriver
136
+ end # Selenium
@@ -0,0 +1,53 @@
1
+ # require 'selenium-webdriver'
2
+
3
+ # Patch or add methods for Element instance
4
+ Selenium::WebDriver::Element.class_eval do
5
+ def eid
6
+ @id['ELEMENT']
7
+ end
8
+
9
+ # Scroll on an element with its id
10
+ # @param id [String], direction [String] up, down, left, right
11
+ # @return {}
12
+ def scroll(direction)
13
+ bridge.element_scroll @id, direction
14
+ end
15
+
16
+ # Get wdRect by id
17
+ # @param id [String] Element uuid
18
+ # @return rect [Hash] location: y, x, size: width, height
19
+ def rect
20
+ bridge.element_rect @id
21
+ end
22
+
23
+ # Get element type attribute
24
+ # @return [String] example: "XCUIElementTypePageIndicator", "XCUIElementTypeButton"
25
+ def type
26
+ bridge.element_tag_name @id
27
+ end
28
+
29
+ # Get element value attribute
30
+ def value
31
+ bridge.element_attribute @id, 'value'
32
+ end
33
+
34
+ # Get element name attribute
35
+ def name
36
+ bridge.element_attribute @id, 'name'
37
+ end
38
+
39
+ # Get element name attribute
40
+ def label
41
+ bridge.element_attribute @id, 'label'
42
+ end
43
+
44
+ # Get the value of a the given attribute of the element.
45
+ # @param [String]
46
+ # attribute name, example: type, label, name, value, rect
47
+ # @return [String,nil]
48
+ # attribute value
49
+ def attribute(name)
50
+ bridge.element_attribute @id, name
51
+ end
52
+
53
+ end
@@ -0,0 +1,31 @@
1
+ # Patch or add methods for Bridge. Called by Element instance or Bridge instance
2
+
3
+ Selenium::WebDriver::Remote::W3CBridge.class_eval do
4
+ # Patch W3CBridge create_session method
5
+ def create_session(desired_capabilities)
6
+ @session_id = desired_capabilities[:session_id]
7
+ if !desired_capabilities[:session_valid]
8
+ resp = raw_execute :newSession, {}, {desiredCapabilities: desired_capabilities}
9
+ desired_capabilities[:session_id] = resp['sessionId']
10
+ desired_capabilities[:session_valid] = true
11
+ @session_id = resp['sessionId']
12
+ end
13
+ return desired_capabilities
14
+ end
15
+
16
+ # Add element_scroll method
17
+ def element_scroll(element, direction)
18
+ execute :elementScroll, {id: element.values.first}, {direction: direction}
19
+ end
20
+
21
+ # Add element_rect method
22
+ def element_rect(element)
23
+ data = execute :getElementRect, id: element['ELEMENT']
24
+ return data
25
+ end
26
+
27
+ # Patch W3CBridge element_attribute method
28
+ def element_attribute(element, name)
29
+ execute :getElementAttribute, id: element['ELEMENT'], name: name
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ class WDA
2
+ module Alert
3
+
4
+ # Get alert
5
+ # Return text [String]
6
+ def alert_text
7
+ get('/alert/text')['value']
8
+ end
9
+
10
+ # Accept alert
11
+ def accept_alert
12
+ post '/alert/accept'
13
+ end
14
+
15
+ # Dismiss alert
16
+ def dismiss_alert
17
+ post '/alert/dismiss'
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,33 @@
1
+ class WDA
2
+ module Custome
3
+
4
+ # Go to home screen
5
+ def homescreen
6
+ post(@base_url + '/homescreen')
7
+ end
8
+
9
+ # Same as homescreen, go to home screen
10
+ def springboard
11
+ homescreen
12
+ end
13
+
14
+ # Deactivate application for given time
15
+ def pause(duration)
16
+ post '/deactivateApp', { duration: duration }
17
+ end
18
+
19
+ # Timeout(without Session)
20
+ # @param duraiton [Float] the timeout in milliseconds
21
+ # @return [void]
22
+ def timeout(duraiton)
23
+ post(@base_url + '/timeout', { type: 'xctevent', ms: duration })
24
+ end
25
+
26
+ # Timeout(with Session)
27
+ # @param duration [Float] the timeout in milliseconds
28
+ # @return [void]
29
+ def timeout_in_session(duraiton)
30
+ post '/timeout', { type: 'xctevent', ms: duration }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ class WDA
2
+ module Debug
3
+
4
+ # Get all elements on the screen
5
+ def source(session_id = nil, accessible = true)
6
+ if session_id.nil?
7
+ post(@base_url + '/source', { accessible: accessible })
8
+ else
9
+ post '/source', { accessible: accessible }
10
+ end
11
+ end
12
+
13
+ def get_source
14
+ get(@base_url + '/source')['value']['tree']['children']
15
+ end
16
+
17
+ def get_window_statusbar
18
+ get(@base_url + '/source')['value']['tree']['children'][2]
19
+ end
20
+
21
+ def get_window(window_number = 0)
22
+ get(@base_url + '/source')['value']['tree']['children'][window_number]
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,183 @@
1
+ class WDA
2
+ class Element
3
+
4
+ def initialize(client, id)
5
+ @client = client
6
+ @id = id
7
+ end
8
+
9
+ # Remove useless attributes, return object only with element
10
+ def inspect
11
+ format '#<%s:0x%x id=%s>', self.class, hash * 2, @id.inspect
12
+ end
13
+
14
+ def ref
15
+ @id
16
+ end
17
+
18
+ def eid
19
+ @id['ELEMENT']
20
+ end
21
+
22
+ # Check if element is enabled?
23
+ # @param id [String] Element uuid
24
+ # @return isEnabled? [Boolean]
25
+ def enabled?
26
+ client.get '/element/' + eid + '/enabled'
27
+ end
28
+
29
+ # Get wdRect by id
30
+ # @param id [String] Element uuid
31
+ # @return wdRect
32
+ def rect
33
+ client.get '/element/' + eid + '/rect'
34
+ end
35
+
36
+ # Get attribute value
37
+ # @param id [String], name [String]
38
+ # @return attributeValue [String]
39
+ def attribute(name)
40
+ client.get '/element/' + eid + '/attribute/' + name
41
+ end
42
+
43
+ # Get text from an element(StaticText or Button)
44
+ # @param id [String] Element uuid
45
+ # @return text [String]
46
+ def text
47
+ client.get '/element/' + eid + '/text'
48
+ end
49
+
50
+ # Check if element is displayed?
51
+ # @param id [String] Element uuid
52
+ # @return isVisible? [Boolean]
53
+ def displayed?
54
+ client.get '/element/' + eid + '/displayed'
55
+ end
56
+
57
+ # Check if element is accessible?
58
+ # @param id [String] Element uuid
59
+ # @return is accessible? [String]
60
+ def accessible?
61
+ client.get '/element/' + eid + '/accessible'
62
+ end
63
+
64
+ # Check if element is accessibilityContainer?
65
+ # @param id [String] Element uuid
66
+ # @return is accessibilityContainer? [String]
67
+ def accessible_container?
68
+ client.get '/element/' + eid + '/accessibilityContainer'
69
+ end
70
+
71
+
72
+ # Get type from an element
73
+ # @param id [String] Element uuid
74
+ # @return type [String]
75
+ def name
76
+ client.get '/element/' + eid + '/name'
77
+ end
78
+
79
+ # Set value to an element
80
+ # @param id [String] Element uuid, value [String]
81
+ # @return element uuid [String]
82
+ def send_keys(value)
83
+ client.post '/element/' + eid + '/value', { value: value.chars }
84
+ end
85
+
86
+ # Tap on an element with its id
87
+ # @param id [String] Element uuid
88
+ # @return element uuid [String]
89
+ def click
90
+ client.post '/element/' + eid + '/click'
91
+ end
92
+
93
+ # Clearing text of an given element
94
+ # @param id [String] Element uuid
95
+ # @return element uuid [String]
96
+ def clear
97
+ client.post '/element/' + eid + '/clear'
98
+ end
99
+
100
+ # Double tap on an element with its id
101
+ # @param id [String] Element uuid
102
+ # @return element uuid [String]
103
+ def double_tap
104
+ client.post '/uiaElement/' + eid + '/doubleTap'
105
+ end
106
+
107
+ # Two finger tap on an element with its id
108
+ # @param id [String] Element uuid
109
+ # @return element uuid [String]
110
+ def two_finger_tap
111
+ client.post '/uiaElement/' + eid + '/twoFingerTap'
112
+ end
113
+
114
+ # Touch and hold on for a while finger tap on an element with its id
115
+ # @param id [String], duration [Double]
116
+ # @return element uuid [String]
117
+ def touch_hold(duration)
118
+ client.post '/uiaElement/' + eid + '/touchAndHold', { duration: duration }
119
+ end
120
+
121
+ # Scroll on an element with its id
122
+ # @param id [String], direction [String] up, down, left, right
123
+ # @return [Hash]
124
+ def scroll(direction = nil)
125
+ client.post '/uiaElement/' + eid + '/scroll', { direction: direction }
126
+ end
127
+
128
+ # Drag on an element with its id and position
129
+ # @param to* [String], duration [Double]
130
+ def drag_to(toX, toY, duration = 0)
131
+ fromX = location[:x]
132
+ fromY = location[:y]
133
+ client.post '/uiaTarget/' + eid + '/dragfromtoforduration', { fromX: fromX, toX: toX, fromY: fromY, toY: toY, duration: duration }
134
+ end
135
+
136
+ # Get element size
137
+ # @return [Struct] [:width, :height]
138
+ def size
139
+ r = rect['value']
140
+ Dimension.new(r['width'], r['height'])
141
+ end
142
+
143
+ # Get element size
144
+ # @return [Struct] [:x, :y]
145
+ def location
146
+ r = rect['value']
147
+ Point.new(r['x'], r['y'])
148
+ end
149
+
150
+ alias_method :[], :attribute
151
+
152
+ private
153
+
154
+ attr_reader :client
155
+
156
+ end
157
+
158
+ # Swipe on an element with its id and position
159
+ # @param [Integer]
160
+ def swipe(fromX, toX, fromY, toY)
161
+ post '/uiaTarget/0/dragfromtoforduration', { fromX: fromX, toX: toX, fromY: fromY, toY: toY, duration: 0 }
162
+ end
163
+
164
+ # Tap on a given positon
165
+ # @param id [String], x, y [Integer]
166
+ def tap_on(x, y)
167
+ post '/tap/0', { x: x, y: y }
168
+ end
169
+
170
+ # Type text to textfield
171
+ # @param value [String]
172
+ def keys(value)
173
+ post '/keys', { value: value.chars }
174
+ end
175
+
176
+ # @return width, height
177
+ def window_size
178
+ win_size = get('/window/size')['value']
179
+ Dimension.new(win_size['width'], win_size['height'])
180
+ end
181
+
182
+ end
183
+