robotframework-appiumwindows 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robotframework_appiumwindows-0.1.0/AppiumLibrary/__init__.py +106 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/appium_path.py +10 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/__init__.py +21 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_applicationmanagement.py +515 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_element.py +1282 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_logging.py +63 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_powershell.py +553 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_runonfailure.py +74 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_screenrecord.py +138 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_screenshot.py +109 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_waiting.py +163 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/_windows.py +215 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/keywords/keywordgroup.py +70 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/locators/__init__.py +7 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/locators/elementfinder.py +264 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/utils/__init__.py +50 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/utils/applicationcache.py +48 -0
- robotframework_appiumwindows-0.1.0/AppiumLibrary/version.py +2 -0
- robotframework_appiumwindows-0.1.0/LICENSE +21 -0
- robotframework_appiumwindows-0.1.0/PKG-INFO +148 -0
- robotframework_appiumwindows-0.1.0/README.md +119 -0
- robotframework_appiumwindows-0.1.0/pyproject.toml +38 -0
- robotframework_appiumwindows-0.1.0/robotframework_appiumwindows.egg-info/PKG-INFO +148 -0
- robotframework_appiumwindows-0.1.0/robotframework_appiumwindows.egg-info/SOURCES.txt +26 -0
- robotframework_appiumwindows-0.1.0/robotframework_appiumwindows.egg-info/dependency_links.txt +1 -0
- robotframework_appiumwindows-0.1.0/robotframework_appiumwindows.egg-info/requires.txt +2 -0
- robotframework_appiumwindows-0.1.0/robotframework_appiumwindows.egg-info/top_level.txt +1 -0
- robotframework_appiumwindows-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from AppiumLibrary.keywords import *
|
|
5
|
+
from AppiumLibrary.version import VERSION
|
|
6
|
+
|
|
7
|
+
__version__ = VERSION
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AppiumLibrary(
|
|
11
|
+
_LoggingKeywords,
|
|
12
|
+
_RunOnFailureKeywords,
|
|
13
|
+
_ElementKeywords,
|
|
14
|
+
_WindowsKeywords,
|
|
15
|
+
_PowershellKeywords,
|
|
16
|
+
_ScreenshotKeywords,
|
|
17
|
+
_ApplicationManagementKeywords,
|
|
18
|
+
_WaitingKeywords,
|
|
19
|
+
_ScreenrecordKeywords
|
|
20
|
+
):
|
|
21
|
+
"""AppiumLibrary is a Mobile App testing library for Robot Framework.
|
|
22
|
+
|
|
23
|
+
= Locating or specifying elements =
|
|
24
|
+
|
|
25
|
+
All keywords in AppiumLibrary that need to find an element on the page
|
|
26
|
+
take an argument, either a ``locator`` or a ``webelement``. ``locator``
|
|
27
|
+
is a string that describes how to locate an element using a syntax
|
|
28
|
+
specifying different location strategies. ``webelement`` is a variable that
|
|
29
|
+
holds a WebElement instance, which is a representation of the element.
|
|
30
|
+
|
|
31
|
+
== Using locators ==
|
|
32
|
+
|
|
33
|
+
By default, when a locator is provided, it is matched against the key attributes
|
|
34
|
+
of the particular element type. For iOS and Android, key attribute is ``id`` for
|
|
35
|
+
all elements and locating elements is easy using just the ``id``. For example:
|
|
36
|
+
|
|
37
|
+
| Click Element id=my_element
|
|
38
|
+
|
|
39
|
+
New in AppiumLibrary 1.4, ``id`` and ``xpath`` are not required to be specified,
|
|
40
|
+
however ``xpath`` should start with ``//`` else just use ``xpath`` locator as explained below.
|
|
41
|
+
|
|
42
|
+
For example:
|
|
43
|
+
|
|
44
|
+
| Click Element my_element
|
|
45
|
+
| Wait Until Page Contains Element //*[@type="android.widget.EditText"]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Appium additionally supports some of the [https://w3c.github.io/webdriver/webdriver-spec.html|Mobile JSON Wire Protocol] locator strategies.
|
|
49
|
+
It is also possible to specify the approach AppiumLibrary should take
|
|
50
|
+
to find an element by specifying a lookup strategy with a locator
|
|
51
|
+
prefix. Supported strategies are:
|
|
52
|
+
|
|
53
|
+
| *Strategy* | *Example* | *Description* | *Note* |
|
|
54
|
+
| identifier | Click Element `|` identifier=my_element | Matches by @id attribute | |
|
|
55
|
+
| id | Click Element `|` id=my_element | Matches by @resource-id attribute | |
|
|
56
|
+
| accessibility_id | Click Element `|` accessibility_id=button3 | Accessibility options utilize. | |
|
|
57
|
+
| xpath | Click Element `|` xpath=//UIATableView/UIATableCell/UIAButton | Matches with arbitrary XPath | |
|
|
58
|
+
| class | Click Element `|` class=UIAPickerWheel | Matches by class | |
|
|
59
|
+
| android | Click Element `|` android=UiSelector().description('Apps') | Matches by Android UI Automator | |
|
|
60
|
+
| ios | Click Element `|` ios=.buttons().withName('Apps') | Matches by iOS UI Automation | |
|
|
61
|
+
| predicate | Click Element `|` predicate=name=="login" | Matches by iOS Predicate | Check PR: #196 |
|
|
62
|
+
| chain | Click Element `|` chain=XCUIElementTypeWindow[1]/* | Matches by iOS Class Chain | |
|
|
63
|
+
| css | Click Element `|` css=.green_button | Matches by css in webview | |
|
|
64
|
+
| name | Click Element `|` name=my_element | Matches by @name attribute | *Only valid* for Selendroid |
|
|
65
|
+
|
|
66
|
+
== Using webelements ==
|
|
67
|
+
|
|
68
|
+
Starting with version 1.4 of the AppiumLibrary, one can pass an argument
|
|
69
|
+
that contains a WebElement instead of a string locator. To get a WebElement,
|
|
70
|
+
use the new `Get WebElements` or `Get WebElement` keyword.
|
|
71
|
+
|
|
72
|
+
For example:
|
|
73
|
+
| @{elements} Get Webelements class=UIAButton
|
|
74
|
+
| Click Element @{elements}[2]
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
|
|
79
|
+
ROBOT_LIBRARY_VERSION = VERSION
|
|
80
|
+
|
|
81
|
+
def __init__(self, timeout=5, run_on_failure='Appium Capture Page Screenshot', sleep_between_wait_loop=0.2):
|
|
82
|
+
"""AppiumLibrary can be imported with optional arguments.
|
|
83
|
+
|
|
84
|
+
``timeout`` is the default timeout used to wait for all waiting actions.
|
|
85
|
+
It can be later set with `Set Appium Timeout`.
|
|
86
|
+
|
|
87
|
+
``run_on_failure`` specifies the name of a keyword (from any available
|
|
88
|
+
libraries) to execute when a AppiumLibrary keyword fails.
|
|
89
|
+
|
|
90
|
+
By default `Capture Page Screenshot` will be used to take a screenshot of the current page.
|
|
91
|
+
Using the value `No Operation` will disable this feature altogether. See
|
|
92
|
+
`Register Keyword To Run On Failure` keyword for more information about this
|
|
93
|
+
functionality.
|
|
94
|
+
|
|
95
|
+
``sleep_between_wait_loop`` is the default sleep used to wait between loop in all wait until keywords
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
| Library | AppiumLibrary | 10 | # Sets default timeout to 10 seconds |
|
|
99
|
+
| Library | AppiumLibrary | timeout=10 | run_on_failure=No Operation | # Sets default timeout to 10 seconds and does nothing on failure |
|
|
100
|
+
| Library | AppiumLibrary | timeout=10 | sleep_between_wait_loop=0.3 | # Sets default timeout to 10 seconds and sleep 300 ms between wait loop |
|
|
101
|
+
"""
|
|
102
|
+
for base in AppiumLibrary.__bases__:
|
|
103
|
+
base.__init__(self)
|
|
104
|
+
self.set_appium_timeout(timeout)
|
|
105
|
+
self.register_keyword_to_run_on_failure(run_on_failure)
|
|
106
|
+
self.set_sleep_between_wait_loop(sleep_between_wait_loop)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ._applicationmanagement import _ApplicationManagementKeywords
|
|
4
|
+
from ._element import _ElementKeywords
|
|
5
|
+
from ._logging import _LoggingKeywords
|
|
6
|
+
from ._powershell import _PowershellKeywords
|
|
7
|
+
from ._runonfailure import _RunOnFailureKeywords
|
|
8
|
+
from ._screenrecord import _ScreenrecordKeywords
|
|
9
|
+
from ._screenshot import _ScreenshotKeywords
|
|
10
|
+
from ._waiting import _WaitingKeywords
|
|
11
|
+
from ._windows import _WindowsKeywords
|
|
12
|
+
|
|
13
|
+
__all__ = ["_LoggingKeywords",
|
|
14
|
+
"_RunOnFailureKeywords",
|
|
15
|
+
"_ElementKeywords",
|
|
16
|
+
"_PowershellKeywords",
|
|
17
|
+
"_WindowsKeywords",
|
|
18
|
+
"_ScreenshotKeywords",
|
|
19
|
+
"_ApplicationManagementKeywords",
|
|
20
|
+
"_WaitingKeywords",
|
|
21
|
+
"_ScreenrecordKeywords"]
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import robot
|
|
6
|
+
from appium import webdriver
|
|
7
|
+
from appium.options.common import AppiumOptions
|
|
8
|
+
|
|
9
|
+
from AppiumLibrary.utils import ApplicationCache
|
|
10
|
+
from .keywordgroup import KeywordGroup
|
|
11
|
+
|
|
12
|
+
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _ApplicationManagementKeywords(KeywordGroup):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self._cache = ApplicationCache()
|
|
18
|
+
self._timeout_in_secs = float(5)
|
|
19
|
+
|
|
20
|
+
# Public, open and close
|
|
21
|
+
def appium_get_current_application(self):
|
|
22
|
+
current = self._cache.current
|
|
23
|
+
if current is self._cache._no_current:
|
|
24
|
+
return None
|
|
25
|
+
return current
|
|
26
|
+
|
|
27
|
+
def appium_get_session_index(self):
|
|
28
|
+
current_index = self._cache.current_index
|
|
29
|
+
return current_index
|
|
30
|
+
|
|
31
|
+
def appium_close_application(self, ignore_fail=False, quit_app=True):
|
|
32
|
+
self._cache.close(ignore_fail, quit_app)
|
|
33
|
+
|
|
34
|
+
def appium_close_all_applications(self, ignore_fail=True, quit_app=True):
|
|
35
|
+
self._cache.close_all(ignore_fail, quit_app)
|
|
36
|
+
|
|
37
|
+
def appium_save_source(self, file_path='file_source.txt'):
|
|
38
|
+
page_source = self._invoke_original("get_source")
|
|
39
|
+
with open(file_path, 'w', encoding='utf-8') as file:
|
|
40
|
+
file.write(page_source)
|
|
41
|
+
|
|
42
|
+
def close_application(self):
|
|
43
|
+
"""Closes the current application and also close webdriver session."""
|
|
44
|
+
self._info('Closing application with session id %s' % self._current_application().session_id)
|
|
45
|
+
self._cache.close()
|
|
46
|
+
|
|
47
|
+
def close_all_applications(self, ignore_fail=True):
|
|
48
|
+
"""Closes all open applications.
|
|
49
|
+
|
|
50
|
+
This keyword is meant to be used in test or suite teardown to
|
|
51
|
+
make sure all the applications are closed before the test execution
|
|
52
|
+
finishes.
|
|
53
|
+
|
|
54
|
+
After this keyword, the application indices returned by `Open Application`
|
|
55
|
+
are reset and start from `1`.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
self._info('Closing all applications')
|
|
59
|
+
self._cache.close_all(ignore_fail)
|
|
60
|
+
|
|
61
|
+
def open_application(self, remote_url, alias=None, **kwargs):
|
|
62
|
+
"""Opens a new application to given Appium server.
|
|
63
|
+
Capabilities of appium server, Android and iOS,
|
|
64
|
+
Please check https://appium.io/docs/en/2.1/cli/args/
|
|
65
|
+
| *Option* | *Man.* | *Description* |
|
|
66
|
+
| remote_url | Yes | Appium server url |
|
|
67
|
+
| alias | no | alias |
|
|
68
|
+
| strict_ssl | No | allows you to send commands to an invalid certificate host like a self-signed one. |
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
| Open Application | http://localhost:4723/wd/hub | alias=Myapp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
|
|
72
|
+
| Open Application | http://localhost:4723/wd/hub | alias=Myapp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app | strict_ssl=False |
|
|
73
|
+
| Open Application | http://localhost:4723/wd/hub | platformName=Android | platformVersion=4.2.2 | deviceName=192.168.56.101:5555 | app=${CURDIR}/demoapp/OrangeDemoApp.apk | appPackage=com.netease.qa.orangedemo | appActivity=MainActivity |
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
desired_caps = AppiumOptions().load_capabilities(caps=kwargs)
|
|
77
|
+
application = webdriver.Remote(str(remote_url), options=desired_caps)
|
|
78
|
+
|
|
79
|
+
self._info('Opened application with session id %s' % application.session_id)
|
|
80
|
+
|
|
81
|
+
if hasattr(self, "clear_search_context"):
|
|
82
|
+
self._invoke_original("clear_search_context")
|
|
83
|
+
|
|
84
|
+
return self._cache.register(application, alias)
|
|
85
|
+
|
|
86
|
+
def switch_application(self, index_or_alias):
|
|
87
|
+
"""Switches the active application by index or alias.
|
|
88
|
+
|
|
89
|
+
`index_or_alias` is either application index (an integer) or alias
|
|
90
|
+
(a string). Index is got as the return value of `Open Application`.
|
|
91
|
+
|
|
92
|
+
This keyword returns the index of the previous active application,
|
|
93
|
+
which can be used to switch back to that application later.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
| ${appium1}= | Open Application | http://localhost:4723/wd/hub | alias=MyApp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
|
|
97
|
+
| ${appium2}= | Open Application | http://localhost:4755/wd/hub | alias=MyApp2 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
|
|
98
|
+
| Click Element | sendHello | # Executed on appium running at localhost:4755 |
|
|
99
|
+
| Switch Application | ${appium1} | # Switch using index |
|
|
100
|
+
| Click Element | ackHello | # Executed on appium running at localhost:4723 |
|
|
101
|
+
| Switch Application | MyApp2 | # Switch using alias |
|
|
102
|
+
| Page Should Contain Text | ackHello Received | # Executed on appium running at localhost:4755 |
|
|
103
|
+
|
|
104
|
+
"""
|
|
105
|
+
old_index = self._cache.current_index
|
|
106
|
+
if index_or_alias is None:
|
|
107
|
+
self._cache.close()
|
|
108
|
+
else:
|
|
109
|
+
self._cache.switch(index_or_alias)
|
|
110
|
+
return old_index
|
|
111
|
+
|
|
112
|
+
def launch_application(self):
|
|
113
|
+
"""*DEPRECATED!!* in selenium v4, use `Activate Application` keyword.
|
|
114
|
+
|
|
115
|
+
Launch application. Application can be launched while Appium session running.
|
|
116
|
+
This keyword can be used to launch application during test case or between test cases.
|
|
117
|
+
|
|
118
|
+
This keyword works while `Open Application` has a test running. This is good practice to `Launch Application`
|
|
119
|
+
and `Quit Application` between test cases. As Suite Setup is `Open Application`, `Test Setup` can be used to `Launch Application`
|
|
120
|
+
|
|
121
|
+
Example (syntax is just a representation, refer to RF Guide for usage of Setup/Teardown):
|
|
122
|
+
| [Setup Suite] |
|
|
123
|
+
| | Open Application | http://localhost:4723/wd/hub | platformName=Android | deviceName=192.168.56.101:5555 | app=${CURDIR}/demoapp/OrangeDemoApp.apk |
|
|
124
|
+
| [Test Setup] |
|
|
125
|
+
| | Launch Application |
|
|
126
|
+
| | | <<<test execution>>> |
|
|
127
|
+
| | | <<<test execution>>> |
|
|
128
|
+
| [Test Teardown] |
|
|
129
|
+
| | Quit Application |
|
|
130
|
+
| [Suite Teardown] |
|
|
131
|
+
| | Close Application |
|
|
132
|
+
|
|
133
|
+
See `Quit Application` for quiting application but keeping Appium sesion running.
|
|
134
|
+
"""
|
|
135
|
+
driver = self._current_application()
|
|
136
|
+
driver.launch_app()
|
|
137
|
+
|
|
138
|
+
def quit_application(self):
|
|
139
|
+
"""*DEPRECATED!!* in selenium v4, check `Close Application` keyword.
|
|
140
|
+
|
|
141
|
+
Close application. Application can be quit while Appium session is kept alive.
|
|
142
|
+
This keyword can be used to close application during test case or between test cases.
|
|
143
|
+
|
|
144
|
+
See `Launch Application` for an explanation.
|
|
145
|
+
|
|
146
|
+
"""
|
|
147
|
+
driver = self._current_application()
|
|
148
|
+
driver.close_app()
|
|
149
|
+
|
|
150
|
+
def reset_application(self):
|
|
151
|
+
"""*DEPRECATED!!* in selenium v4, check `Terminate Application` keyword.
|
|
152
|
+
|
|
153
|
+
Reset application. Open Application can be reset while Appium session is kept alive.
|
|
154
|
+
"""
|
|
155
|
+
driver = self._current_application()
|
|
156
|
+
driver.reset()
|
|
157
|
+
|
|
158
|
+
def remove_application(self, application_id):
|
|
159
|
+
""" Removes the application that is identified with an application id
|
|
160
|
+
|
|
161
|
+
Example:
|
|
162
|
+
| Remove Application | com.netease.qa.orangedemo |
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
driver = self._current_application()
|
|
166
|
+
driver.remove_app(application_id)
|
|
167
|
+
|
|
168
|
+
def get_appium_timeout(self):
|
|
169
|
+
"""Gets the timeout in seconds that is used by various keywords.
|
|
170
|
+
|
|
171
|
+
See `Set Appium Timeout` for an explanation."""
|
|
172
|
+
return robot.utils.secs_to_timestr(self._timeout_in_secs)
|
|
173
|
+
|
|
174
|
+
def set_appium_timeout(self, seconds):
|
|
175
|
+
"""Sets the timeout in seconds used by various keywords.
|
|
176
|
+
|
|
177
|
+
There are several `Wait ...` keywords that take timeout as an
|
|
178
|
+
argument. All of these timeout arguments are optional. The timeout
|
|
179
|
+
used by all of them can be set globally using this keyword.
|
|
180
|
+
|
|
181
|
+
The previous timeout value is returned by this keyword and can
|
|
182
|
+
be used to set the old value back later. The default timeout
|
|
183
|
+
is 5 seconds, but it can be altered in `importing`.
|
|
184
|
+
|
|
185
|
+
Example:
|
|
186
|
+
| ${orig timeout} = | Set Appium Timeout | 15 seconds |
|
|
187
|
+
| Open page that loads slowly |
|
|
188
|
+
| Set Appium Timeout | ${orig timeout} |
|
|
189
|
+
"""
|
|
190
|
+
old_timeout = self._invoke_original("get_appium_timeout")
|
|
191
|
+
self._timeout_in_secs = robot.utils.timestr_to_secs(seconds)
|
|
192
|
+
return old_timeout
|
|
193
|
+
|
|
194
|
+
def get_appium_sessionId(self):
|
|
195
|
+
"""Returns the current session ID as a reference"""
|
|
196
|
+
self._info("Appium Session ID: " + self._current_application().session_id)
|
|
197
|
+
return self._current_application().session_id
|
|
198
|
+
|
|
199
|
+
def get_source(self):
|
|
200
|
+
"""Returns the entire source of the current page."""
|
|
201
|
+
return self._current_application().page_source
|
|
202
|
+
|
|
203
|
+
def log_source(self, loglevel='INFO'):
|
|
204
|
+
"""Logs and returns the entire html source of the current page or frame.
|
|
205
|
+
|
|
206
|
+
The `loglevel` argument defines the used log level. Valid log levels are
|
|
207
|
+
`WARN`, `INFO` (default), `DEBUG`, `TRACE` and `NONE` (no logging).
|
|
208
|
+
"""
|
|
209
|
+
ll = loglevel.upper()
|
|
210
|
+
if ll == 'NONE':
|
|
211
|
+
return ''
|
|
212
|
+
else:
|
|
213
|
+
if "run_keyword_and_ignore_error" not in [check_error_ignored[3] for check_error_ignored in
|
|
214
|
+
inspect.stack()]:
|
|
215
|
+
source = self._current_application().page_source
|
|
216
|
+
self._log(source, ll)
|
|
217
|
+
return source
|
|
218
|
+
else:
|
|
219
|
+
return ''
|
|
220
|
+
|
|
221
|
+
def execute_script(self, script, **kwargs):
|
|
222
|
+
"""
|
|
223
|
+
Execute a variety of native, mobile commands that aren't associated
|
|
224
|
+
with a specific endpoint. See [https://appium.io/docs/en/commands/mobile-command/|Appium Mobile Command]
|
|
225
|
+
for more details.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
| &{scrollGesture} | create dictionary | left=${50} | top=${150} | width=${50} | height=${200} | direction=down | percent=${100} |
|
|
229
|
+
| Sleep | 1 |
|
|
230
|
+
| Execute Script | mobile: scrollGesture | &{scrollGesture} |
|
|
231
|
+
|
|
232
|
+
Updated in AppiumLibrary 2
|
|
233
|
+
"""
|
|
234
|
+
if kwargs:
|
|
235
|
+
self._info(f"Provided dictionary: {kwargs}")
|
|
236
|
+
|
|
237
|
+
return self._current_application().execute_script(script, kwargs)
|
|
238
|
+
|
|
239
|
+
def execute_async_script(self, script, **kwargs):
|
|
240
|
+
"""
|
|
241
|
+
Inject a snippet of Async-JavaScript into the page for execution in the
|
|
242
|
+
context of the currently selected frame (Web context only).
|
|
243
|
+
|
|
244
|
+
The executed script is assumed to be asynchronous and must signal that is done by
|
|
245
|
+
invoking the provided callback, which is always provided as the final argument to the
|
|
246
|
+
function.
|
|
247
|
+
|
|
248
|
+
The value to this callback will be returned to the client.
|
|
249
|
+
|
|
250
|
+
Check `Execute Script` for example kwargs usage
|
|
251
|
+
|
|
252
|
+
Updated in AppiumLibrary 2
|
|
253
|
+
"""
|
|
254
|
+
if kwargs:
|
|
255
|
+
self._info(f"Provided dictionary: {kwargs}")
|
|
256
|
+
|
|
257
|
+
return self._current_application().execute_async_script(script, kwargs)
|
|
258
|
+
|
|
259
|
+
def execute_adb_shell(self, command, *args):
|
|
260
|
+
"""
|
|
261
|
+
Execute ADB shell commands
|
|
262
|
+
|
|
263
|
+
Android only.
|
|
264
|
+
|
|
265
|
+
- _command_ - The ABD shell command
|
|
266
|
+
- _args_ - Arguments to send to command
|
|
267
|
+
|
|
268
|
+
Returns the exit code of ADB shell.
|
|
269
|
+
|
|
270
|
+
Requires server flag --relaxed-security to be set on Appium server.
|
|
271
|
+
"""
|
|
272
|
+
return self._current_application().execute_script('mobile: shell', {
|
|
273
|
+
'command': command,
|
|
274
|
+
'args': list(args)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
def execute_adb_shell_timeout(self, command, timeout, *args):
|
|
278
|
+
"""
|
|
279
|
+
Execute ADB shell commands
|
|
280
|
+
|
|
281
|
+
Android only.
|
|
282
|
+
|
|
283
|
+
- _command_ - The ABD shell command
|
|
284
|
+
- _timeout_ - Timeout to be applied to command
|
|
285
|
+
- _args_ - Arguments to send to command
|
|
286
|
+
|
|
287
|
+
Returns the exit code of ADB shell.
|
|
288
|
+
|
|
289
|
+
Requires server flag --relaxed-security to be set on Appium server.
|
|
290
|
+
"""
|
|
291
|
+
return self._current_application().execute_script('mobile: shell', {
|
|
292
|
+
'command': command,
|
|
293
|
+
'args': list(args),
|
|
294
|
+
'timeout': timeout
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
def go_back(self):
|
|
298
|
+
"""Goes one step backward in the browser history."""
|
|
299
|
+
self._current_application().back()
|
|
300
|
+
|
|
301
|
+
def lock(self, seconds=5):
|
|
302
|
+
"""
|
|
303
|
+
Lock the device for a certain period of time. iOS only.
|
|
304
|
+
"""
|
|
305
|
+
self._current_application().lock(robot.utils.timestr_to_secs(seconds))
|
|
306
|
+
|
|
307
|
+
def background_app(self, seconds=5):
|
|
308
|
+
"""*DEPRECATED!!* use `Background Application` instead.
|
|
309
|
+
Puts the application in the background on the device for a certain
|
|
310
|
+
duration.
|
|
311
|
+
"""
|
|
312
|
+
self._current_application().background_app(seconds)
|
|
313
|
+
|
|
314
|
+
def background_application(self, seconds=5):
|
|
315
|
+
"""
|
|
316
|
+
Puts the application in the background on the device for a certain
|
|
317
|
+
duration.
|
|
318
|
+
"""
|
|
319
|
+
self._current_application().background_app(seconds)
|
|
320
|
+
|
|
321
|
+
def activate_application(self, app_id):
|
|
322
|
+
"""
|
|
323
|
+
Activates the application if it is not running or is running in the background.
|
|
324
|
+
Args:
|
|
325
|
+
- app_id - BundleId for iOS. Package name for Android.
|
|
326
|
+
|
|
327
|
+
New in AppiumLibrary v2
|
|
328
|
+
"""
|
|
329
|
+
self._current_application().activate_app(app_id)
|
|
330
|
+
|
|
331
|
+
def terminate_application(self, app_id):
|
|
332
|
+
"""
|
|
333
|
+
Terminate the given app on the device
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
- app_id - BundleId for iOS. Package name for Android.
|
|
337
|
+
|
|
338
|
+
New in AppiumLibrary v2
|
|
339
|
+
"""
|
|
340
|
+
return self._current_application().terminate_app(app_id)
|
|
341
|
+
|
|
342
|
+
def stop_application(self, app_id, timeout=5000, include_stderr=True):
|
|
343
|
+
"""
|
|
344
|
+
Stop the given app on the device
|
|
345
|
+
|
|
346
|
+
Android only. New in AppiumLibrary v2
|
|
347
|
+
"""
|
|
348
|
+
self._current_application().execute_script('mobile: shell', {
|
|
349
|
+
'command': 'am force-stop',
|
|
350
|
+
'args': [app_id],
|
|
351
|
+
'includeStderr': include_stderr,
|
|
352
|
+
'timeout': timeout
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
def touch_id(self, match=True):
|
|
356
|
+
"""
|
|
357
|
+
Simulate Touch ID on iOS Simulator
|
|
358
|
+
|
|
359
|
+
`match` (boolean) whether the simulated fingerprint is valid (default true)
|
|
360
|
+
|
|
361
|
+
New in AppiumLibrary 1.5
|
|
362
|
+
"""
|
|
363
|
+
self._current_application().touch_id(match)
|
|
364
|
+
|
|
365
|
+
def toggle_touch_id_enrollment(self):
|
|
366
|
+
"""
|
|
367
|
+
Toggle Touch ID enrolled state on iOS Simulator
|
|
368
|
+
|
|
369
|
+
New in AppiumLibrary 1.5
|
|
370
|
+
"""
|
|
371
|
+
self._current_application().toggle_touch_id_enrollment()
|
|
372
|
+
|
|
373
|
+
def shake(self):
|
|
374
|
+
"""
|
|
375
|
+
Shake the device
|
|
376
|
+
"""
|
|
377
|
+
self._current_application().shake()
|
|
378
|
+
|
|
379
|
+
def portrait(self):
|
|
380
|
+
"""
|
|
381
|
+
Set the device orientation to PORTRAIT
|
|
382
|
+
"""
|
|
383
|
+
self._rotate('PORTRAIT')
|
|
384
|
+
|
|
385
|
+
def landscape(self):
|
|
386
|
+
"""
|
|
387
|
+
Set the device orientation to LANDSCAPE
|
|
388
|
+
"""
|
|
389
|
+
self._rotate('LANDSCAPE')
|
|
390
|
+
|
|
391
|
+
def get_current_context(self):
|
|
392
|
+
"""Get current context."""
|
|
393
|
+
return self._current_application().current_context
|
|
394
|
+
|
|
395
|
+
def get_contexts(self):
|
|
396
|
+
"""Get available contexts."""
|
|
397
|
+
print(self._current_application().contexts)
|
|
398
|
+
return self._current_application().contexts
|
|
399
|
+
|
|
400
|
+
def get_window_height(self):
|
|
401
|
+
"""Get current device height.
|
|
402
|
+
|
|
403
|
+
Example:
|
|
404
|
+
| ${width} | Get Window Width |
|
|
405
|
+
| ${height} | Get Window Height |
|
|
406
|
+
| Click A Point | ${width} | ${height} |
|
|
407
|
+
|
|
408
|
+
New in AppiumLibrary 1.4.5
|
|
409
|
+
"""
|
|
410
|
+
return self._current_application().get_window_size()['height']
|
|
411
|
+
|
|
412
|
+
def get_window_width(self):
|
|
413
|
+
"""Get current device width.
|
|
414
|
+
|
|
415
|
+
Example:
|
|
416
|
+
| ${width} | Get Window Width |
|
|
417
|
+
| ${height} | Get Window Height |
|
|
418
|
+
| Click A Point | ${width} | ${height} |
|
|
419
|
+
|
|
420
|
+
New in AppiumLibrary 1.4.5
|
|
421
|
+
"""
|
|
422
|
+
return self._current_application().get_window_size()['width']
|
|
423
|
+
|
|
424
|
+
def switch_to_context(self, context_name):
|
|
425
|
+
"""Switch to a new context"""
|
|
426
|
+
self._current_application().switch_to.context(context_name)
|
|
427
|
+
|
|
428
|
+
def switch_to_frame(self, frame):
|
|
429
|
+
"""
|
|
430
|
+
Switches focus to the specified frame, by index, name, or webelement.
|
|
431
|
+
|
|
432
|
+
Example:
|
|
433
|
+
| Go To Url | http://www.xxx.com |
|
|
434
|
+
| Switch To Frame | iframe_name|
|
|
435
|
+
| Click Element | xpath=//*[@id="online-btn"] |
|
|
436
|
+
"""
|
|
437
|
+
self._current_application().switch_to.frame(frame)
|
|
438
|
+
|
|
439
|
+
def switch_to_parent_frame(self):
|
|
440
|
+
"""
|
|
441
|
+
Switches focus to the parent context. If the current context is the top
|
|
442
|
+
level browsing context, the context remains unchanged.
|
|
443
|
+
"""
|
|
444
|
+
self._current_application().switch_to.parent_frame()
|
|
445
|
+
|
|
446
|
+
def switch_to_window(self, window_name):
|
|
447
|
+
"""
|
|
448
|
+
Switch to a new webview window if the application contains multiple webviews
|
|
449
|
+
"""
|
|
450
|
+
self._current_application().switch_to.window(window_name)
|
|
451
|
+
|
|
452
|
+
def go_to_url(self, url):
|
|
453
|
+
"""
|
|
454
|
+
Opens URL in default web browser.
|
|
455
|
+
|
|
456
|
+
Example:
|
|
457
|
+
| Open Application | http://localhost:4755/wd/hub | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | browserName=Safari |
|
|
458
|
+
| Go To URL | http://m.webapp.com |
|
|
459
|
+
"""
|
|
460
|
+
self._current_application().get(url)
|
|
461
|
+
|
|
462
|
+
def get_capability(self, capability_name=None):
|
|
463
|
+
"""
|
|
464
|
+
Return the desired capability value by desired capability name
|
|
465
|
+
"""
|
|
466
|
+
try:
|
|
467
|
+
capabilities = self._current_application().capabilities
|
|
468
|
+
capability = capabilities[capability_name] if capability_name else capabilities
|
|
469
|
+
except Exception as e:
|
|
470
|
+
raise e
|
|
471
|
+
return capability
|
|
472
|
+
|
|
473
|
+
def get_window_title(self):
|
|
474
|
+
"""Get the current Webview window title."""
|
|
475
|
+
return self._current_application().title
|
|
476
|
+
|
|
477
|
+
def get_window_url(self):
|
|
478
|
+
"""Get the current Webview window URL."""
|
|
479
|
+
return self._current_application().current_url
|
|
480
|
+
|
|
481
|
+
def get_windows(self):
|
|
482
|
+
"""Get available Webview windows."""
|
|
483
|
+
print(self._current_application().window_handles)
|
|
484
|
+
return self._current_application().window_handles
|
|
485
|
+
|
|
486
|
+
# Private
|
|
487
|
+
|
|
488
|
+
def _current_application(self):
|
|
489
|
+
if not self._cache.current:
|
|
490
|
+
raise RuntimeError('No application is open')
|
|
491
|
+
return self._cache.current
|
|
492
|
+
|
|
493
|
+
def _get_platform(self):
|
|
494
|
+
try:
|
|
495
|
+
platform_name = self._current_application().capabilities['platformName']
|
|
496
|
+
except Exception as e:
|
|
497
|
+
raise e
|
|
498
|
+
return platform_name.lower()
|
|
499
|
+
|
|
500
|
+
def _is_platform(self, platform):
|
|
501
|
+
platform_name = self._get_platform()
|
|
502
|
+
return platform.lower() == platform_name
|
|
503
|
+
|
|
504
|
+
def _is_ios(self):
|
|
505
|
+
return self._is_platform('ios')
|
|
506
|
+
|
|
507
|
+
def _is_android(self):
|
|
508
|
+
return self._is_platform('android')
|
|
509
|
+
|
|
510
|
+
def _is_window(self):
|
|
511
|
+
return self._is_platform('windows')
|
|
512
|
+
|
|
513
|
+
def _rotate(self, orientation):
|
|
514
|
+
driver = self._current_application()
|
|
515
|
+
driver.orientation = orientation
|