pymobiledevice3 5.3.2__py3-none-any.whl → 6.0.0__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.
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/cli/webinspector.py +90 -60
- pymobiledevice3/services/web_protocol/automation_session.py +83 -77
- pymobiledevice3/services/web_protocol/driver.py +69 -68
- pymobiledevice3/services/web_protocol/element.py +54 -52
- pymobiledevice3/services/web_protocol/session_protocol.py +3 -2
- pymobiledevice3/services/webinspector.py +42 -67
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/METADATA +1 -1
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/RECORD +13 -13
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.3.2.dist-info → pymobiledevice3-6.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from dataclasses import asdict, dataclass
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from pymobiledevice3.services.web_protocol.automation_session import RESOURCES, Point, Rect, Size
|
|
4
5
|
from pymobiledevice3.services.web_protocol.element import WebElement
|
|
@@ -34,106 +35,106 @@ class WebDriver(SeleniumApi):
|
|
|
34
35
|
self.session = session
|
|
35
36
|
self.switch_to = SwitchTo(session)
|
|
36
37
|
|
|
37
|
-
def add_cookie(self, cookie: Cookie):
|
|
38
|
+
async def add_cookie(self, cookie: Cookie):
|
|
38
39
|
"""Adds a cookie to your current session."""
|
|
39
40
|
if isinstance(cookie, Cookie):
|
|
40
41
|
cookie = asdict(cookie)
|
|
41
|
-
self.session.add_single_cookie(cookie)
|
|
42
|
+
await self.session.add_single_cookie(cookie)
|
|
42
43
|
|
|
43
|
-
def back(self):
|
|
44
|
+
async def back(self):
|
|
44
45
|
"""Goes one step backward in the browser history."""
|
|
45
|
-
self.session.wait_for_navigation_to_complete()
|
|
46
|
-
self.session.go_back_in_browsing_context()
|
|
47
|
-
self.session.switch_to_browsing_context("")
|
|
46
|
+
await self.session.wait_for_navigation_to_complete()
|
|
47
|
+
await self.session.go_back_in_browsing_context()
|
|
48
|
+
await self.session.switch_to_browsing_context("")
|
|
48
49
|
|
|
49
|
-
def close(self):
|
|
50
|
+
async def close(self):
|
|
50
51
|
"""Closes the current window."""
|
|
51
|
-
self.session.close_window()
|
|
52
|
+
await self.session.close_window()
|
|
52
53
|
|
|
53
54
|
@property
|
|
54
|
-
def current_url(self):
|
|
55
|
+
async def current_url(self):
|
|
55
56
|
"""Gets the URL of the current page."""
|
|
56
|
-
self.session.wait_for_navigation_to_complete()
|
|
57
|
-
return self.session.get_browsing_context()["url"]
|
|
57
|
+
await self.session.wait_for_navigation_to_complete()
|
|
58
|
+
return (await self.session.get_browsing_context())["url"]
|
|
58
59
|
|
|
59
60
|
@property
|
|
60
|
-
def current_window_handle(self):
|
|
61
|
+
async def current_window_handle(self):
|
|
61
62
|
"""Returns the handle of the current window."""
|
|
62
|
-
return self.session.get_browsing_context()["handle"]
|
|
63
|
+
return (await self.session.get_browsing_context())["handle"]
|
|
63
64
|
|
|
64
|
-
def delete_all_cookies(self):
|
|
65
|
+
async def delete_all_cookies(self):
|
|
65
66
|
"""Delete all cookies in the scope of the session."""
|
|
66
|
-
self.session.delete_all_cookies()
|
|
67
|
+
await self.session.delete_all_cookies()
|
|
67
68
|
|
|
68
|
-
def delete_cookie(self, name: str):
|
|
69
|
+
async def delete_cookie(self, name: str):
|
|
69
70
|
"""Deletes a single cookie with the given name."""
|
|
70
|
-
self.session.delete_single_cookie(name)
|
|
71
|
+
await self.session.delete_single_cookie(name)
|
|
71
72
|
|
|
72
|
-
def execute_async_script(self, script: str, *args):
|
|
73
|
+
async def execute_async_script(self, script: str, *args):
|
|
73
74
|
"""
|
|
74
75
|
Asynchronously Executes JavaScript in the current window/frame.
|
|
75
76
|
:param script: The JavaScript to execute.
|
|
76
77
|
:param args: Any applicable arguments for your JavaScript.
|
|
77
78
|
"""
|
|
78
|
-
return self.session.execute_script(script, args, async_=True)
|
|
79
|
+
return await self.session.execute_script(script, args, async_=True)
|
|
79
80
|
|
|
80
|
-
def execute_script(self, script: str, *args):
|
|
81
|
+
async def execute_script(self, script: str, *args):
|
|
81
82
|
"""
|
|
82
83
|
Synchronously Executes JavaScript in the current window/frame.
|
|
83
84
|
:param script: The JavaScript to execute.
|
|
84
85
|
:param args: Any applicable arguments for your JavaScript.
|
|
85
86
|
"""
|
|
86
|
-
return self.session.execute_script(script, args)
|
|
87
|
+
return await self.session.execute_script(script, args)
|
|
87
88
|
|
|
88
|
-
def find_element(self, by=By.ID, value=None) -> WebElement:
|
|
89
|
+
async def find_element(self, by=By.ID, value=None) -> Optional[WebElement]:
|
|
89
90
|
"""Find an element given a By strategy and locator."""
|
|
90
|
-
elem = self.session.find_elements(by, value)
|
|
91
|
+
elem = await self.session.find_elements(by, value)
|
|
91
92
|
return None if elem is None else WebElement(self.session, elem)
|
|
92
93
|
|
|
93
|
-
def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
|
|
94
|
+
async def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
|
|
94
95
|
"""Find elements given a By strategy and locator."""
|
|
95
|
-
elements = self.session.find_elements(by, value, single=False)
|
|
96
|
+
elements = await self.session.find_elements(by, value, single=False)
|
|
96
97
|
return [WebElement(self.session, elem) for elem in elements]
|
|
97
98
|
|
|
98
|
-
def forward(self):
|
|
99
|
+
async def forward(self):
|
|
99
100
|
"""Goes one step forward in the browser history."""
|
|
100
|
-
self.session.wait_for_navigation_to_complete()
|
|
101
|
-
self.session.go_forward_in_browsing_context()
|
|
102
|
-
self.session.switch_to_browsing_context("")
|
|
101
|
+
await self.session.wait_for_navigation_to_complete()
|
|
102
|
+
await self.session.go_forward_in_browsing_context()
|
|
103
|
+
await self.session.switch_to_browsing_context("")
|
|
103
104
|
|
|
104
|
-
def fullscreen_window(self):
|
|
105
|
+
async def fullscreen_window(self):
|
|
105
106
|
"""Invokes the window manager-specific 'full screen' operation."""
|
|
106
|
-
self.session.evaluate_js_function(ENTER_FULLSCREEN, implicit_callback=True)
|
|
107
|
+
await self.session.evaluate_js_function(ENTER_FULLSCREEN, implicit_callback=True)
|
|
107
108
|
|
|
108
|
-
def get(self, url: str):
|
|
109
|
+
async def get(self, url: str):
|
|
109
110
|
"""Loads a web page in the current browser session."""
|
|
110
|
-
self.session.wait_for_navigation_to_complete()
|
|
111
|
-
self.session.navigate_broswing_context(url)
|
|
112
|
-
self.session.switch_to_browsing_context("")
|
|
111
|
+
await self.session.wait_for_navigation_to_complete()
|
|
112
|
+
await self.session.navigate_broswing_context(url)
|
|
113
|
+
await self.session.switch_to_browsing_context("")
|
|
113
114
|
|
|
114
|
-
def get_cookie(self, name: str) -> Cookie:
|
|
115
|
+
async def get_cookie(self, name: str) -> Cookie:
|
|
115
116
|
"""Get a single cookie by name. Returns the cookie if found, None if not."""
|
|
116
|
-
for cookie in self.get_cookies():
|
|
117
|
+
for cookie in await self.get_cookies():
|
|
117
118
|
if cookie.name == name:
|
|
118
119
|
return cookie
|
|
119
120
|
|
|
120
|
-
def get_cookies(self) -> list[Cookie]:
|
|
121
|
+
async def get_cookies(self) -> list[Cookie]:
|
|
121
122
|
"""Returns cookies visible in the current session."""
|
|
122
|
-
return list(map(Cookie.from_automation, self.session.get_all_cookies()))
|
|
123
|
+
return list(map(Cookie.from_automation, await self.session.get_all_cookies()))
|
|
123
124
|
|
|
124
125
|
@property
|
|
125
|
-
def screenshot_as_base64(self) -> str:
|
|
126
|
+
async def screenshot_as_base64(self) -> str:
|
|
126
127
|
"""Gets the screenshot of the current window as a base64 encoded string."""
|
|
127
|
-
return self.session.screenshot_as_base64()
|
|
128
|
+
return await self.session.screenshot_as_base64()
|
|
128
129
|
|
|
129
130
|
def get_window_position(self) -> Point:
|
|
130
131
|
"""Gets the x,y position of the current window."""
|
|
131
132
|
rect = self.get_window_rect()
|
|
132
133
|
return Point(x=rect.x, y=rect.y)
|
|
133
134
|
|
|
134
|
-
def get_window_rect(self) -> Rect:
|
|
135
|
+
async def get_window_rect(self) -> Rect:
|
|
135
136
|
"""Gets the x, y coordinates of the window as well as height and width of the current window."""
|
|
136
|
-
context = self.session.get_browsing_context()
|
|
137
|
+
context = await self.session.get_browsing_context()
|
|
137
138
|
return Rect(
|
|
138
139
|
context["windowOrigin"]["x"],
|
|
139
140
|
context["windowOrigin"]["y"],
|
|
@@ -141,57 +142,57 @@ class WebDriver(SeleniumApi):
|
|
|
141
142
|
context["windowSize"]["height"],
|
|
142
143
|
)
|
|
143
144
|
|
|
144
|
-
def get_window_size(self) -> Size:
|
|
145
|
+
async def get_window_size(self) -> Size:
|
|
145
146
|
"""Gets the width and height of the current window."""
|
|
146
|
-
rect = self.get_window_rect()
|
|
147
|
+
rect = await self.get_window_rect()
|
|
147
148
|
return Size(height=rect.height, width=rect.width)
|
|
148
149
|
|
|
149
150
|
def implicitly_wait(self, time_to_wait):
|
|
150
151
|
"""Sets a sticky timeout to implicitly wait for an element to be found, or a command to complete."""
|
|
151
152
|
self.session.implicit_wait_timeout = time_to_wait * 1000
|
|
152
153
|
|
|
153
|
-
def maximize_window(self):
|
|
154
|
+
async def maximize_window(self):
|
|
154
155
|
"""Maximizes the current window."""
|
|
155
|
-
self.session.maximize_window()
|
|
156
|
+
await self.session.maximize_window()
|
|
156
157
|
|
|
157
|
-
def minimize_window(self):
|
|
158
|
+
async def minimize_window(self):
|
|
158
159
|
"""Invokes the window manager-specific 'minimize' operation."""
|
|
159
|
-
self.session.hide_window()
|
|
160
|
+
await self.session.hide_window()
|
|
160
161
|
|
|
161
162
|
@property
|
|
162
|
-
def page_source(self) -> str:
|
|
163
|
+
async def page_source(self) -> str:
|
|
163
164
|
"""Gets the source of the current page."""
|
|
164
|
-
return self.session.evaluate_js_function("function() { return document.documentElement.outerHTML; }")
|
|
165
|
+
return await self.session.evaluate_js_function("function() { return document.documentElement.outerHTML; }")
|
|
165
166
|
|
|
166
|
-
def refresh(self):
|
|
167
|
+
async def refresh(self):
|
|
167
168
|
"""Refreshes the current page."""
|
|
168
|
-
self.session.wait_for_navigation_to_complete()
|
|
169
|
-
self.session.reload_browsing_context()
|
|
170
|
-
self.session.switch_to_browsing_context("")
|
|
169
|
+
await self.session.wait_for_navigation_to_complete()
|
|
170
|
+
await self.session.reload_browsing_context()
|
|
171
|
+
await self.session.switch_to_browsing_context("")
|
|
171
172
|
|
|
172
|
-
def set_window_position(self, x, y):
|
|
173
|
+
async def set_window_position(self, x, y):
|
|
173
174
|
"""Sets the x,y position of the current window."""
|
|
174
|
-
self.set_window_rect(x=int(x, 0), y=int(y, 0))
|
|
175
|
+
await self.set_window_rect(x=int(x, 0), y=int(y, 0))
|
|
175
176
|
|
|
176
|
-
def set_window_rect(self, x=None, y=None, width=None, height=None):
|
|
177
|
+
async def set_window_rect(self, x=None, y=None, width=None, height=None):
|
|
177
178
|
"""Sets the x, y coordinates of the window as well as height and width of the current window."""
|
|
178
|
-
self.session.set_window_frame(x, y, width, height)
|
|
179
|
+
await self.session.set_window_frame(x, y, width, height)
|
|
179
180
|
|
|
180
|
-
def set_window_size(self, width, height):
|
|
181
|
+
async def set_window_size(self, width, height):
|
|
181
182
|
"""Sets the width and height of the current window."""
|
|
182
|
-
self.set_window_rect(width=int(width, 0), height=int(height, 0))
|
|
183
|
+
await self.set_window_rect(width=int(width, 0), height=int(height, 0))
|
|
183
184
|
|
|
184
|
-
def start_session(self):
|
|
185
|
+
async def start_session(self):
|
|
185
186
|
"""Creates a new session."""
|
|
186
|
-
self.session.start_session()
|
|
187
|
+
await self.session.start_session()
|
|
187
188
|
|
|
188
189
|
@property
|
|
189
|
-
def title(self) -> str:
|
|
190
|
+
async def title(self) -> str:
|
|
190
191
|
"""Returns the title of the current page."""
|
|
191
|
-
self.session.wait_for_navigation_to_complete()
|
|
192
|
-
return self.session.evaluate_js_function("function() { return document.title; }")
|
|
192
|
+
await self.session.wait_for_navigation_to_complete()
|
|
193
|
+
return await self.session.evaluate_js_function("function() { return document.title; }")
|
|
193
194
|
|
|
194
195
|
@property
|
|
195
|
-
def window_handles(self) -> list[str]:
|
|
196
|
+
async def window_handles(self) -> list[str]:
|
|
196
197
|
"""Returns the handles of all windows within the current session."""
|
|
197
|
-
return self.session.get_window_handles()
|
|
198
|
+
return await self.session.get_window_handles()
|
|
@@ -31,89 +31,91 @@ class WebElement(SeleniumApi):
|
|
|
31
31
|
self.id_ = id_
|
|
32
32
|
self.node_id = id_[f"session-node-{self.session.id_}"]
|
|
33
33
|
|
|
34
|
-
def clear(self):
|
|
34
|
+
async def clear(self):
|
|
35
35
|
"""Clears the text if it's a text entry element."""
|
|
36
36
|
if not self.is_editable():
|
|
37
37
|
return
|
|
38
|
-
rect, center, _is_obscured = self._compute_layout()
|
|
38
|
+
rect, center, _is_obscured = await self._compute_layout()
|
|
39
39
|
if rect is None or center is None:
|
|
40
40
|
return
|
|
41
|
-
self._evaluate_js_function(ELEMENT_CLEAR)
|
|
41
|
+
await self._evaluate_js_function(ELEMENT_CLEAR)
|
|
42
42
|
|
|
43
|
-
def click(self):
|
|
43
|
+
async def click(self):
|
|
44
44
|
"""Clicks the element."""
|
|
45
|
-
rect, center, is_obscured = self._compute_layout(use_viewport=True)
|
|
45
|
+
rect, center, is_obscured = await self._compute_layout(use_viewport=True)
|
|
46
46
|
if rect is None or is_obscured or center is None:
|
|
47
47
|
return
|
|
48
48
|
if self.tag_name == "option":
|
|
49
|
-
self._select_option_element()
|
|
49
|
+
await self._select_option_element()
|
|
50
50
|
else:
|
|
51
|
-
self.session.perform_mouse_interaction(
|
|
51
|
+
await self.session.perform_mouse_interaction(
|
|
52
|
+
center.x, center.y, MouseButton.LEFT, MouseInteraction.SINGLE_CLICK
|
|
53
|
+
)
|
|
52
54
|
|
|
53
|
-
def find_element(self, by=By.ID, value=None):
|
|
55
|
+
async def find_element(self, by=By.ID, value=None):
|
|
54
56
|
"""Find an element given a By strategy and locator."""
|
|
55
57
|
elem = self.session.find_elements(by, value, root=self.id_)
|
|
56
58
|
return None if elem is None else WebElement(self.session, elem)
|
|
57
59
|
|
|
58
|
-
def find_elements(self, by=By.ID, value=None):
|
|
60
|
+
async def find_elements(self, by=By.ID, value=None):
|
|
59
61
|
"""Find elements given a By strategy and locator."""
|
|
60
|
-
elements = self.session.find_elements(by, value, single=False, root=self.id_)
|
|
62
|
+
elements = await self.session.find_elements(by, value, single=False, root=self.id_)
|
|
61
63
|
return [WebElement(self.session, elem) for elem in elements]
|
|
62
64
|
|
|
63
|
-
def get_attribute(self, name: str) -> str:
|
|
65
|
+
async def get_attribute(self, name: str) -> str:
|
|
64
66
|
"""Gets the given attribute or property of the element."""
|
|
65
|
-
return self.session.execute_script(f"return ({GET_ATTRIBUTE}).apply(null, arguments);", self.id_, name)
|
|
67
|
+
return await self.session.execute_script(f"return ({GET_ATTRIBUTE}).apply(null, arguments);", self.id_, name)
|
|
66
68
|
|
|
67
|
-
def get_dom_attribute(self, name: str) -> str:
|
|
69
|
+
async def get_dom_attribute(self, name: str) -> str:
|
|
68
70
|
"""Gets the given attribute of the element."""
|
|
69
|
-
return self._evaluate_js_function(ELEMENT_ATTRIBUTE, name)
|
|
71
|
+
return await self._evaluate_js_function(ELEMENT_ATTRIBUTE, name)
|
|
70
72
|
|
|
71
|
-
def get_property(self, name: str) -> str:
|
|
73
|
+
async def get_property(self, name: str) -> str:
|
|
72
74
|
"""Gets the given property of the element."""
|
|
73
|
-
return self._evaluate_js_function(f"function(element) {{ return element.{name}; }}")
|
|
75
|
+
return await self._evaluate_js_function(f"function(element) {{ return element.{name}; }}")
|
|
74
76
|
|
|
75
|
-
def is_displayed(self) -> bool:
|
|
77
|
+
async def is_displayed(self) -> bool:
|
|
76
78
|
"""Whether the element is visible to a user."""
|
|
77
|
-
return self.session.execute_script(f"return ({IS_DISPLAYED}).apply(null, arguments);", self.id_)
|
|
79
|
+
return await self.session.execute_script(f"return ({IS_DISPLAYED}).apply(null, arguments);", self.id_)
|
|
78
80
|
|
|
79
|
-
def is_enabled(self) -> bool:
|
|
81
|
+
async def is_enabled(self) -> bool:
|
|
80
82
|
"""Returns whether the element is enabled."""
|
|
81
|
-
return self._evaluate_js_function(IS_ENABLED)
|
|
83
|
+
return await self._evaluate_js_function(IS_ENABLED)
|
|
82
84
|
|
|
83
|
-
def is_selected(self) -> bool:
|
|
85
|
+
async def is_selected(self) -> bool:
|
|
84
86
|
"""Returns whether the element is selected. Can be used to check if a checkbox or radio button is selected."""
|
|
85
|
-
return bool(self.get_dom_attribute("selected"))
|
|
87
|
+
return bool(await self.get_dom_attribute("selected"))
|
|
86
88
|
|
|
87
89
|
@property
|
|
88
|
-
def location(self) -> Point:
|
|
90
|
+
async def location(self) -> Point:
|
|
89
91
|
"""The location of the element in the renderable canvas."""
|
|
90
|
-
rect = self.rect
|
|
92
|
+
rect = await self.rect
|
|
91
93
|
return Point(x=rect.x, y=rect.y)
|
|
92
94
|
|
|
93
95
|
@property
|
|
94
|
-
def location_once_scrolled_into_view(self) -> Point:
|
|
96
|
+
async def location_once_scrolled_into_view(self) -> Point:
|
|
95
97
|
"""Returns the top lefthand corner location on the screen, or ``None`` if the element is not visible."""
|
|
96
|
-
rect = self.session.execute_script(
|
|
98
|
+
rect = await self.session.execute_script(
|
|
97
99
|
"arguments[0].scrollIntoView(true); return arguments[0].getBoundingClientRect(); ", self.id_
|
|
98
100
|
)
|
|
99
101
|
return Point(x=round(rect["x"]), y=round(rect["y"]))
|
|
100
102
|
|
|
101
103
|
@property
|
|
102
|
-
def rect(self) -> Rect:
|
|
104
|
+
async def rect(self) -> Rect:
|
|
103
105
|
"""The size and location of the element."""
|
|
104
|
-
return self._compute_layout(scroll_if_needed=False)[0]
|
|
106
|
+
return await self._compute_layout(scroll_if_needed=False)[0]
|
|
105
107
|
|
|
106
108
|
@property
|
|
107
|
-
def screenshot_as_base64(self) -> str:
|
|
109
|
+
async def screenshot_as_base64(self) -> str:
|
|
108
110
|
"""Gets the screenshot of the current element as a base64 encoded string."""
|
|
109
|
-
return self.session.screenshot_as_base64(scroll=True, node_id=self.node_id)
|
|
111
|
+
return await self.session.screenshot_as_base64(scroll=True, node_id=self.node_id)
|
|
110
112
|
|
|
111
|
-
def send_keys(self, value):
|
|
113
|
+
async def send_keys(self, value):
|
|
112
114
|
"""
|
|
113
115
|
Simulates typing into the element.
|
|
114
116
|
:param value: A string for typing, or setting form fields.
|
|
115
117
|
"""
|
|
116
|
-
self._evaluate_js_function(FOCUS)
|
|
118
|
+
await self._evaluate_js_function(FOCUS)
|
|
117
119
|
interactions = []
|
|
118
120
|
sticky_modifier = set()
|
|
119
121
|
for key in value:
|
|
@@ -132,15 +134,15 @@ class WebElement(SeleniumApi):
|
|
|
132
134
|
interactions.append({"type": KeyboardInteractionType.INSERT_BY_KEY, "text": key})
|
|
133
135
|
for modifier in sticky_modifier:
|
|
134
136
|
interactions.append({"type": KeyboardInteractionType.KEY_RELEASE, "key": MODIFIER_TO_KEY[modifier]})
|
|
135
|
-
self.session.perform_keyboard_interactions(interactions)
|
|
137
|
+
await self.session.perform_keyboard_interactions(interactions)
|
|
136
138
|
|
|
137
139
|
@property
|
|
138
|
-
def size(self) -> Size:
|
|
140
|
+
async def size(self) -> Size:
|
|
139
141
|
"""The size of the element."""
|
|
140
|
-
rect = self.rect
|
|
142
|
+
rect = await self.rect
|
|
141
143
|
return Size(height=rect.height, width=rect.width)
|
|
142
144
|
|
|
143
|
-
def submit(self):
|
|
145
|
+
async def submit(self):
|
|
144
146
|
"""Submits a form."""
|
|
145
147
|
form = self.find_element(By.XPATH, "./ancestor-or-self::form")
|
|
146
148
|
submit_code = (
|
|
@@ -148,31 +150,31 @@ class WebElement(SeleniumApi):
|
|
|
148
150
|
"e.initEvent('submit', true, true);"
|
|
149
151
|
"if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }"
|
|
150
152
|
)
|
|
151
|
-
self.session.execute_script(submit_code, form.id_)
|
|
153
|
+
await self.session.execute_script(submit_code, form.id_)
|
|
152
154
|
|
|
153
155
|
@property
|
|
154
|
-
def tag_name(self) -> str:
|
|
156
|
+
async def tag_name(self) -> str:
|
|
155
157
|
"""This element's ``tagName`` property."""
|
|
156
|
-
return self._evaluate_js_function("function(element) { return element.tagName.toLowerCase() }")
|
|
158
|
+
return await self._evaluate_js_function("function(element) { return element.tagName.toLowerCase() }")
|
|
157
159
|
|
|
158
160
|
@property
|
|
159
|
-
def text(self) -> str:
|
|
161
|
+
async def text(self) -> str:
|
|
160
162
|
"""The text of the element."""
|
|
161
|
-
return self._evaluate_js_function(
|
|
163
|
+
return await self._evaluate_js_function(
|
|
162
164
|
'function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, "") }'
|
|
163
165
|
)
|
|
164
166
|
|
|
165
|
-
def touch(self):
|
|
167
|
+
async def touch(self):
|
|
166
168
|
"""Simulate touch interaction on the element."""
|
|
167
|
-
_rect, center, _is_obscured = self._compute_layout(use_viewport=True)
|
|
168
|
-
self.session.perform_interaction_sequence(
|
|
169
|
+
_rect, center, _is_obscured = await self._compute_layout(use_viewport=True)
|
|
170
|
+
await self.session.perform_interaction_sequence(
|
|
169
171
|
[{"sourceId": self.session.id_, "sourceType": "Touch"}],
|
|
170
172
|
[{"states": [{"sourceId": self.session.id_, "location": {"x": center.x, "y": center.y}}]}],
|
|
171
173
|
)
|
|
172
174
|
|
|
173
|
-
def value_of_css_property(self, property_name) -> str:
|
|
175
|
+
async def value_of_css_property(self, property_name) -> str:
|
|
174
176
|
"""The value of a CSS property."""
|
|
175
|
-
return self._evaluate_js_function(
|
|
177
|
+
return await self._evaluate_js_function(
|
|
176
178
|
"function(element) {"
|
|
177
179
|
f' return document.defaultView.getComputedStyle(element).getPropertyValue("{property_name}"); '
|
|
178
180
|
"}"
|
|
@@ -182,9 +184,9 @@ class WebElement(SeleniumApi):
|
|
|
182
184
|
"""Returns whether the element is editable."""
|
|
183
185
|
return self._evaluate_js_function(IS_EDITABLE)
|
|
184
186
|
|
|
185
|
-
def _compute_layout(self, scroll_if_needed=True, use_viewport=False):
|
|
187
|
+
async def _compute_layout(self, scroll_if_needed=True, use_viewport=False):
|
|
186
188
|
try:
|
|
187
|
-
result = self.session.compute_element_layout(
|
|
189
|
+
result = await self.session.compute_element_layout(
|
|
188
190
|
self.node_id, scroll_if_needed, "LayoutViewport" if use_viewport else "Page"
|
|
189
191
|
)
|
|
190
192
|
except WirError:
|
|
@@ -196,11 +198,11 @@ class WebElement(SeleniumApi):
|
|
|
196
198
|
center = Point(x=result["inViewCenterPoint"]["x"], y=result["inViewCenterPoint"]["y"])
|
|
197
199
|
return rect, center, result["isObscured"]
|
|
198
200
|
|
|
199
|
-
def _select_option_element(self):
|
|
200
|
-
self.session.select_option_element(self.node_id)
|
|
201
|
+
async def _select_option_element(self):
|
|
202
|
+
await self.session.select_option_element(self.node_id)
|
|
201
203
|
|
|
202
|
-
def _evaluate_js_function(self, function, *args):
|
|
203
|
-
return self.session.evaluate_js_function(function, self.id_, *args)
|
|
204
|
+
async def _evaluate_js_function(self, function, *args):
|
|
205
|
+
return await self.session.evaluate_js_function(function, self.id_, *args)
|
|
204
206
|
|
|
205
207
|
def __eq__(self, other):
|
|
206
208
|
return self.id_ == other.id_
|
|
@@ -37,6 +37,7 @@ class SessionProtocol:
|
|
|
37
37
|
return response["result"]
|
|
38
38
|
elif "error" in response:
|
|
39
39
|
raise WirError(response["error"]["message"])
|
|
40
|
+
raise WirError(f"Unknown response: {response}")
|
|
40
41
|
|
|
41
42
|
async def send_receive(self, method, wait_for_response=True, **kwargs):
|
|
42
43
|
wir_id = await self.send_command(method, **kwargs)
|
|
@@ -50,8 +51,8 @@ class SessionProtocol:
|
|
|
50
51
|
await asyncio.sleep(0)
|
|
51
52
|
return self.inspector.wir_message_results.pop(id_)
|
|
52
53
|
|
|
53
|
-
def sync_send_receive(self, method, wait_for_response=True, **kwargs):
|
|
54
|
-
return self.
|
|
54
|
+
async def sync_send_receive(self, method, wait_for_response=True, **kwargs):
|
|
55
|
+
return await self.send_receive(method, wait_for_response, **kwargs)
|
|
55
56
|
|
|
56
57
|
def __getattr__(self, item):
|
|
57
58
|
return partial(self.sync_send_receive, method=item)
|