robotframework-appiumwindows 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.
@@ -1,515 +1,595 @@
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
1
+ # -*- coding: utf-8 -*-
2
+ import base64
3
+ import inspect
4
+ import os
5
+
6
+ import robot
7
+ from appium import webdriver
8
+ from appium.options.common import AppiumOptions
9
+ from appium.webdriver.client_config import AppiumClientConfig
10
+
11
+ from AppiumLibrary.utils import ApplicationCache
12
+ from .keywordgroup import KeywordGroup
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.get_source()
39
+ with open(file_path, 'w', encoding='utf-8') as file:
40
+ file.write(page_source)
41
+
42
+ def appium_activate_application(self, process):
43
+ """Activates the application with the given process name.
44
+
45
+ Args:
46
+ process (str): The process name of the application to activate.
47
+
48
+ Example:
49
+ | Appium Activate Application | notepad.exe |
50
+ """
51
+ self._info(f"Activating application '{process}'")
52
+ driver = self._current_application()
53
+ driver.execute_script('windows: setProcessForeground', {'process': process})
54
+
55
+ def appium_set_clipboard(self, content, content_type='plaintext', encode_base64=True):
56
+ """Sets the clipboard content.
57
+
58
+ Args:
59
+ content (str): The content to set to the clipboard.
60
+ content_type (str): The type of content to set to the clipboard.
61
+ encode_base64 (bool): Whether to encode the clipboard content to base64.
62
+
63
+ Example:
64
+ | Appium Set Clipboard | Hello World |
65
+ """
66
+ self._info("Setting clipboard content")
67
+ if content_type == 'text/plain':
68
+ content_type = 'plaintext'
69
+ elif content_type == 'image/png':
70
+ content_type = 'image'
71
+
72
+ if content_type not in ['plaintext', 'image']:
73
+ raise ValueError("Invalid content type. Must be 'plaintext' or 'image'.")
74
+
75
+ if encode_base64:
76
+ content = base64.b64encode(content.encode('utf-8')).decode('utf-8')
77
+
78
+ driver = self._current_application()
79
+ result = driver.execute_script('windows: setClipboard', {'b64Content': content, 'contentType': content_type})
80
+ return result
81
+
82
+ def appium_get_clipboard(self, content_type='plaintext', decode_base64=True):
83
+ """Gets the clipboard content.
84
+
85
+ Args:
86
+ content_type (str): The type of content to get from the clipboard.
87
+ decode_base64 (bool): Whether to decode the clipboard content from base64.
88
+
89
+ Returns:
90
+ str: The clipboard content.
91
+
92
+ Example:
93
+ | ${clipboard}= | Appium Get Clipboard |
94
+ """
95
+ self._info("Getting clipboard content")
96
+ if content_type == 'text/plain':
97
+ content_type = 'plaintext'
98
+ elif content_type == 'image/png':
99
+ content_type = 'image'
100
+
101
+ if content_type not in ['plaintext', 'image']:
102
+ raise ValueError("Invalid content type. Must be 'plaintext' or 'image'.")
103
+
104
+ driver = self._current_application()
105
+ clipboard = driver.execute_script('windows: getClipboard', {'contentType': content_type})
106
+
107
+ if decode_base64:
108
+ clipboard = base64.b64decode(clipboard).decode('utf-8')
109
+ return clipboard
110
+
111
+ def close_application(self):
112
+ """Closes the current application and also close webdriver session."""
113
+ self._info('Closing application with session id %s' % self._current_application().session_id)
114
+ self._cache.close()
115
+
116
+ def close_all_applications(self, ignore_fail=True):
117
+ """Closes all open applications.
118
+
119
+ This keyword is meant to be used in test or suite teardown to
120
+ make sure all the applications are closed before the test execution
121
+ finishes.
122
+
123
+ After this keyword, the application indices returned by `Open Application`
124
+ are reset and start from `1`.
125
+ """
126
+
127
+ self._info('Closing all applications')
128
+ self._cache.close_all(ignore_fail)
129
+
130
+ def open_application(self, remote_url, alias=None, **kwargs):
131
+ """Opens a new application to given Appium server.
132
+ Capabilities of appium server, Android and iOS,
133
+ Please check https://appium.io/docs/en/2.1/cli/args/
134
+ | *Option* | *Man.* | *Description* |
135
+ | remote_url | Yes | Appium server url |
136
+ | alias | no | alias |
137
+ | strict_ssl | No | allows you to send commands to an invalid certificate host like a self-signed one. |
138
+
139
+ Examples:
140
+ | Open Application | http://localhost:4723/wd/hub | alias=Myapp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
141
+ | Open Application | http://localhost:4723/wd/hub | alias=Myapp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app | strict_ssl=False |
142
+ | 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 |
143
+ | Open Application | http://localhost:4723/wd/hub | platformName=Windows | automationName=NovaWindows2 | app=Root | # Connect to Windows Desktop using NovaWindows2 driver |
144
+ """
145
+ # Parse AppiumClientConfig arguments from kwargs
146
+ ignore_certificates = kwargs.pop('ignore_certificates', True)
147
+
148
+ # Handle strict_ssl alias for ignore_certificates (strict_ssl=False -> ignore_certificates=True)
149
+ if 'strict_ssl' in kwargs:
150
+ ignore_certificates = str(kwargs.pop('strict_ssl')).lower() == 'false'
151
+
152
+ client_config = AppiumClientConfig(remote_url,
153
+ direct_connection=kwargs.pop('direct_connection', True),
154
+ keep_alive=kwargs.pop('keep_alive', False),
155
+ ignore_certificates=ignore_certificates)
156
+
157
+ options = AppiumOptions().load_capabilities(caps=kwargs)
158
+ application = webdriver.Remote(command_executor=str(remote_url), options=options, client_config=client_config)
159
+
160
+ self._info(f'Opened application with session id {application.session_id}')
161
+
162
+ if hasattr(self, "clear_search_context"):
163
+ self.clear_search_context()
164
+
165
+ return self._cache.register(application, alias)
166
+
167
+ def switch_application(self, index_or_alias):
168
+ """Switches the active application by index or alias.
169
+
170
+ `index_or_alias` is either application index (an integer) or alias
171
+ (a string). Index is got as the return value of `Open Application`.
172
+
173
+ This keyword returns the index of the previous active application,
174
+ which can be used to switch back to that application later.
175
+
176
+ Example:
177
+ | ${appium1}= | Open Application | http://localhost:4723/wd/hub | alias=MyApp1 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
178
+ | ${appium2}= | Open Application | http://localhost:4755/wd/hub | alias=MyApp2 | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | app=your.app |
179
+ | Click Element | sendHello | # Executed on appium running at localhost:4755 |
180
+ | Switch Application | ${appium1} | # Switch using index |
181
+ | Click Element | ackHello | # Executed on appium running at localhost:4723 |
182
+ | Switch Application | MyApp2 | # Switch using alias |
183
+ | Page Should Contain Text | ackHello Received | # Executed on appium running at localhost:4755 |
184
+
185
+ """
186
+ old_index = self._cache.current_index
187
+ if index_or_alias is None:
188
+ self._cache.close()
189
+ else:
190
+ self._cache.switch(index_or_alias)
191
+ return old_index
192
+
193
+ def launch_application(self):
194
+ """*DEPRECATED!!* in selenium v4, use `Activate Application` keyword.
195
+
196
+ Launch application. Application can be launched while Appium session running.
197
+ This keyword can be used to launch application during test case or between test cases.
198
+
199
+ This keyword works while `Open Application` has a test running. This is good practice to `Launch Application`
200
+ and `Quit Application` between test cases. As Suite Setup is `Open Application`, `Test Setup` can be used to `Launch Application`
201
+
202
+ Example (syntax is just a representation, refer to RF Guide for usage of Setup/Teardown):
203
+ | [Setup Suite] |
204
+ | | Open Application | http://localhost:4723/wd/hub | platformName=Android | deviceName=192.168.56.101:5555 | app=${CURDIR}/demoapp/OrangeDemoApp.apk |
205
+ | [Test Setup] |
206
+ | | Launch Application |
207
+ | | | <<<test execution>>> |
208
+ | | | <<<test execution>>> |
209
+ | [Test Teardown] |
210
+ | | Quit Application |
211
+ | [Suite Teardown] |
212
+ | | Close Application |
213
+
214
+ See `Quit Application` for quiting application but keeping Appium sesion running.
215
+ """
216
+ driver = self._current_application()
217
+ driver.launch_app()
218
+
219
+ def quit_application(self):
220
+ """*DEPRECATED!!* in selenium v4, check `Close Application` keyword.
221
+
222
+ Close application. Application can be quit while Appium session is kept alive.
223
+ This keyword can be used to close application during test case or between test cases.
224
+
225
+ See `Launch Application` for an explanation.
226
+
227
+ """
228
+ driver = self._current_application()
229
+ driver.close_app()
230
+
231
+ def reset_application(self):
232
+ """*DEPRECATED!!* in selenium v4, check `Terminate Application` keyword.
233
+
234
+ Reset application. Open Application can be reset while Appium session is kept alive.
235
+ """
236
+ driver = self._current_application()
237
+ driver.reset()
238
+
239
+ def remove_application(self, application_id):
240
+ """ Removes the application that is identified with an application id
241
+
242
+ Example:
243
+ | Remove Application | com.netease.qa.orangedemo |
244
+
245
+ """
246
+ driver = self._current_application()
247
+ driver.remove_app(application_id)
248
+
249
+ def get_appium_timeout(self):
250
+ """Gets the timeout in seconds that is used by various keywords.
251
+
252
+ See `Set Appium Timeout` for an explanation."""
253
+ return robot.utils.secs_to_timestr(self._timeout_in_secs)
254
+
255
+ def set_appium_timeout(self, seconds):
256
+ """Sets the timeout in seconds used by various keywords.
257
+
258
+ There are several `Wait ...` keywords that take timeout as an
259
+ argument. All of these timeout arguments are optional. The timeout
260
+ used by all of them can be set globally using this keyword.
261
+
262
+ The previous timeout value is returned by this keyword and can
263
+ be used to set the old value back later. The default timeout
264
+ is 5 seconds, but it can be altered in `importing`.
265
+
266
+ Example:
267
+ | ${orig timeout} = | Set Appium Timeout | 15 seconds |
268
+ | Open page that loads slowly |
269
+ | Set Appium Timeout | ${orig timeout} |
270
+ """
271
+ old_timeout = self.get_appium_timeout()
272
+ self._timeout_in_secs = robot.utils.timestr_to_secs(seconds)
273
+ return old_timeout
274
+
275
+ def get_appium_sessionId(self):
276
+ """Returns the current session ID as a reference"""
277
+ self._info("Appium Session ID: " + self._current_application().session_id)
278
+ return self._current_application().session_id
279
+
280
+ def get_source(self):
281
+ """Returns the entire source of the current page."""
282
+ return self._current_application().page_source
283
+
284
+ def log_source(self, loglevel='INFO'):
285
+ """Logs and returns the entire html source of the current page or frame.
286
+
287
+ The `loglevel` argument defines the used log level. Valid log levels are
288
+ `WARN`, `INFO` (default), `DEBUG`, `TRACE` and `NONE` (no logging).
289
+ """
290
+ ll = loglevel.upper()
291
+ if ll == 'NONE':
292
+ return ''
293
+ else:
294
+ if "run_keyword_and_ignore_error" not in [check_error_ignored[3] for check_error_ignored in inspect.stack()]:
295
+ source = self._current_application().page_source
296
+ self._log(source, ll)
297
+ return source
298
+ else:
299
+ return ''
300
+
301
+ def execute_script(self, script, **kwargs):
302
+ """
303
+ Execute a variety of native, mobile commands that aren't associated
304
+ with a specific endpoint. See [https://appium.io/docs/en/commands/mobile-command/|Appium Mobile Command]
305
+ for more details.
306
+
307
+ Example:
308
+ | &{scrollGesture} | create dictionary | left=${50} | top=${150} | width=${50} | height=${200} | direction=down | percent=${100} |
309
+ | Sleep | 1 |
310
+ | Execute Script | mobile: scrollGesture | &{scrollGesture} |
311
+
312
+ Updated in AppiumLibrary 2
313
+ """
314
+ if kwargs:
315
+ self._info(f"Provided dictionary: {kwargs}")
316
+
317
+ return self._current_application().execute_script(script, kwargs)
318
+
319
+ def execute_async_script(self, script, **kwargs):
320
+ """
321
+ Inject a snippet of Async-JavaScript into the page for execution in the
322
+ context of the currently selected frame (Web context only).
323
+
324
+ The executed script is assumed to be asynchronous and must signal that is done by
325
+ invoking the provided callback, which is always provided as the final argument to the
326
+ function.
327
+
328
+ The value to this callback will be returned to the client.
329
+
330
+ Check `Execute Script` for example kwargs usage
331
+
332
+ Updated in AppiumLibrary 2
333
+ """
334
+ if kwargs:
335
+ self._info(f"Provided dictionary: {kwargs}")
336
+
337
+ return self._current_application().execute_async_script(script, kwargs)
338
+
339
+ def execute_adb_shell(self, command, *args):
340
+ """
341
+ Execute ADB shell commands
342
+
343
+ Android only.
344
+
345
+ - _command_ - The ABD shell command
346
+ - _args_ - Arguments to send to command
347
+
348
+ Returns the exit code of ADB shell.
349
+
350
+ Requires server flag --relaxed-security to be set on Appium server.
351
+ """
352
+ return self._current_application().execute_script('mobile: shell', {
353
+ 'command': command,
354
+ 'args': list(args)
355
+ })
356
+
357
+ def execute_adb_shell_timeout(self, command, timeout, *args):
358
+ """
359
+ Execute ADB shell commands
360
+
361
+ Android only.
362
+
363
+ - _command_ - The ABD shell command
364
+ - _timeout_ - Timeout to be applied to command
365
+ - _args_ - Arguments to send to command
366
+
367
+ Returns the exit code of ADB shell.
368
+
369
+ Requires server flag --relaxed-security to be set on Appium server.
370
+ """
371
+ return self._current_application().execute_script('mobile: shell', {
372
+ 'command': command,
373
+ 'args': list(args),
374
+ 'timeout': timeout
375
+ })
376
+
377
+ def go_back(self):
378
+ """Goes one step backward in the browser history."""
379
+ self._current_application().back()
380
+
381
+ def lock(self, seconds=5):
382
+ """
383
+ Lock the device for a certain period of time. iOS only.
384
+ """
385
+ self._current_application().lock(robot.utils.timestr_to_secs(seconds))
386
+
387
+ def background_app(self, seconds=5):
388
+ """*DEPRECATED!!* use `Background Application` instead.
389
+ Puts the application in the background on the device for a certain
390
+ duration.
391
+ """
392
+ self._current_application().background_app(seconds)
393
+
394
+ def background_application(self, seconds=5):
395
+ """
396
+ Puts the application in the background on the device for a certain
397
+ duration.
398
+ """
399
+ self._current_application().background_app(seconds)
400
+
401
+ def activate_application(self, app_id):
402
+ """
403
+ Activates the application if it is not running or is running in the background.
404
+ Args:
405
+ - app_id - BundleId for iOS. Package name for Android.
406
+
407
+ New in AppiumLibrary v2
408
+ """
409
+ self._current_application().activate_app(app_id)
410
+
411
+ def terminate_application(self, app_id):
412
+ """
413
+ Terminate the given app on the device
414
+
415
+ Args:
416
+ - app_id - BundleId for iOS. Package name for Android.
417
+
418
+ New in AppiumLibrary v2
419
+ """
420
+ return self._current_application().terminate_app(app_id)
421
+
422
+ def stop_application(self, app_id, timeout=5000, include_stderr=True):
423
+ """
424
+ Stop the given app on the device
425
+
426
+ Android only. New in AppiumLibrary v2
427
+ """
428
+ self._current_application().execute_script('mobile: shell', {
429
+ 'command': 'am force-stop',
430
+ 'args': [app_id],
431
+ 'includeStderr': include_stderr,
432
+ 'timeout': timeout
433
+ })
434
+
435
+ def touch_id(self, match=True):
436
+ """
437
+ Simulate Touch ID on iOS Simulator
438
+
439
+ `match` (boolean) whether the simulated fingerprint is valid (default true)
440
+
441
+ New in AppiumLibrary 1.5
442
+ """
443
+ self._current_application().touch_id(match)
444
+
445
+ def toggle_touch_id_enrollment(self):
446
+ """
447
+ Toggle Touch ID enrolled state on iOS Simulator
448
+
449
+ New in AppiumLibrary 1.5
450
+ """
451
+ self._current_application().toggle_touch_id_enrollment()
452
+
453
+ def shake(self):
454
+ """
455
+ Shake the device
456
+ """
457
+ self._current_application().shake()
458
+
459
+ def portrait(self):
460
+ """
461
+ Set the device orientation to PORTRAIT
462
+ """
463
+ self._rotate('PORTRAIT')
464
+
465
+ def landscape(self):
466
+ """
467
+ Set the device orientation to LANDSCAPE
468
+ """
469
+ self._rotate('LANDSCAPE')
470
+
471
+ def get_current_context(self):
472
+ """Get current context."""
473
+ return self._current_application().current_context
474
+
475
+ def get_contexts(self):
476
+ """Get available contexts."""
477
+ print(self._current_application().contexts)
478
+ return self._current_application().contexts
479
+
480
+ def get_window_height(self):
481
+ """Get current device height.
482
+
483
+ Example:
484
+ | ${width} | Get Window Width |
485
+ | ${height} | Get Window Height |
486
+ | Click A Point | ${width} | ${height} |
487
+
488
+ New in AppiumLibrary 1.4.5
489
+ """
490
+ return self._current_application().get_window_size()['height']
491
+
492
+ def get_window_width(self):
493
+ """Get current device width.
494
+
495
+ Example:
496
+ | ${width} | Get Window Width |
497
+ | ${height} | Get Window Height |
498
+ | Click A Point | ${width} | ${height} |
499
+
500
+ New in AppiumLibrary 1.4.5
501
+ """
502
+ return self._current_application().get_window_size()['width']
503
+
504
+ def switch_to_context(self, context_name):
505
+ """Switch to a new context"""
506
+ self._current_application().switch_to.context(context_name)
507
+
508
+ def switch_to_frame(self, frame):
509
+ """
510
+ Switches focus to the specified frame, by index, name, or webelement.
511
+
512
+ Example:
513
+ | Go To Url | http://www.xxx.com |
514
+ | Switch To Frame | iframe_name|
515
+ | Click Element | xpath=//*[@id="online-btn"] |
516
+ """
517
+ self._current_application().switch_to.frame(frame)
518
+
519
+ def switch_to_parent_frame(self):
520
+ """
521
+ Switches focus to the parent context. If the current context is the top
522
+ level browsing context, the context remains unchanged.
523
+ """
524
+ self._current_application().switch_to.parent_frame()
525
+
526
+ def switch_to_window(self, window_name):
527
+ """
528
+ Switch to a new webview window if the application contains multiple webviews
529
+ """
530
+ self._current_application().switch_to.window(window_name)
531
+
532
+ def go_to_url(self, url):
533
+ """
534
+ Opens URL in default web browser.
535
+
536
+ Example:
537
+ | Open Application | http://localhost:4755/wd/hub | platformName=iOS | platformVersion=7.0 | deviceName='iPhone Simulator' | browserName=Safari |
538
+ | Go To URL | http://m.webapp.com |
539
+ """
540
+ self._current_application().get(url)
541
+
542
+ def get_capability(self, capability_name=None):
543
+ """
544
+ Return the desired capability value by desired capability name
545
+ """
546
+ try:
547
+ capabilities = self._current_application().capabilities
548
+ capability = capabilities[capability_name] if capability_name else capabilities
549
+ except Exception as e:
550
+ raise e
551
+ return capability
552
+
553
+ def get_window_title(self):
554
+ """Get the current Webview window title."""
555
+ return self._current_application().title
556
+
557
+ def get_window_url(self):
558
+ """Get the current Webview window URL."""
559
+ return self._current_application().current_url
560
+
561
+ def get_windows(self):
562
+ """Get available Webview windows."""
563
+ print(self._current_application().window_handles)
564
+ return self._current_application().window_handles
565
+
566
+ # Private
567
+
568
+ def _current_application(self):
569
+ if not self._cache.current:
570
+ raise RuntimeError('No application is open')
571
+ return self._cache.current
572
+
573
+ def _get_platform(self):
574
+ try:
575
+ platform_name = self._current_application().capabilities['platformName']
576
+ except Exception as e:
577
+ raise e
578
+ return platform_name.lower()
579
+
580
+ def _is_platform(self, platform):
581
+ platform_name = self._get_platform()
582
+ return platform.lower() == platform_name
583
+
584
+ def _is_ios(self):
585
+ return self._is_platform('ios')
586
+
587
+ def _is_android(self):
588
+ return self._is_platform('android')
589
+
590
+ def _is_window(self):
591
+ return self._is_platform('windows')
592
+
593
+ def _rotate(self, orientation):
594
+ driver = self._current_application()
595
+ driver.orientation = orientation