Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mostly pytest updates #3317

Merged
merged 6 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading