8000 Add miscellaneous methods · YapEro/python-client@7929f02 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7929f02

Browse files
committed
Add miscellaneous methods
1 parent 51e3ff6 commit 7929f02

File tree

8 files changed

+461
-10
lines changed

8 files changed

+461
-10
lines changed

appium/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
"""
16+
Appium Python Client
17+
"""

appium/common/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
"""
16+
Appium Python Client: Common classes
17+
"""

appium/webdriver/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
"""
16+
Appium Python Client: WebDriver module
17+
"""
18+
1519
from webdriver import WebDriver as Remote

appium/webdriver/common/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
"""
16+
Appium Python Client: WebDriver common classes
17+
"""

appium/webdriver/mobilecommand.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,21 @@ class MobileCommand(object):
1818
SWITCH_TO_CONTEXT = 'switchToContext'
1919
TOUCH_ACTION = 'touchAction'
2020
MULTI_ACTION = 'multiAction'
21+
22+
# Appium Commands
23+
GET_APP_STRINGS = 'getAppStrings'
24+
KEY_EVENT = 'keyEvent'
25+
GET_CURRENT_ACTIVITY = 'getCurrentActivity'
26+
SET_IMMEDIATE_VALUE = 'setImmediateValue'
27+
PULL_FILE = 'pullFile'
28+
PUSH_FILE = 'pushFile'
29+
COMPLEX_FIND = 'complexFind'
30+
BACKGROUND = 'background'
31+
IS_APP_INSTALLED = 'isAppInstalled'
32+
INSTALL_APP = 'installApp'
33+
REMOVE_APP = 'removeApp'
34+
LAUNCH_APP = 'launchApp'
35+
CLOSE_APP = 'closeApp'
36+
END_TEST_COVERAGE = 'endTestCoverage'
37+
LOCK = 'lock'
38+
SHAKE = 'shake'

appium/webdriver/webdriver.py

Lines changed: 234 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from appium.webdriver.common.multi_action import MultiAction
2424

2525
from selenium.webdriver.common.by import By
26+
from selenium.webdriver.remote.webelement import WebElement
2627

2728
class WebDriver(webdriver.Remote):
2829
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
@@ -41,6 +42,9 @@ def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
4142
By.ANDROID_UIAUTOMATOR = MobileBy.ANDROID_UIAUTOMATOR
4243
By.ACCESSIBILITY_ID = MobileBy.ACCESSIBILITY_ID
4344

45+
# add methods to the WebElement class
46+
WebElement.set_value = set_value
47+
4448
@property
4549
def contexts(self):
4650
"""
@@ -109,7 +113,8 @@ def find_element_by_accessibility_id(self, id):
109113
"""Finds an element by accessibility id.
110114
111115
:Args:
112-
- id - a string corresponding to a recursive element search using the Id/Name that the native Accessibility options utilize
116+
- id - a string corresponding to a recursive element search using the
117+
Id/Name that the native Accessibility options utilize
113118
114119
:Usage:
115120
driver.find_element_by_accessibility_id()
@@ -120,14 +125,14 @@ def find_elements_by_accessibility_id(self, id):
120125
"""Finds elements by accessibility id.
121126
122127
:Args:
123-
- id - a string corresponding to a recursive element search using the Id/Name that the native Accessibility options utilize
128+
- id - a string corresponding to a recursive element search using the
129+
Id/Name that the native Accessibility options utilize
124130
125131
:Usage:
126132
driver.find_elements_by_accessibility_id()
127133
"""
128134
return self.find_elements(by=By.ACCESSIBILITY_ID, value=id)
129135

130-
131136
# convenience method added to Appium (NOT Selenium 3)
132137
def scroll(self, originEl, destinationEl):
133138
"""Scrolls from one element to another
@@ -141,7 +146,6 @@ def scroll(self, originEl, destinationEl):
141146
"""
142147
action = TouchAction(self)
143148
action.press(originEl).move_to(destinationEl).release().perform()
144-
145149
return self
146150

147151
# convenience method added to Appium (NOT Selenium 3)
@@ -154,15 +158,16 @@ def drag_and_drop(self, originEl, destinationEl):
154158
"""
155159
action = TouchAction(self)
156160
action.long_press(originEl).move_to(destinationEl).release().perform()
157-
158161
return self
159162

160163
# convenience method added to Appium (NOT Selenium 3)
161164
def tap(self, positions, duration=None):
162-
"""Taps on an particular place with up to five fingers, holding for a certain time
165+
"""Taps on an particular place with up to five fingers, holding for a
166+
certain time
163167
164168
:Args:
165-
- positions - an array of tuples representing the x/y coordinates of the fingers to tap. Length can be up to five.
169+
- positions - an array of tuples representing the x/y coordinates of
170+
the fingers to tap. Length can be up to five.
166171
- duration - (optional) length of time to tap, in seconds
167172
168173
:Usage:
@@ -181,7 +186,6 @@ def tap(self, positions, duration=None):
181186
ma.add(action)
182187

183188
ma.perform()
184-
185189
return self
186190

187191
# convenience method added to Appium (NOT Selenium 3)
@@ -207,7 +211,6 @@ def swipe(self, startx, starty, endx, endy, duration=0):
207211
.move_to(x=endx, y=endy) \
208212
.release()
209213
action.perform()
210-
211214
return self
212215

213216
# convenience method added to Appium (NOT Selenium 3)
@@ -234,7 +237,6 @@ def pinch(self, element=None, startx=None, starty=None, endx=None, endy=None, du
234237
'duration': duration
235238
};
236239
self.execute_script('mobile: pinchClose', opts)
237-
238240
return self
239241

240242
# convenience method added to Appium (NOT Selenium 3)
@@ -263,7 +265,185 @@ def zoom(self, element=None, startx=None, starty=None, endx=None, endy=None, dur
263265
'duration': duration
264266
};
265267
self.execute_script('mobile: pinchOpen', opts)
268+
return self
269+
270+
@property
271+
def app_strings(self):
272+
"""Returns the application strings from the device.
273+
274+
:Usage:
275+
strings = driver.app_strings
276+
"""
277+
return self.execute(Command.GET_APP_STRINGS)['value']
278+
279+
def keyevent(self, keycode, metastate=None):
280+
"""Sends a keycode to the device. Android only. Possible keycodes can be
281+
found in http://developer.android.com/reference/android/view/KeyEvent.html.
282+
283+
:Args:
284+
- keycode - the keycode to be sent to the device
285+
- metastate - meta information about the keycode being sent
286+
"""
287+
data = {
288+
'keycode': keycode
289+
}
290+
if metastate != None:
291+
data['metastate'] = metastate
292+
self.execute(Command.KEY_EVENT, data)
293+
return self
294+
295+
@property
296+
def current_activity(self):
297+
"""Retrieves the current activity on the device.
298+
"""
299+
return self.execute(Command.GET_CURRENT_ACTIVITY)['value']
300+
301+
def set_value(self, element, value):
302+
"""Set the value on an element in the application.
303+
304+
:Args:
305+
- element - the element whose value will be set
306+
- Value - the value to set on the element
307+
"""
308+
data = {
309+
'elementId': element.id,
310+
'value': [value]
311+
}
312+
self.execute(Command.SET_IMMEDIATE_VALUE, data)
313+
return self
314+
315+
def pull_file(self, path):
316+
"""Retrieves the file at `path`. Returns the file's content encoded as
317+
Base64.
318+
319+
:Args:
320+
- path - the path to the file on the device
321+
"""
322+
data = {
323+
'path': path
324+
}
325+
return self.execute(Command.PULL_FILE, data)['value']
326+
327+
def push_file(self, path, base64data):
328+
"""Puts the data, encoded as Base64, in the file specified as `path`.
329+
330+
:Args:
331+
- path - the path on the device
332+
- base64data - data, encoded as Base64, to be written to the file
333+
"""
334+
data = {
335+
'path': path,
336+
'data': base64data
337+
}
338+
self.execute(Command.PUSH_FILE, data)
339+
return self
340+
341+
def complex_find(self, selector):
342+
"""Performs a find for elements in the current application.
343+
344+
:Args:
345+
- selector - an array of selection criteria
346+
"""
347+
data = {
348+
'selector': selector
349+
}
350+
return self.execute(Command.COMPLEX_FIND, data)['value']
351+
352+
def background_app(self, seconds):
353+
"""Puts the application in the background on the device for a certain
354+
duration. iOS only.
355+
356+
:Args:
357+
- seconds - the duration fo 57BB r the application to remain in the background
358+
"""
359+
data = {
360+
'seconds': seconds
361+
}
362+
self.execute(Command.BACKGROUND, data)
363+
return self
364+
365+
def is_app_installed(self, bundle_id):
366+
"""Checks whether the application specified by `bundle_id` is installed
367+
on the device.
368+
369+
:Args:
370+
- bundle_id - the id of the application to query
371+
"""
372+
data = {
373+
'bundleId': bundle_id
374+
}
375+
return self.execute(Command.IS_APP_INSTALLED, data)['value']
376+
377+
def install_app(self, app_path):
378+
"""Install the application found at `app_path` on the device.
379+
380+
:Args:
381+
- app_path - the local or remote path to the application to install
382+
"""
383+
data = {
384+
'appPath': app_path
385+
}
386+
self.execute(Command.INSTALL_APP, data)
387+
return self
388+
389+
def remove_app(self, app_id):
390+
"""Remove the specified application from the device.
391+
392+
:Args:
393+
- app_id - the application id to be removed
394+
"""
395+
data = {
396+
'appId': app_id
397+
}
398+
self.execute(Command.REMOVE_APP, data)
399+
return self
400+
401+
def launch_app(self):
402+
"""Start on the device the application specified in the desired capabilities.
403+
"""
404+
self.execute(Command.LAUNCH_APP)
405+
return self
406+
407+
def close_app(self):
408+
"""Stop the running application, specified in the desired capabilities, on
409+
the device.
410+
"""
411+
self.execute(Command.CLOSE_APP)
412+
return self
413+
414+
def end_test_coverage(self, intent, path):
415+
"""Ends the coverage collection and pull the coverage.ec file from the device.
416+
Android only.
266417
418+
See https://github.com/appium/appium/blob/master/docs/en/android_coverage.md
419+
420+
:Args:
421+
- intent - description of operation to be performed
422+
- path - path to coverage.ec file to be pulled from the device
423+
"""
424+
data = {
425+
'intent': intent,
426+
'path': path
427+
}
428+
self.execute(Command.END_TEST_COVERAGE, data)
429+
return self
430+
431+
def lock(self, seconds):
432+
"""Lock the device for a certain period of time. iOS only.
433+
434+
:Args:
435+
- the duration to lock the device, in seconds
436+
"""
437+
data = {
438+
'seconds': seconds
439+
}
440+
self.execute(Command.LOCK, data)
441+
return self
442+
443+
def shake(self):
444+
"""Shake the device.
445+
"""
446+
self.execute(Command.SHAKE)
267447
return self
268448

269449

@@ -278,3 +458,47 @@ def _addCommands(self):
278458
('POST', '/session/$sessionId/touch/perform')
279459
self.command_executor._commands[Command.MULTI_ACTION] = \
280460
('POST', '/session/$sessionId/touch/multi/perform')
461+
self.command_executor._commands[Command.GET_APP_STRINGS] = \
462+
('GET', '/session/$sessionId/appium/app/strings')
463+
self.command_executor._commands[Command.KEY_EVENT] = \
464+
('POST', '/session/$sessionId/appium/device/keyevent')
465+
self.command_executor._commands[Command.GET_CURRENT_ACTIVITY] = \
466+
('GET', '/session/$sessionId/appium/device/current_activity')
467+
self.command_executor._commands[Command.SET_IMMEDIATE_VALUE] = \
468+
('POST', '/session/$sessionId/appium/element/$elementId/value')
469+
self.command_executor._commands[Command.PULL_FILE] = \
470+
('POST', '/session/$sessionId/appium/device/pull_file')
471+
self.command_executor._commands[Command.PUSH_FILE] = \
472+
('POST', '/session/$sessionId/appium/device/push_file')
473+
self.command_executor._commands[Command.COMPLEX_FIND] = \
474+
('POST', '/session/$sessionId/appium/app/complex_find')
475+
self.command_executor._commands[Command.BACKGROUND] = \
476+
('POST', '/session/$sessionId/appium/app/background')
477+
self.command_executor._commands[Command.IS_APP_INSTALLED] = \
478+
('POST', '/session/$sessionId/appium/device/app_installed')
479+
self.command_executor._commands[Command.INSTALL_APP] = \
480+
('POST', '/session/$sessionId/appium/device/install_app')
481+
self.command_executor._commands[Command.REMOVE_APP] = \
482+
('POST', '/session/$sessionId/appium/device/remove_app')
483+
self.command_executor._commands[Command.LAUNCH_APP] = \
484+
('POST', '/session/$sessionId/appium/app/launch')
485+
self.command_executor._commands[Command.CLOSE_APP] = \
486+
('POST', '/session/$sessionId/appium/app/close')
487+
self.command_executor._commands[Command.END_TEST_COVERAGE] = \
488+
('POST', '/session/$sessionId/appium/app/end_test_coverage')
489+
self.command_executor._commands[Command.LOCK] = \
490+
('POST', '/session/$sessionId/appium/device/lock')
491+
self.command_executor._commands[Command.SHAKE] = \
492+
('POST', '/session/$sessionId/appium/device/shake')
493+
494+
495+
# monkeypatched method for WebElement
496+
def set_value(self, value):
497+
"""Set the value on this element in the application
498+
"""
499+
data = {
500+
'elementId': self.id,
501+
'value': [value]
502+
}
503+
self._execute(Command.SET_IMMEDIATE_VALUE, data)
504+
return self

0 commit comments

Comments
 (0)
0