Skip to content

Commit a9276b7

Browse files
committed
add more code
1 parent d869172 commit a9276b7

File tree

6 files changed

+95
-152
lines changed

6 files changed

+95
-152
lines changed

Pipfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ tox = "~=4.23"
1515
types-python-dateutil = "~=2.9"
1616

1717
[packages]
18-
selenium = "~=4.25"
18+
selenium = "~=4.26"
1919
typing-extensions = "~=4.12.2"

appium/webdriver/appium_connection.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import uuid
1616
from typing import TYPE_CHECKING, Any, Dict, Optional
1717

18+
from selenium.webdriver.remote.client_config import ClientConfig
1819
from selenium.webdriver.remote.remote_connection import RemoteConnection
1920

2021
from appium.common.helper import library_version
@@ -31,6 +32,21 @@ class AppiumConnection(RemoteConnection):
3132

3233
RemoteConnection.user_agent = f'{PREFIX_HEADER}{library_version()} ({RemoteConnection.user_agent})'
3334

35+
def __init__(
36+
self,
37+
remote_server_addr: Optional[str] = None,
38+
keep_alive: Optional[bool] = True,
39+
init_args_for_pool_manager: Optional[dict] = None,
40+
client_config: Optional[ClientConfig] = None,
41+
):
42+
if client_config is None:
43+
client_config = ClientConfig(remote_server_addr=remote_server_addr)
44+
client_config.keep_alive = keep_alive
45+
if init_args_for_pool_manager is not None:
46+
client_config.init_args_for_pool_manager = init_args_for_pool_manager
47+
48+
super().__init__(client_config=client_config)
49+
3450
@classmethod
3551
def get_remote_connection_headers(cls, parsed_url: 'ParseResult', keep_alive: bool = True) -> Dict[str, Any]:
3652
"""Override get_remote_connection_headers in RemoteConnection"""

appium/webdriver/webdriver.py

Lines changed: 14 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
WebDriverException,
2323
)
2424
from selenium.webdriver.common.by import By
25+
from selenium.webdriver.remote.client_config import ClientConfig
2526
from selenium.webdriver.remote.command import Command as RemoteCommand
2627
from selenium.webdriver.remote.remote_connection import RemoteConnection
2728
from typing_extensions import Self
@@ -62,6 +63,11 @@
6263
from .webelement import WebElement as MobileWebElement
6364

6465

66+
class AppiumLocatorConverter:
67+
def convert(self, by, value):
68+
return (by, value)
69+
70+
6571
class ExtensionBase:
6672
"""
6773
Used to define an extension command as driver's methods.
@@ -200,32 +206,28 @@ class WebDriver(
200206
Sms,
201207
SystemBars,
202208
):
203-
def __init__(
209+
def __init__( # noqa: PLR0913
204210
self,
205211
command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444/wd/hub',
206212
keep_alive: bool = True,
207213
direct_connection: bool = True,
208214
extensions: Optional[List['WebDriver']] = None,
209215
strict_ssl: bool = True,
210216
options: Union[AppiumOptions, List[AppiumOptions], None] = None,
217+
client_config: Optional[ClientConfig] = None,
211218
):
212-
if strict_ssl is False:
213-
# noinspection PyPackageRequirements
214-
import urllib3
215-
216-
# noinspection PyPackageRequirements
217-
import urllib3.exceptions
218-
219-
# noinspection PyUnresolvedReferences
220-
AppiumConnection.set_certificate_bundle_path(None)
221-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
222-
223219
if isinstance(command_executor, str):
224220
command_executor = AppiumConnection(command_executor, keep_alive=keep_alive)
225221

222+
if client_config is None:
223+
client_config = ClientConfig(remote_server_addr=command_executor, ignore_certificates=not strict_ssl)
224+
226225
super().__init__(
227226
command_executor=command_executor,
228227
options=options,
228+
locator_converter=AppiumLocatorConverter(),
229+
web_element_cls=MobileWebElement,
230+
client_config=client_config,
229231
)
230232

231233
if hasattr(self, 'command_executor'):
@@ -346,72 +348,6 @@ def get_status(self) -> Dict:
346348
"""
347349
return self.execute(Command.GET_STATUS)['value']
348350

349-
def find_element(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None) -> MobileWebElement:
350-
"""
351-
Find an element given a AppiumBy strategy and locator
352-
353-
Args:
354-
by: The strategy
355-
value: The locator
356-
357-
Usage:
358-
driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='accessibility_id')
359-
360-
Returns:
361-
`appium.webdriver.webelement.WebElement`: The found element
362-
363-
"""
364-
# We prefer to patch locators in the client code
365-
# Checking current context every time a locator is accessed could significantly slow down tests
366-
# Check https://github.com/appium/python-client/pull/724 before submitting any issue
367-
# if by == By.ID:
368-
# by = By.CSS_SELECTOR
369-
# value = '[id="%s"]' % value
370-
# elif by == By.TAG_NAME:
371-
# by = By.CSS_SELECTOR
372-
# elif by == By.CLASS_NAME:
373-
# by = By.CSS_SELECTOR
374-
# value = ".%s" % value
375-
# elif by == By.NAME:
376-
# by = By.CSS_SELECTOR
377-
# value = '[name="%s"]' % value
378-
379-
return self.execute(RemoteCommand.FIND_ELEMENT, {'using': by, 'value': value})['value']
380-
381-
def find_elements(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None) -> Union[List[MobileWebElement], List]:
382-
"""
383-
Find elements given a AppiumBy strategy and locator
384-
385-
Args:
386-
by: The strategy
387-
value: The locator
388-
389-
Usage:
390-
driver.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value='accessibility_id')
391-
392-
Returns:
393-
:obj:`list` of :obj:`appium.webdriver.webelement.WebElement`: The found elements
394-
"""
395-
# We prefer to patch locators in the client code
396-
# Checking current context every time a locator is accessed could significantly slow down tests
397-
# Check https://github.com/appium/python-client/pull/724 before submitting any issue
398-
# if by == By.ID:
399-
# by = By.CSS_SELECTOR
400-
# value = '[id="%s"]' % value
401-
# elif by == By.TAG_NAME:
402-
# by = By.CSS_SELECTOR
403-
# elif by == By.CLASS_NAME:
404-
# by = By.CSS_SELECTOR
405-
# value = ".%s" % value
406-
# elif by == By.NAME:
407-
# by = By.CSS_SELECTOR
408-
# value = '[name="%s"]' % value
409-
410-
# Return empty list if driver returns null
411-
# See https://github.com/SeleniumHQ/selenium/issues/4555
412-
413-
return self.execute(RemoteCommand.FIND_ELEMENTS, {'using': by, 'value': value})['value'] or []
414-
415351
def create_web_element(self, element_id: Union[int, str]) -> MobileWebElement:
416352
"""Creates a web element with the specified element_id.
417353

appium/webdriver/webelement.py

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Callable, Dict, List, Optional, Union
15+
from typing import Callable, Dict, Optional, Union
1616

1717
from selenium.webdriver.common.utils import keys_to_typing
1818
from selenium.webdriver.remote.command import Command as RemoteCommand
1919
from selenium.webdriver.remote.webelement import WebElement as SeleniumWebElement
2020
from typing_extensions import Self
2121

22-
from appium.webdriver.common.appiumby import AppiumBy
23-
2422
from .mobilecommand import MobileCommand as Command
2523

2624

@@ -80,70 +78,6 @@ def is_displayed(self) -> bool:
8078
"""
8179
return self._execute(Command.IS_ELEMENT_DISPLAYED)['value']
8280

83-
def find_element(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None) -> 'WebElement':
84-
"""Find an element given a AppiumBy strategy and locator
85-
86-
Override for Appium
87-
88-
Prefer the find_element_by_* methods when possible.
89-
90-
Args:
91-
by: The strategy
92-
value: The locator
93-
94-
Usage:
95-
element = element.find_element(AppiumBy.ID, 'foo')
96-
97-
Returns:
98-
`appium.webdriver.webelement.WebElement`
99-
"""
100-
# We prefer to patch locators in the client code
101-
# Checking current context every time a locator is accessed could significantly slow down tests
102-
# Check https://github.com/appium/python-client/pull/724 before submitting any issue
103-
# if by == By.ID:
104-
# by = By.CSS_SELECTOR
105-
# value = '[id="%s"]' % value
106-
# elif by == By.TAG_NAME:
107-
# by = By.CSS_SELECTOR
108-
# elif by == By.CLASS_NAME:
109-
# by = By.CSS_SELECTOR
110-
# value = ".%s" % value
111-
# elif by == By.NAME:
112-
# by = By.CSS_SELECTOR
113-
# value = '[name="%s"]' % value
114-
115-
return self._execute(RemoteCommand.FIND_CHILD_ELEMENT, {'using': by, 'value': value})['value']
116-
117-
def find_elements(self, by: str = AppiumBy.ID, value: Union[str, Dict, None] = None) -> List['WebElement']:
118-
"""Find elements given a AppiumBy strategy and locator
119-
120-
Args:
121-
by: The strategy
122-
value: The locator
123-
124-
Usage:
125-
element = element.find_elements(AppiumBy.CLASS_NAME, 'foo')
126-
127-
Returns:
128-
:obj:`list` of :obj:`appium.webdriver.webelement.WebElement`
129-
"""
130-
# We prefer to patch locators in the client code
131-
# Checking current context every time a locator is accessed could significantly slow down tests
132-
# Check https://github.com/appium/python-client/pull/724 before submitting any issue
133-
# if by == By.ID:
134-
# by = By.CSS_SELECTOR
135-
# value = '[id="%s"]' % value
136-
# elif by == By.TAG_NAME:
137-
# by = By.CSS_SELECTOR
138-
# elif by == By.CLASS_NAME:
139-
# by = By.CSS_SELECTOR
140-
# value = ".%s" % value
141-
# elif by == By.NAME:
142-
# by = By.CSS_SELECTOR
143-
# value = '[name="%s"]' % value
144-
145-
return self._execute(RemoteCommand.FIND_CHILD_ELEMENTS, {'using': by, 'value': value})['value']
146-
14781
def clear(self) -> Self:
14882
"""Clears text.
14983

test/unit/webdriver/search_context/android_test.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,62 @@
2222

2323

2424
class TestWebDriverAndroidSearchContext(object):
25+
@httpretty.activate
26+
def test_find_element_by_id(self):
27+
driver = android_w3c_driver()
28+
httpretty.register_uri(
29+
httpretty.POST,
30+
appium_command('/session/1234567890/element'),
31+
body='{"value": {"element-6066-11e4-a52e-4f735466cecf": "element-id"}}',
32+
)
33+
el = driver.find_element(
34+
by=AppiumBy.ID,
35+
value='id data',
36+
)
37+
38+
d = get_httpretty_request_body(httpretty.last_request())
39+
assert d['using'] == 'id'
40+
assert d['value'] == 'id data'
41+
assert isinstance(el, MobileWebElement)
42+
43+
@httpretty.activate
44+
def test_find_elements_by_id(self):
45+
driver = android_w3c_driver()
46+
httpretty.register_uri(
47+
httpretty.POST,
48+
appium_command('/session/1234567890/elements'),
49+
body='{"value": [{"element-6066-11e4-a52e-4f735466cecf": "element-id1"}, '
50+
'{"element-6066-11e4-a52e-4f735466cecf": "element-id2"}]}',
51+
)
52+
els = driver.find_elements(
53+
by=AppiumBy.ID,
54+
value='id data',
55+
)
56+
57+
d = get_httpretty_request_body(httpretty.last_request())
58+
assert d['using'] == 'id'
59+
assert d['value'] == 'id data'
60+
assert isinstance(els[0], MobileWebElement)
61+
62+
@httpretty.activate
63+
def test_find_child_element_by_id(self):
64+
driver = android_w3c_driver()
65+
element = MobileWebElement(driver, 'element_id')
66+
httpretty.register_uri(
67+
httpretty.POST,
68+
appium_command('/session/1234567890/element/element_id/element'),
69+
body='{"value": {"element-6066-11e4-a52e-4f735466cecf": "child-element-id"}}',
70+
)
71+
el = element.find_element(
72+
by=AppiumBy.ID,
73+
value='id data',
74+
)
75+
76+
d = get_httpretty_request_body(httpretty.last_request())
77+
assert d['using'] == 'id'
78+
assert d['value'] == 'id data'
79+
assert isinstance(el, MobileWebElement)
80+
2581
@httpretty.activate
2682
def test_find_element_by_android_data_matcher(self):
2783
driver = android_w3c_driver()

test/unit/webdriver/webdriver_test.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import urllib3
1919
from mock import patch
2020

21-
from appium import version as appium_version
2221
from appium import webdriver
2322
from appium.options.android import UiAutomator2Options
2423
from appium.webdriver.appium_connection import AppiumConnection
@@ -54,7 +53,8 @@ def test_create_session(self):
5453

5554
request = httpretty.HTTPretty.latest_requests[0]
5655
assert request.headers['content-type'] == 'application/json;charset=UTF-8'
57-
assert f'appium/{appium_version.version} (selenium' in request.headers['user-agent']
56+
assert request.headers['user-agent'].startswith('appium/')
57+
assert '(selenium/' in request.headers['user-agent']
5858

5959
request_json = json.loads(httpretty.HTTPretty.latest_requests[0].body.decode('utf-8'))
6060
assert request_json.get('capabilities') is not None
@@ -130,7 +130,7 @@ def test_create_session_register_uridirect(self):
130130
direct_connection=True,
131131
)
132132

133-
assert 'http://localhost2:4800/special/path/wd/hub' == driver.command_executor._url
133+
assert 'http://localhost2:4800/special/path/wd/hub' == driver.command_executor._client_config.remote_server_addr
134134
assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts
135135
assert isinstance(driver.command_executor, AppiumConnection)
136136

@@ -170,7 +170,7 @@ def test_create_session_register_uridirect_no_direct_connect_path(self):
170170
direct_connection=True,
171171
)
172172

173-
assert SERVER_URL_BASE == driver.command_executor._url
173+
assert SERVER_URL_BASE == driver.command_executor._client_config.remote_server_addr
174174
assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts
175175
assert isinstance(driver.command_executor, AppiumConnection)
176176

@@ -303,7 +303,8 @@ class CustomAppiumConnection(AppiumConnection):
303303

304304
request = httpretty.HTTPretty.latest_requests[0]
305305
assert request.headers['content-type'] == 'application/json;charset=UTF-8'
306-
assert f'appium/{appium_version.version} (selenium' in request.headers['user-agent']
306+
assert request.headers['user-agent'].startswith('appium/')
307+
assert '(selenium/' in request.headers['user-agent']
307308

308309
request_json = json.loads(httpretty.HTTPretty.latest_requests[0].body.decode('utf-8'))
309310
assert request_json.get('capabilities') is not None
@@ -347,7 +348,7 @@ class CustomAppiumConnection(AppiumConnection):
347348

348349
request = httpretty.HTTPretty.latest_requests[0]
349350
assert request.headers['content-type'] == 'application/json;charset=UTF-8'
350-
assert f'appium/{appium_version.version} (selenium' in request.headers['user-agent']
351+
assert request.headers['user-agent'] == 'appium/4.1.0 (selenium/4.26.0 (python mac))'
351352

352353
request_json = json.loads(httpretty.HTTPretty.latest_requests[0].body.decode('utf-8'))
353354
assert request_json.get('capabilities') is not None

0 commit comments

Comments
 (0)