Skip to content
This repository was archived by the owner on Mar 31, 2020. It is now read-only.

Commit a92d1f9

Browse files
committed
Add context methods
1 parent 189f22d commit a92d1f9

13 files changed

Lines changed: 353 additions & 6 deletions

File tree

README.md

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,75 @@
11
Appium Python Client
22
====================
33

4-
An extension library for adding [Selenium 3.0 draft](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile) functionality to [Appium](https://github.com/appium/appium).
4+
An extension library for adding [Selenium 3.0 draft](https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html) and [Mobile JSON Wire Protocol Specification draft](https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile)
5+
functionality to the Python language bindings, for use with the mobile testing
6+
framework [Appium](https://appium.io).
57

8+
# Usage
69

10+
The Appium Python Client is fully compliant with the Selenium 3.0 specification
11+
draft, with some helpers to make mobile testing in Python easier. The majority of
12+
the usage remains as it has been for Selenium 2 (WebDriver), and as the [official
13+
Selenium Python bindings](https://pypi.python.org/pypi/selenium) begins to
14+
implement the new specification that implementation will be used underneath, so
15+
test code can be written that is utilizable with both bindings.
16+
17+
To use the new functionality now, and to use the superset of functions, instead of
18+
including the Selenium `webdriver` module in your test code, use that from
19+
Appium instead.
20+
21+
```python
22+
from appium import webdriver
23+
```
24+
25+
From there much of your test code will work with no change.
26+
27+
As a base for the following code examples, the following sets up the [UnitTest](https://docs.python.org/2/library/unittest.html)
28+
environment:
29+
30+
```python
31+
from appium import webdriver
32+
33+
desired_caps = {}
34+
desired_caps['device'] = 'Android'
35+
desired_caps['browserName'] = ''
36+
desired_caps['version'] = '4.2'
37+
desired_caps['app'] = PATH('../../../apps/selendroid-test-app.apk')
38+
desired_caps['app-package'] = 'io.selendroid.testapp'
39+
desired_caps['app-activity'] = '.HomeScreenActivity'
40+
41+
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
42+
```
43+
44+
## Changed or added functionality
45+
46+
The methods that do change are...
47+
48+
49+
### Switching between 'Native' and 'Webview'
50+
51+
For mobile testing the Selnium methods for switching between windows was previously
52+
commandeered for switching between native applications and webview contexts. Methods
53+
explicitly for this have been added to the Selenium 3 specification, so moving
54+
forward these 'context' methods are to be used.
55+
56+
To get the current context, rather than calling `driver.current_window_handle` you
57+
use
58+
59+
```python
60+
current = driver.context
61+
```
62+
63+
The available contexts are not retrieved using `driver.window_handles` but with
64+
65+
```python
66+
driver.contexts
67+
```
68+
69+
Finally, to switch to a new context, rather than `driver.switch_to.window(name)`,
70+
use the comparable context method
71+
72+
```python
73+
context_name = "WEBVIEW_1"
74+
driver.switch_to.context(context_name)
75+
```

appium/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
1+
#!/usr/bin/env python
12

3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

appium/common/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

appium/common/exceptions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from selenium.common.exceptions import InvalidSwitchToTargetException
16+
17+
class NoSuchContextException(InvalidSwitchToTargetException):
18+
"""
19+
Thrown when window target to be switched doesn't exist.
20+
21+
To find the current set of active window handles, you can get a list
22+
of the active window handles in the following way::
23+
24+
print driver.window_handles
25+
26+
"""
27+
pass

appium/mobilecommand.py

Lines changed: 0 additions & 2 deletions
This file was deleted.

appium/webdriver/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
from webdriver import WebDriver as Remote

appium/webdriver/errorhandler.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from selenium.webdriver.remote import errorhandler
16+
from selenium.common.exceptions import WebDriverException
17+
18+
from appium.common.exceptions import NoSuchContextException
19+
20+
class MobileErrorHandler(errorhandler.ErrorHandler):
21+
def check_response(self, response):
22+
try:
23+
super(MobileErrorHandler, self).check_response(response)
24+
except WebDriverException as wde:
25+
if wde.msg == 'No such context found.':
26+
raise NoSuchContextException(wde.msg, wde.screen, wde.stacktrace)
27+
else:
28+
raise wde
29+

appium/webdriver/mobilecommand.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
class MobileCommand(object):
16+
CONTEXTS = 'getContexts',
17+
GET_CURRENT_CONTEXT = 'getCurrentContext',
18+
SWITCH_TO_CONTEXT = 'switchToContext'

appium/webdriver/switch_to.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from selenium.webdriver.remote.switch_to import SwitchTo
16+
17+
from .mobilecommand import MobileCommand
18+
19+
class MobileSwitchTo(SwitchTo):
20+
def context(self, context_name):
21+
"""
22+
Sets the context for the current session.
23+
24+
:Args:
25+
- context_name: The name of the context to switch to.
26+
27+
:Usage:
28+
driver.switch_to.context('WEBVIEW_1')
29+
"""
30+
self._driver.execute(MobileCommand.SWITCH_TO_CONTEXT, {'name': context_name})

appium/webdriver/webdriver.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,59 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
214

315
from selenium import webdriver
416

17+
from .mobilecommand import MobileCommand as Command
18+
from .errorhandler import MobileErrorHandler
19+
from .switch_to import MobileSwitchTo
20+
521
class WebDriver(webdriver.Remote):
622
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
723
desired_capabilities=None, browser_profile=None, proxy=None, keep_alive=False):
824

9-
# we have no new initialization to do
1025
super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)
26+
27+
if self.command_executor is not None:
28+
self._addCommands()
29+
30+
self.error_handler = MobileErrorHandler()
31+
self._switch_to = MobileSwitchTo(self)
32+
33+
@property
34+
def contexts(self):
35+
"""
36+
Returns the contexts within the current session.
37+
38+
:Usage:
39+
driver.contexts
40+
"""
41+
return self.execute(Command.CONTEXTS)['value'];
42+
43+
@property
44+
def current_context(self):
45+
"""
46+
Returns the current context of the current session.
47+
48+
:Usage:
49+
driver.current_context
50+
"""
51+
return self.execute(Command.GET_CURRENT_CONTEXT)['value']
52+
53+
def _addCommands(self):
54+
self.command_executor._commands[Command.CONTEXTS] = \
55+
('GET', '/session/$sessionId/contexts')
56+
self.command_executor._commands[Command.GET_CURRENT_CONTEXT] = \
57+
('GET', '/session/$sessionId/context')
58+
self.command_executor._commands[Command.SWITCH_TO_CONTEXT] = \
59+
('POST', '/session/$sessionId/context')

0 commit comments

Comments
 (0)