Skip to content

Commit c7311e8

Browse files
cp
1 parent 5ed63ed commit c7311e8

File tree

7 files changed

+307
-96
lines changed

7 files changed

+307
-96
lines changed

py/selenium/common/exceptions.py

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"""Exceptions that may happen in all the webdriver code."""
1818

1919
from collections.abc import Sequence
20-
from typing import Any
20+
from typing import Any, Optional, Union
2121

2222
SUPPORT_MSG = "For documentation on this error, please visit:"
2323
ERROR_URL = "https://www.selenium.dev/documentation/webdriver/troubleshooting/errors"
@@ -27,7 +27,10 @@ class WebDriverException(Exception):
2727
"""Base webdriver exception."""
2828

2929
def __init__(
30-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
30+
self,
31+
msg: Optional[Any] = None,
32+
screen: Optional[str] = None,
33+
stacktrace: Optional[Sequence[str]] = None,
3134
) -> None:
3235
super().__init__()
3336
self.msg = msg
@@ -73,7 +76,10 @@ class NoSuchElementException(WebDriverException):
7376
"""
7477

7578
def __init__(
76-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
79+
self,
80+
msg: Optional[Any] = None,
81+
screen: Optional[str] = None,
82+
stacktrace: Optional[Sequence[str]] = None,
7783
) -> None:
7884
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#nosuchelementexception"
7985

@@ -111,9 +117,14 @@ class StaleElementReferenceException(WebDriverException):
111117
"""
112118

113119
def __init__(
114-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
120+
self,
121+
msg: Optional[Any] = None,
122+
screen: Optional[str] = None,
123+
stacktrace: Optional[Sequence[str]] = None,
115124
) -> None:
116-
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#staleelementreferenceexception"
125+
with_support = (
126+
f"{msg}; {SUPPORT_MSG} {ERROR_URL}#staleelementreferenceexception"
127+
)
117128

118129
super().__init__(with_support, screen, stacktrace)
119130

@@ -134,10 +145,10 @@ class UnexpectedAlertPresentException(WebDriverException):
134145

135146
def __init__(
136147
self,
137-
msg: Any | None = None,
138-
screen: str | None = None,
139-
stacktrace: Sequence[str] | None = None,
140-
alert_text: str | None = None,
148+
msg: Optional[Any] = None,
149+
screen: Optional[str] = None,
150+
stacktrace: Optional[Sequence[str]] = None,
151+
alert_text: Optional[str] = None,
141152
) -> None:
142153
super().__init__(msg, screen, stacktrace)
143154
self.alert_text = alert_text
@@ -161,7 +172,10 @@ class ElementNotVisibleException(InvalidElementStateException):
161172
"""
162173

163174
def __init__(
164-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
175+
self,
176+
msg: Optional[Any] = None,
177+
screen: Optional[str] = None,
178+
stacktrace: Optional[Sequence[str]] = None,
165179
) -> None:
166180
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#elementnotvisibleexception"
167181

@@ -172,9 +186,14 @@ class ElementNotInteractableException(InvalidElementStateException):
172186
"""Thrown when element interactions will hit another element due to paint order."""
173187

174188
def __init__(
175-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
189+
self,
190+
msg: Optional[Any] = None,
191+
screen: Optional[str] = None,
192+
stacktrace: Optional[Sequence[str]] = None,
176193
) -> None:
177-
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#elementnotinteractableexception"
194+
with_support = (
195+
f"{msg}; {SUPPORT_MSG} {ERROR_URL}#elementnotinteractableexception"
196+
)
178197

179198
super().__init__(with_support, screen, stacktrace)
180199

@@ -213,7 +232,10 @@ class InvalidSelectorException(WebDriverException):
213232
"""
214233

215234
def __init__(
216-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
235+
self,
236+
msg: Optional[Any] = None,
237+
screen: Optional[str] = None,
238+
stacktrace: Optional[Sequence[str]] = None,
217239
) -> None:
218240
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#invalidselectorexception"
219241

@@ -252,9 +274,14 @@ class ElementClickInterceptedException(WebDriverException):
252274
"""Thrown when element click fails because another element obscures it."""
253275

254276
def __init__(
255-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
277+
self,
278+
msg: Optional[Any] = None,
279+
screen: Optional[str] = None,
280+
stacktrace: Optional[Sequence[str]] = None,
256281
) -> None:
257-
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#elementclickinterceptedexception"
282+
with_support = (
283+
f"{msg}; {SUPPORT_MSG} {ERROR_URL}#elementclickinterceptedexception"
284+
)
258285

259286
super().__init__(with_support, screen, stacktrace)
260287

@@ -271,7 +298,10 @@ class InvalidSessionIdException(WebDriverException):
271298
"""Thrown when the given session id is not in the list of active sessions."""
272299

273300
def __init__(
274-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
301+
self,
302+
msg: Optional[Any] = None,
303+
screen: Optional[str] = None,
304+
stacktrace: Optional[Sequence[str]] = None,
275305
) -> None:
276306
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#invalidsessionidexception"
277307

@@ -282,7 +312,10 @@ class SessionNotCreatedException(WebDriverException):
282312
"""A new session could not be created."""
283313

284314
def __init__(
285-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
315+
self,
316+
msg: Optional[Any] = None,
317+
screen: Optional[str] = None,
318+
stacktrace: Optional[Sequence[str]] = None,
286319
) -> None:
287320
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#sessionnotcreatedexception"
288321

@@ -297,7 +330,10 @@ class NoSuchDriverException(WebDriverException):
297330
"""Raised when driver is not specified and cannot be located."""
298331

299332
def __init__(
300-
self, msg: Any | None = None, screen: str | None = None, stacktrace: Sequence[str] | None = None
333+
self,
334+
msg: Optional[Any] = None,
335+
screen: Optional[str] = None,
336+
stacktrace: Optional[Sequence[str]] = None,
301337
) -> None:
302338
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}/driver_location"
303339

py/selenium/webdriver/common/bidi/browser.py

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
from dataclasses import dataclass
1414

1515

16+
class ClientWindowState:
17+
"""ClientWindowState enum."""
18+
19+
ACTIVE = "active"
20+
BACKGROUND = "background"
21+
FULLSCREEN = "fullscreen"
22+
MAXIMIZED = "maximized"
23+
MINIMIZED = "minimized"
24+
NORMAL = "normal"
25+
26+
1627
@dataclass
1728
class ClientWindowInfo:
1829
"""ClientWindowInfo type type."""
@@ -117,59 +128,99 @@ class Browser:
117128
def __init__(self, driver) -> None:
118129
self._driver = driver
119130

120-
def close(self) -> Generator[dict, dict, dict]:
131+
def close(self):
121132
"""Execute browser.close."""
122-
params = {
123-
}
133+
params = {}
124134
params = {k: v for k, v in params.items() if v is not None}
125-
return command_builder("browser.close", params)
126-
127-
def create_user_context(self, accept_insecure_certs: bool = None, proxy: Any = None, unhandled_prompt_behavior: Any = None) -> Generator[dict, dict, dict]:
128-
"""Execute browser.createUserContext."""
135+
cmd = command_builder("browser.close", params)
136+
return self._driver.execute(cmd)
137+
138+
def create_user_context(
139+
self,
140+
accept_insecure_certs: bool = None,
141+
proxy: Any = None,
142+
unhandled_prompt_behavior: Any = None,
143+
):
144+
"""Execute browser.createUserContext and return the user context ID."""
129145
params = {
130146
"acceptInsecureCerts": accept_insecure_certs,
131147
"proxy": proxy,
132148
"unhandledPromptBehavior": unhandled_prompt_behavior,
133149
}
134150
params = {k: v for k, v in params.items() if v is not None}
135-
return command_builder("browser.createUserContext", params)
151+
cmd = command_builder("browser.createUserContext", params)
152+
result = self._driver.execute(cmd)
153+
return result.get("userContext") if "userContext" in result else result
136154

137-
def get_client_windows(self) -> Generator[dict, dict, dict]:
138-
"""Execute browser.getClientWindows."""
139-
params = {
140-
}
155+
def get_client_windows(self):
156+
"""Execute browser.getClientWindows and return the client windows."""
157+
params = {}
141158
params = {k: v for k, v in params.items() if v is not None}
142-
return command_builder("browser.getClientWindows", params)
159+
cmd = command_builder("browser.getClientWindows", params)
160+
result = self._driver.execute(cmd)
161+
return result.get("clientWindows", []) if result else []
143162

144-
def get_user_contexts(self) -> Generator[dict, dict, dict]:
145-
"""Execute browser.getUserContexts."""
146-
params = {
147-
}
163+
def get_user_contexts(self):
164+
"""Execute browser.getUserContexts and return the user contexts."""
165+
params = {}
148166
params = {k: v for k, v in params.items() if v is not None}
149-
return command_builder("browser.getUserContexts", params)
167+
cmd = command_builder("browser.getUserContexts", params)
168+
result = self._driver.execute(cmd)
169+
return result.get("userContexts", []) if result else []
150170

151-
def remove_user_context(self, user_context: Any = None) -> Generator[dict, dict, dict]:
171+
def remove_user_context(self, user_context: Any = None):
152172
"""Execute browser.removeUserContext."""
153173
params = {
154174
"userContext": user_context,
155175
}
156176
params = {k: v for k, v in params.items() if v is not None}
157-
return command_builder("browser.removeUserContext", params)
177+
cmd = command_builder("browser.removeUserContext", params)
178+
return self._driver.execute(cmd)
158179

159-
def set_client_window_state(self, client_window: Any = None) -> Generator[dict, dict, dict]:
180+
def set_client_window_state(self, client_window: Any = None):
160181
"""Execute browser.setClientWindowState."""
161182
params = {
162183
"clientWindow": client_window,
163184
}
164185
params = {k: v for k, v in params.items() if v is not None}
165-
return command_builder("browser.setClientWindowState", params)
166-
167-
def set_download_behavior(self, download_behavior: Any = None, user_contexts: List[Any] = None) -> Generator[dict, dict, dict]:
186+
cmd = command_builder("browser.setClientWindowState", params)
187+
return self._driver.execute(cmd)
188+
189+
def set_download_behavior(
190+
self,
191+
allowed: bool | None = None,
192+
destination_folder: str | None = None,
193+
user_contexts: List[Any] | None = None,
194+
):
168195
"""Execute browser.setDownloadBehavior."""
196+
# Validate parameters
197+
if allowed is True and not destination_folder:
198+
raise ValueError("destination_folder is required when allowed=True")
199+
if allowed is False and destination_folder:
200+
raise ValueError(
201+
"destination_folder should not be provided when allowed=False"
202+
)
203+
204+
# Build download_behavior object
205+
download_behavior = None
206+
if allowed is True:
207+
download_behavior = {
208+
"type": "allow",
209+
"destinationFolder": destination_folder,
210+
}
211+
elif allowed is False:
212+
download_behavior = {
213+
"type": "deny",
214+
}
215+
elif allowed is None:
216+
download_behavior = {
217+
"type": "allow",
218+
}
219+
169220
params = {
170221
"downloadBehavior": download_behavior,
171222
"userContexts": user_contexts,
172223
}
173224
params = {k: v for k, v in params.items() if v is not None}
174-
return command_builder("browser.setDownloadBehavior", params)
175-
225+
cmd = command_builder("browser.setDownloadBehavior", params)
226+
return self._driver.execute(cmd)

0 commit comments

Comments
 (0)