Skip to content

Commit

Permalink
Merge pull request #3317 from seleniumbase/mostly-pytest-updates
Browse files Browse the repository at this point in the history
Mostly `pytest` updates
  • Loading branch information
mdmintz authored Dec 6, 2024
2 parents c909b1a + 13983a9 commit f4c3f24
Show file tree
Hide file tree
Showing 18 changed files with 254 additions and 29 deletions.
13 changes: 13 additions & 0 deletions examples/cdp_mode/raw_radwell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from seleniumbase import SB

with SB(uc=True, test=True, locale_code="en", incognito=True) as sb:
url = "https://www.radwell.com/en-US/Search/Advanced/"
sb.activate_cdp_mode(url)
sb.sleep(3)
sb.cdp.press_keys("form#basicsearch input", "821C-PM-111DA-142")
sb.sleep(1)
sb.cdp.click('[value="Search Icon"]')
sb.sleep(3)
sb.cdp.assert_text("MAC VALVES INC", "a.manufacturer-link")
sb.cdp.highlight("a.manufacturer-link")
sb.sleep(1)
15 changes: 15 additions & 0 deletions examples/cdp_mode/raw_tiktok.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from seleniumbase import SB

with SB(
uc=True, test=True, locale_code="en", incognito=True, ad_block=True
) as sb:
url = "https://www.tiktok.com/@startrek?lang=en"
sb.activate_cdp_mode(url)
sb.sleep(2.5)
sb.cdp.click('button:contains("Refresh")')
sb.sleep(1.5)
print(sb.cdp.get_text('h2[data-e2e="user-bio"]'))
for i in range(55):
sb.cdp.scroll_down(12)
sb.sleep(0.06)
sb.sleep(1)
31 changes: 31 additions & 0 deletions examples/cdp_mode/raw_united.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from seleniumbase import SB

with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
url = "https://www.united.com/en/us"
sb.activate_cdp_mode(url)
sb.sleep(2.5)
origin_input = 'input[placeholder="Origin"]'
origin = "Boston, MA"
destination_input = 'input[placeholder="Destination"]'
destination = "San Diego, CA"
sb.cdp.gui_click_element(origin_input)
sb.sleep(1.2)
sb.cdp.type(origin_input, origin)
sb.sleep(1.2)
sb.cdp.click('strong:contains("%s")' % origin)
sb.sleep(1.2)
sb.cdp.gui_click_element(destination_input)
sb.sleep(1.2)
sb.cdp.type(destination_input, destination)
sb.sleep(1.2)
sb.cdp.click('strong:contains("%s")' % destination)
sb.sleep(1.2)
sb.cdp.click('button[aria-label="Find flights"]')
sb.sleep(6)
flights = sb.find_elements('div[class*="CardContainer__block"]')
print("**** Flights from %s to %s ****" % (origin, destination))
if not flights:
print("* No flights found!")
for flight in flights:
print("* " + flight.text.split(" Destination")[0])
sb.sleep(1.5)
2 changes: 1 addition & 1 deletion examples/master_qa/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]

# Display console output. Disable cacheprovider:
addopts = --capture=no -p no:cacheprovider
addopts = --capture=tee-sys -p no:cacheprovider

# Skip these directories during test collection:
norecursedirs = .* build dist recordings temp assets
Expand Down
2 changes: 1 addition & 1 deletion examples/migration/raw_selenium/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]

# Display console output. Disable cacheprovider:
addopts = --capture=no -p no:cacheprovider
addopts = --capture=tee-sys -p no:cacheprovider

# Skip these directories during test collection:
norecursedirs = .* build dist recordings temp assets
Expand Down
2 changes: 1 addition & 1 deletion examples/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]

# Display console output. Disable cacheprovider:
addopts = --capture=no -p no:cacheprovider
addopts = --capture=tee-sys -p no:cacheprovider

# Skip these directories during test collection:
norecursedirs = .* build dist recordings temp assets
Expand Down
2 changes: 1 addition & 1 deletion examples/translations/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]

# Display console output. Disable cacheprovider:
addopts = --capture=no -p no:cacheprovider
addopts = --capture=tee-sys -p no:cacheprovider

# Skip these directories during test collection:
norecursedirs = .* build dist recordings temp assets
Expand Down
48 changes: 42 additions & 6 deletions help_docs/method_summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,44 @@ self._print(TEXT) # Calls Python's print() / Allows for translations

############

# **** UC Mode methods. (uc=True / --uc) ****

# (Mainly for CDP Mode) - (For all CDP methods, see the CDP Mode Docs)

self.activate_cdp_mode(url=None) # Activate CDP Mode on the given URL

self.reconnect(timeout=0.1) # disconnect() + sleep(timeout) + connect()

self.disconnect() # Stops the webdriver service to prevent detection

self.connect() # Starts the webdriver service to allow actions again

# (For regular UC Mode)

self.uc_open(url) # (Open in same tab with default reconnect_time)

self.uc_open_with_tab(url) # (New tab with default reconnect_time)

self.uc_open_with_reconnect(url, reconnect_time=None) # (New tab)

self.uc_open_with_disconnect(url, timeout=None) # New tab + sleep()

self.uc_click(selector) # A stealthy click for evading bot-detection

self.uc_gui_press_key(key) # Use PyAutoGUI to press the keyboard key

self.uc_gui_press_keys(keys) # Use PyAutoGUI to press a list of keys

self.uc_gui_write(text) # Similar to uc_gui_press_keys(), but faster

self.uc_gui_click_x_y(x, y, timeframe=0.25) # PyAutoGUI click screen

self.uc_gui_click_captcha(frame="iframe", retry=False, blind=False)

self.uc_gui_handle_captcha(frame="iframe")

############

# "driver"-specific methods added (or modified) by SeleniumBase

driver.default_get(url) # Because driver.get(url) works differently in UC Mode
Expand Down Expand Up @@ -1076,7 +1114,9 @@ driver.uc_open_with_reconnect(url, reconnect_time=None) # (New tab)

driver.uc_open_with_disconnect(url, timeout=None) # New tab + sleep()

driver.reconnect(timeout) # disconnect() + sleep(timeout) + connect()
driver.uc_activate_cdp_mode(url=None) # Activate CDP Mode on the given URL

driver.reconnect(timeout=0.1) # disconnect() + sleep(timeout) + connect()

driver.disconnect() # Stops the webdriver service to prevent detection

Expand All @@ -1093,12 +1133,8 @@ driver.uc_gui_write(text) # Similar to uc_gui_press_keys(), but faster
driver.uc_gui_click_x_y(x, y, timeframe=0.25) # PyAutoGUI click screen

driver.uc_gui_click_captcha(frame="iframe", retry=False, blind=False)
# driver.uc_gui_click_cf(frame="iframe", retry=False, blind=False)
# driver.uc_gui_click_rc(frame="iframe", retry=False, blind=False)

driver.uc_gui_handle_captcha(frame="iframe") # (Auto-detects the CAPTCHA)
# driver.uc_gui_handle_cf(frame="iframe") # PyAutoGUI click CF Turnstile
# driver.uc_gui_handle_rc(frame="iframe") # PyAutoGUI click G. reCAPTCHA
driver.uc_gui_handle_captcha(frame="iframe")
```

--------
Expand Down
2 changes: 1 addition & 1 deletion help_docs/recorder_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ sbase print ./recordings/TEST_NAME_rec.py -n
cp ./recordings/TEST_NAME_rec.py ./TEST_NAME.py
```
The first command creates a boilerplate test with a breakpoint; the second command runs the test with the Recorder activated; the third command prints the completed test to the console; and the fourth command replaces the initial boilerplate with the completed test. If you're just experimenting with the Recorder, you can run the second command as many times as you want, and it'll override previous recordings saved to ``./recordings/TEST_NAME_rec.py``. (Note that ``-s`` is needed to allow breakpoints, unless you already have a ``pytest.ini`` file present with ``addopts = --capture=no`` in it. The ``-q`` is optional, which shortens ``pytest`` console output.)
The first command creates a boilerplate test with a breakpoint; the second command runs the test with the Recorder activated; the third command prints the completed test to the console; and the fourth command replaces the initial boilerplate with the completed test. If you're just experimenting with the Recorder, you can run the second command as many times as you want, and it'll override previous recordings saved to ``./recordings/TEST_NAME_rec.py``. (Note that ``-s`` is needed to allow breakpoints, unless you already have a ``pytest.ini`` file present where you set it. The ``-q`` is optional, which shortens ``pytest`` console output.)
⏺️ You can also use the Recorder to add code to an existing test. To do that, you'll first need to create a breakpoint in your code to insert manual browser actions:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ packages = [
]

[tool.pytest.ini_options]
addopts = ["--capture=no", "-p no:cacheprovider"]
addopts = ["--capture=tee-sys", "-p no:cacheprovider"]
norecursedirs = [".*", "build", "dist", "recordings", "temp", "assets"]
filterwarnings = [
"ignore::pytest.PytestWarning",
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]

# Display console output. Disable cacheprovider:
addopts = --capture=no -p no:cacheprovider
addopts = --capture=tee-sys -p no:cacheprovider

# Skip these directories during test collection:
norecursedirs = .* build dist recordings temp assets
Expand Down
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pynose>=1.5.3
platformdirs>=4.3.6
typing-extensions>=4.12.2
sbvirtualdisplay>=1.3.0
six>=1.16.0
six>=1.17.0
parse>=1.20.2
parse-type>=0.6.4
colorama>=0.4.6
Expand Down Expand Up @@ -43,9 +43,8 @@ sortedcontainers==2.4.0
execnet==2.1.1
iniconfig==2.0.0
pluggy==1.5.0
py==1.11.0
pytest==8.3.4
pytest-html==2.0.1
pytest-html==4.1.1
pytest-metadata==3.1.1
pytest-ordering==0.6
pytest-rerunfailures==14.0;python_version<"3.9"
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.33.3"
__version__ = "4.33.4"
2 changes: 1 addition & 1 deletion seleniumbase/console_scripts/sb_mkdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def main():

data = []
data.append("[pytest]")
data.append("addopts = --capture=no -p no:cacheprovider")
data.append("addopts = --capture=tee-sys -p no:cacheprovider")
data.append("norecursedirs = .* build dist recordings temp assets")
data.append("filterwarnings =")
data.append(" ignore::pytest.PytestWarning")
Expand Down
14 changes: 14 additions & 0 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ def log_d(message):
print(message)


def make_writable(file_path):
# Set permissions to: "If you can read it, you can write it."
mode = os.stat(file_path).st_mode
mode |= (mode & 0o444) >> 1 # copy R bits to W
os.chmod(file_path, mode)


def make_executable(file_path):
# Set permissions to: "If you can read it, you can execute it."
mode = os.stat(file_path).st_mode
Expand Down Expand Up @@ -815,6 +822,13 @@ def install_pyautogui_if_missing(driver):
pip_find_lock = fasteners.InterProcessLock(
constants.PipInstall.FINDLOCK
)
try:
with pip_find_lock:
pass
except Exception:
# Need write permissions
with suppress(Exception):
make_writable(constants.PipInstall.FINDLOCK)
with pip_find_lock: # Prevent issues with multiple processes
try:
import pyautogui
Expand Down
9 changes: 9 additions & 0 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -13983,6 +13983,15 @@ def __activate_virtual_display_as_needed(self):
pip_find_lock = fasteners.InterProcessLock(
constants.PipInstall.FINDLOCK
)
try:
with pip_find_lock:
pass
except Exception:
# Need write permissions
with suppress(Exception):
mode = os.stat(constants.PipInstall.FINDLOCK).st_mode
mode |= (mode & 0o444) >> 1 # copy R bits to W
os.chmod(constants.PipInstall.FINDLOCK, mode)
with pip_find_lock: # Prevent issues with multiple processes
if self.undetectable and not (self.headless or self.headless2):
import Xlib.display
Expand Down
Loading

0 comments on commit f4c3f24

Please sign in to comment.