Skip to content

Commit 7fda761

Browse files
authored
Merge pull request #1171 from seleniumbase/new-methods-a-fix-and-refactoring
New methods, a fix, and some refactoring
2 parents 0d1de72 + 4db8891 commit 7fda761

File tree

11 files changed

+161
-18
lines changed

11 files changed

+161
-18
lines changed

examples/test_agent.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,41 @@
44
class UserAgentTests(BaseCase):
55
def test_user_agent(self):
66
self.open("http://whatsmyuseragent.org/")
7-
user_agent = self.get_text(".user-agent p")
8-
print("\n\nUser-Agent:\n%s\n" % user_agent)
7+
user_agent_detected = self.get_text(".user-agent p")
8+
original_user_agent = user_agent_detected
9+
if not self.user_agent:
10+
# Using the built-in user-agent string
11+
print("\n\nUser-Agent:\n%s\n" % user_agent_detected)
12+
else:
13+
# User-agent was overridden using: --agent=STRING
14+
print("\n\nUser-Agent override:\n%s\n" % user_agent_detected)
915
print(self.get_text(".ip-address p"))
10-
print("\nThe browser will close automatically in 7 seconds...")
11-
self.sleep(7)
16+
self.sleep(3)
17+
18+
# Now change the user-agent using "execute_cdp_cmd()"
19+
if not self.is_chromium():
20+
msg = "\n* execute_cdp_cmd() is only for Chromium browsers"
21+
print(msg)
22+
self.skip(msg)
23+
print("\n--------------------------")
24+
try:
25+
self.driver.execute_cdp_cmd(
26+
"Network.setUserAgentOverride", {
27+
"userAgent": "Mozilla/5.0 "
28+
"(Nintendo Switch; WifiWebAuthApplet) "
29+
"AppleWebKit/606.4 (KHTML, like Gecko) "
30+
"NF/6.0.1.15.4 NintendoBrowser/5.1.0.20393"
31+
}
32+
)
33+
self.open("http://whatsmyuseragent.org/")
34+
user_agent_detected = self.get_text(".user-agent p")
35+
print("\nUser-Agent (after override):\n%s\n" % user_agent_detected)
36+
print(self.get_text(".ip-address p"))
37+
self.sleep(3)
38+
finally:
39+
# Reset the user-agent back to the original
40+
self.driver.execute_cdp_cmd(
41+
"Network.setUserAgentOverride", {
42+
"userAgent": original_user_agent
43+
}
44+
)

examples/test_demo_site.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_demo_site(self):
3131

3232
# Verify that a button click changes text on the page
3333
self.assert_text("This Text is Green", "#pText")
34-
self.click("#myButton")
34+
self.click('button:contains("Click Me")')
3535
self.assert_text("This Text is Purple", "#pText")
3636

3737
# Assert that the given SVG is visible on the page

examples/user_agent_test.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,39 @@
44
class UserAgentTests(BaseCase):
55
def test_user_agent(self):
66
self.open("https://www.whatsmyua.info/")
7-
user_agent = self.get_text("#custom-ua-string")
8-
print("\n\nUser-Agent = %s\n" % user_agent)
9-
print("Displaying User-Agent Info:")
10-
print(self.get_text("#useragent"))
11-
print("\nThe browser will close automatically in 7 seconds...")
12-
self.sleep(7)
7+
user_agent_detected = self.get_text("#custom-ua-string")
8+
original_user_agent = user_agent_detected
9+
if not self.user_agent:
10+
# Using the built-in user-agent string
11+
print("\n\nUser-Agent = %s\n" % user_agent_detected)
12+
else:
13+
# User-agent was overridden using: --agent=STRING
14+
print("\n\nUser-Agent override = %s\n" % user_agent_detected)
15+
self.sleep(3)
16+
17+
try:
18+
# Now change the user-agent using "execute_cdp_cmd()"
19+
if not self.is_chromium():
20+
msg = "\n* execute_cdp_cmd() is only for Chromium browsers"
21+
print(msg)
22+
self.skip(msg)
23+
print("--------------------------")
24+
self.driver.execute_cdp_cmd(
25+
"Network.setUserAgentOverride", {
26+
"userAgent": "Mozilla/5.0 "
27+
"(Nintendo Switch; WifiWebAuthApplet) "
28+
"AppleWebKit/606.4 (KHTML, like Gecko) "
29+
"NF/6.0.1.15.4 NintendoBrowser/5.1.0.20393"
30+
}
31+
)
32+
self.open("https://www.whatsmyua.info/")
33+
user_agent_detected = self.get_text("#custom-ua-string")
34+
print("\nUser-Agent (after override) = %s" % user_agent_detected)
35+
self.sleep(3)
36+
finally:
37+
# Reset the user-agent back to the original
38+
self.driver.execute_cdp_cmd(
39+
"Network.setUserAgentOverride", {
40+
"userAgent": original_user_agent
41+
}
42+
)

help_docs/method_summary.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ self.remove_attribute(selector, attribute, by=By.CSS_SELECTOR, timeout=None)
110110

111111
self.remove_attributes(selector, attribute, by=By.CSS_SELECTOR)
112112

113+
self.get_property(selector, property, by=By.CSS_SELECTOR, timeout=None)
114+
115+
self.get_text_content(selector, by=By.CSS_SELECTOR, timeout=None)
116+
113117
self.get_property_value(selector, property, by=By.CSS_SELECTOR, timeout=None)
114118

115119
self.get_image_url(selector, by=By.CSS_SELECTOR, timeout=None)

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Pillow==8.4.0;python_version>="3.6" and python_version<"3.7"
116116
Pillow==9.0.0;python_version>="3.7"
117117
typing-extensions==3.10.0.2;python_version<"3.6"
118118
typing-extensions==4.0.0;python_version>="3.6" and python_version<"3.8"
119-
rich==10.16.2;python_version>="3.6" and python_version<"4.0"
119+
rich==11.0.0;python_version>="3.6" and python_version<"4.0"
120120
tornado==5.1.1;python_version<"3.5"
121121
tornado==6.1;python_version>="3.5"
122122
pdfminer.six==20191110;python_version<"3.5"

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "2.3.10"
2+
__version__ = "2.3.11"

seleniumbase/console_scripts/rich_helper.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ def display_code(code):
3737
def fix_emoji_spacing(code):
3838
try:
3939
# Fix the display width of certain emojis that take up two spaces
40-
double_width_emojis = ["🗺️", "🖼️", "🗄️", "⏺️", "♻️", "🗂️", "🖥️"]
40+
double_width_emojis = [
41+
"🗺️", "🖼️", "🗄️", "⏺️", "♻️", "🗂️", "🖥️", "🕹️", "🎞️"
42+
]
4143
for emoji in double_width_emojis:
4244
if emoji in code:
4345
code = code.replace(emoji, emoji + " ")

seleniumbase/fixtures/base_case.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def test_anything(self):
7272
reload(sys) # noqa: F821
7373
sys.setdefaultencoding("utf8")
7474
selenium4 = False
75-
if sys.version_info[0] == 3 and sys.version_info[1] >= 7:
75+
if sys.version_info >= (3, 7):
7676
selenium4 = True
7777

7878

@@ -1403,6 +1403,50 @@ def remove_attributes(self, selector, attribute, by=By.CSS_SELECTOR):
14031403
except Exception:
14041404
pass
14051405

1406+
def get_property(
1407+
self, selector, property, by=By.CSS_SELECTOR, timeout=None
1408+
):
1409+
"""Returns the property value of an element.
1410+
This is not the same as self.get_property_value(), which returns
1411+
the value of an element's computed style using a different algorithm.
1412+
If no result is found, an empty string (instead of None) is returned.
1413+
Example:
1414+
html_text = self.get_property(SELECTOR, "textContent")
1415+
"""
1416+
self.__check_scope()
1417+
if not timeout:
1418+
timeout = settings.SMALL_TIMEOUT
1419+
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1420+
timeout = self.__get_new_timeout(timeout)
1421+
selector, by = self.__recalculate_selector(selector, by)
1422+
self.wait_for_ready_state_complete()
1423+
time.sleep(0.01)
1424+
element = page_actions.wait_for_element_present(
1425+
self.driver, selector, by, timeout
1426+
)
1427+
try:
1428+
property_value = element.get_property(property)
1429+
except (StaleElementReferenceException, ENI_Exception):
1430+
self.wait_for_ready_state_complete()
1431+
time.sleep(0.14)
1432+
element = page_actions.wait_for_element_present(
1433+
self.driver, selector, by, timeout
1434+
)
1435+
property_value = element.get_property(property)
1436+
if not property_value:
1437+
return ""
1438+
return property_value
1439+
1440+
def get_text_content(self, selector, by=By.CSS_SELECTOR, timeout=None):
1441+
"""Returns the text that appears in the HTML for an element.
1442+
This is different from "self.get_text(selector, by=By.CSS_SELECTOR)"
1443+
because that only returns the visible text on a page for an element,
1444+
rather than the HTML text that's being returned from this method."""
1445+
self.__check_scope()
1446+
return self.get_property(
1447+
selector, property="textContent", by=by, timeout=timeout
1448+
)
1449+
14061450
def get_property_value(
14071451
self, selector, property, by=By.CSS_SELECTOR, timeout=None
14081452
):
@@ -3895,12 +3939,18 @@ def __are_quotes_escaped(self, string):
38953939
def __escape_quotes_if_needed(self, string):
38963940
return js_utils.escape_quotes_if_needed(string)
38973941

3942+
def __is_in_frame(self):
3943+
return js_utils.is_in_frame(self.driver)
3944+
38983945
def bring_active_window_to_front(self):
38993946
"""Brings the active browser window to the front.
39003947
This is useful when multiple drivers are being used."""
39013948
self.__check_scope()
39023949
try:
3903-
self.switch_to_window(self.driver.current_window_handle)
3950+
if not self.__is_in_frame():
3951+
# Only bring the window to the front if not in a frame
3952+
# because the driver resets itself to default content.
3953+
self.switch_to_window(self.driver.current_window_handle)
39043954
except Exception:
39053955
pass
39063956

seleniumbase/fixtures/js_utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ def escape_quotes_if_needed(string):
212212
return string
213213

214214

215+
def is_in_frame(driver):
216+
"""
217+
Returns True if the driver has switched to a frame.
218+
Returns False if the driver was on default content.
219+
"""
220+
return driver.execute_script(
221+
"""
222+
var frame = window.frameElement;
223+
if (frame) {
224+
return true;
225+
}
226+
else {
227+
return false;
228+
}
229+
"""
230+
)
231+
232+
215233
def safe_execute_script(driver, script):
216234
"""When executing a script that contains a jQuery command,
217235
it's important that the jQuery library has been loaded first.

seleniumbase/fixtures/page_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
This module contains useful utility methods.
33
"""
44
import codecs
5+
import os
56
import re
67
import requests
78

@@ -247,7 +248,8 @@ def _download_file_to(file_url, destination_folder, new_file_name=None):
247248
else:
248249
file_name = file_url.split("/")[-1]
249250
r = requests.get(file_url)
250-
with open(destination_folder + "/" + file_name, "wb") as code:
251+
file_path = os.path.join(destination_folder, file_name)
252+
with open(file_path, "wb") as code:
251253
code.write(r.content)
252254

253255

0 commit comments

Comments
 (0)