Skip to content

CDP Mode - Patch 15 #3304

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

Merged
merged 4 commits into from
Nov 30, 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
4 changes: 4 additions & 0 deletions examples/cdp_mode/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ sb.cdp.assert_text(text, selector="html")
sb.cdp.assert_exact_text(text, selector="html")
sb.cdp.assert_true()
sb.cdp.assert_false()
sb.cdp.assert_equal(first, second)
sb.cdp.assert_not_equal(first, second)
sb.cdp.assert_in(first, second)
sb.cdp.assert_not_in(first, second)
sb.cdp.scroll_into_view(selector)
sb.cdp.scroll_to_y(y)
sb.cdp.scroll_to_top()
Expand Down
12 changes: 12 additions & 0 deletions examples/cdp_mode/raw_fingerprint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from seleniumbase import SB

with SB(uc=True, test=True, incognito=True) as sb:
url = "https://demo.fingerprint.com/playground"
sb.activate_cdp_mode(url)
sb.sleep(1)
sb.cdp.highlight('a[href*="browser-bot-detection"]')
bot_row_selector = 'table:contains("Bot") tr:nth-of-type(3)'
print(sb.cdp.get_text(bot_row_selector))
sb.cdp.assert_text("Bot Not detected", bot_row_selector)
sb.cdp.highlight(bot_row_selector)
sb.sleep(2)
19 changes: 19 additions & 0 deletions examples/cdp_mode/raw_handle_alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""To handle alerts in CDP Mode, reconnect and use WebDriver."""
from seleniumbase import SB

with SB(uc=True, test=True) as sb:
url = "https://the-internet.herokuapp.com/javascript_alerts"
sb.activate_cdp_mode(url)
sb.reconnect()
sb.cdp.gui_click_element('button[onclick="jsAlert()"]')
sb.sleep(1)
sb.accept_alert()
sb.sleep(1)
sb.cdp.gui_click_element('button[onclick="jsConfirm()"]')
sb.sleep(1)
sb.dismiss_alert()
sb.sleep(1)
sb.cdp.gui_click_element('button[onclick="jsPrompt()"]')
sb.sleep(1)
sb.uc_gui_write("Here is my prompt answer\n")
sb.sleep(1)
8 changes: 4 additions & 4 deletions examples/migration/protractor/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
```bash
$ pytest --rs -v --guest
=========================== test session starts ============================
platform darwin -- Python 3.11.2, pytest-7.4.0, pluggy-1.2.0 -- /Users/michael/.virtualenvs/sb_venv/bin/python
metadata: {'Python': '3.11.2', 'Platform': 'macOS-13.2.1-arm64-arm-64bit', 'Packages': {'pytest': '7.4.0', 'pluggy': '1.2.0'}, 'Plugins': {'html': '2.0.1', 'rerunfailures': '12.0', 'metadata': '3.0.0', 'ordering': '0.6', 'xdist': '3.3.1', 'seleniumbase': '4.15.10'}}
platform darwin -- Python 3.11.9, pytest-8.3.3, pluggy-1.5.0 -- /Users/michael/.virtualenvs/sbase11/bin/python
metadata: {'Python': '3.11.9', 'Platform': 'macOS-13.2.1-arm64-arm-64bit', 'Packages': {'pytest': '8.3.3', 'pluggy': '1.5.0'}, 'Plugins': {'cov': '6.0.0', 'html': '2.0.1', 'metadata': '3.1.1', 'seleniumbase': '4.33.2', 'ordering': '0.6', 'rerunfailures': '15.0', 'xdist': '3.6.1'}}
rootdir: /Users/michael/github/SeleniumBase/examples
configfile: pytest.ini
plugins: html-2.0.1, rerunfailures-12.0, metadata-3.0.0, ordering-0.6, xdist-3.3.1, seleniumbase-4.15.10
collected 4 items
plugins: html-2.0.1, metadata-3.1.1, seleniumbase-4.33.2, ordering-0.6, rerunfailures-15.0, xdist-3.6.1
collected 4 items

example_test.py::AngularJSHomePageTests::test_greet_user PASSED
example_test.py::AngularJSHomePageTests::test_todo_list PASSED
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ plugins:
- CONTRIBUTING.md
- SECURITY.md
- examples/case_summary.md
- examples/migration/raw_selenium/ReadMe.md
- help_docs/chinese.md
- integrations/katalon/ReadMe.md
- help_docs/ReadMe.md
Expand Down Expand Up @@ -174,6 +175,7 @@ nav:
- 📃 Desired Capabilities: help_docs/desired_capabilities.md
- 📜 Useful grep commands: help_docs/useful_grep_commands.md
- ⚙️ Downloading drivers: help_docs/webdriver_installation.md
- ✅ Selenium Migration: examples/migration/raw_selenium/ReadMe.md
- ✔️ Verifying drivers: help_docs/verify_webdriver.md
- Behave-BDD Integration:
- 🐝 Behave-BDD ReadMe: examples/behave_bdd/ReadMe.md
Expand Down
13 changes: 11 additions & 2 deletions mkdocs_build/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,17 @@ def main(*args, **kwargs):
scanned_dir_list = []
scanned_dir_list.append("help_docs")
scanned_dir_list.append("examples")
scanned_dir_list.append("examples/behave_bdd")
scanned_dir_list.append("examples/example_logs")
scanned_dir_list.append("examples/cdp_mode")
scanned_dir_list.append("examples/master_qa")
scanned_dir_list.append("examples/presenter")
scanned_dir_list.append("examples/behave_bdd")
scanned_dir_list.append("examples/chart_maker")
scanned_dir_list.append("examples/example_logs")
scanned_dir_list.append("examples/tour_examples")
scanned_dir_list.append("examples/visual_testing")
scanned_dir_list.append("integrations/google_cloud")
scanned_dir_list.append("seleniumbase/console_scripts")
scanned_dir_list.append("examples/migration/raw_selenium")
for scanned_dir in scanned_dir_list:
for dir_ in os.listdir(ROOT_DIR / scanned_dir):
files_to_process.append(os.path.join(scanned_dir, dir_))
Expand Down Expand Up @@ -159,6 +162,12 @@ def main(*args, **kwargs):
)
if alt_link_badge in line:
line = line.replace(alt_link_badge, back_to_gh)
changed = True
if "/help_docs/uc_mode/" in line and file_.count("/") >= 2:
line = line.replace(
"/help_docs/uc_mode/", "/../help_docs/uc_mode/"
)
changed = True
if "<!-- GitHub Only -->" in line:
changed = True
continue
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.1"
__version__ = "4.33.2"
4 changes: 4 additions & 0 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,10 @@ def uc_open_with_cdp_mode(driver, url=None):
cdp.assert_exact_text = CDPM.assert_exact_text
cdp.assert_true = CDPM.assert_true
cdp.assert_false = CDPM.assert_false
cdp.assert_equal = CDPM.assert_equal
cdp.assert_not_equal = CDPM.assert_not_equal
cdp.assert_in = CDPM.assert_in
cdp.assert_not_in = CDPM.assert_not_in
cdp.scroll_into_view = CDPM.scroll_into_view
cdp.scroll_to_y = CDPM.scroll_to_y
cdp.scroll_to_top = CDPM.scroll_to_top
Expand Down
49 changes: 28 additions & 21 deletions seleniumbase/core/sb_cdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,23 +135,10 @@ def find_element(
self.__add_light_pause()
selector = self.__convert_to_css_if_xpath(selector)
early_failure = False
if (":contains(" in selector):
tag_name = selector.split(":contains(")[0].split(" ")[-1]
text = selector.split(":contains(")[1].split(")")[0][1:-1]
with suppress(Exception):
self.loop.run_until_complete(
self.page.select(tag_name, timeout=timeout)
)
self.loop.run_until_complete(
self.page.find(text, timeout=timeout)
)
elements = []
with suppress(Exception):
elements = self.find_elements_by_text(text, tag_name=tag_name)
if elements:
return self.__add_sync_methods(elements[0])
else:
early_failure = True
if (":contains(") in selector:
selector, _ = page_utils.recalculate_selector(
selector, by="css selector", xp_ok=True
)
failure = False
try:
if early_failure:
Expand Down Expand Up @@ -726,12 +713,16 @@ def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT):

def evaluate(self, expression):
"""Run a JavaScript expression and return the result."""
if expression.startswith("return "):
expression = expression[len("return "):]
return self.loop.run_until_complete(
self.page.evaluate(expression)
)

def js_dumps(self, obj_name):
"""Similar to evaluate(), but for dictionary results."""
if obj_name.startswith("return "):
obj_name = obj_name[len("return "):]
return self.loop.run_until_complete(
self.page.js_dumps(obj_name)
)
Expand Down Expand Up @@ -1648,11 +1639,11 @@ def assert_text(
text = text.strip()
element = None
try:
element = self.select(selector, timeout=timeout)
element = self.find_element(selector, timeout=timeout)
except Exception:
raise Exception("Element {%s} not found!" % selector)
for i in range(30):
if self.is_element_visible(selector) and text in element.text_all:
if text in element.text_all:
return True
time.sleep(0.1)
raise Exception(
Expand Down Expand Up @@ -1683,11 +1674,27 @@ def assert_exact_text(

def assert_true(self, expression):
if not expression:
raise AssertionError("%s is not true")
raise AssertionError("%s is not true" % expression)

def assert_false(self, expression):
if expression:
raise AssertionError("%s is not false")
raise AssertionError("%s is not false" % expression)

def assert_equal(self, first, second):
if first != second:
raise AssertionError("%s is not equal to %s" % (first, second))

def assert_not_equal(self, first, second):
if first == second:
raise AssertionError("%s is equal to %s" % (first, second))

def assert_in(self, first, second):
if first not in second:
raise AssertionError("%s is not in %s" % (first, second))

def assert_not_in(self, first, second):
if first in second:
raise AssertionError("%s is in %s" % (first, second))

def scroll_into_view(self, selector):
self.find_element(selector).scroll_into_view()
Expand Down
28 changes: 15 additions & 13 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ def click(
original_by = by
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
self.cdp.click(selector)
self.cdp.click(selector, timeout=timeout)
return
if delay and (type(delay) in [int, float]) and delay > 0:
time.sleep(delay)
Expand Down Expand Up @@ -885,7 +885,7 @@ def update_text(
timeout = self.__get_new_timeout(timeout)
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
self.cdp.type(selector, text)
self.cdp.type(selector, text, timeout=timeout)
return
if self.__is_shadow_selector(selector):
self.__shadow_type(selector, text, timeout)
Expand Down Expand Up @@ -1112,7 +1112,7 @@ def send_keys(self, selector, text, by="css selector", timeout=None):
def press_keys(self, selector, text, by="css selector", timeout=None):
"""Use send_keys() to press one key at a time."""
if self.__is_cdp_swap_needed():
self.cdp.press_keys(selector, text)
self.cdp.press_keys(selector, text, timeout=timeout)
return
self.wait_for_ready_state_complete()
element = self.wait_for_element_present(
Expand Down Expand Up @@ -1597,7 +1597,7 @@ def click_link_text(self, link_text, timeout=None):
"""This method clicks link text on a page."""
self.__check_scope()
if self.__is_cdp_swap_needed():
self.cdp.find_element(link_text).click()
self.cdp.find_element(link_text, timeout=timeout).click()
return
self.__skip_if_esc()
if not timeout:
Expand Down Expand Up @@ -3380,6 +3380,8 @@ def open_html_file(self, html_file):

def execute_script(self, script, *args, **kwargs):
self.__check_scope()
if self.__is_cdp_swap_needed():
return self.cdp.evaluate(script)
self._check_browser()
return self.driver.execute_script(script, *args, **kwargs)

Expand Down Expand Up @@ -6308,7 +6310,7 @@ def js_click(
If "all_matches" is False, only the first match is clicked.
If "scroll" is False, won't scroll unless running in Demo Mode."""
if self.__is_cdp_swap_needed():
self.cdp.click(selector)
self.cdp.click(selector, timeout=timeout)
return
self.wait_for_ready_state_complete()
if not timeout or timeout is True:
Expand Down Expand Up @@ -8245,7 +8247,7 @@ def enter_mfa_code(
timeout = settings.SMALL_TIMEOUT
if self.__is_cdp_swap_needed():
mfa_code = self.get_mfa_code(totp_key)
self.cdp.type(selector, mfa_code + "\n")
self.cdp.type(selector, mfa_code + "\n", timeout=timeout)
return
self.wait_for_element_visible(selector, by=by, timeout=timeout)
if self.recorder_mode and self.__current_url_is_recordable():
Expand Down Expand Up @@ -9003,7 +9005,7 @@ def wait_for_element_visible(
original_selector = selector
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
return self.cdp.select(selector)
return self.cdp.select(selector, timeout=timeout)
if self.__is_shadow_selector(selector):
return self.__get_shadow_element(selector, timeout)
return page_actions.wait_for_element_visible(
Expand All @@ -9026,7 +9028,7 @@ def wait_for_element_clickable(
original_selector = selector
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
return self.cdp.select(selector)
return self.cdp.select(selector, timeout=timeout)
elif self.__is_shadow_selector(selector):
# If a shadow selector, use visible instead of clickable
return self.__wait_for_shadow_element_visible(selector, timeout)
Expand Down Expand Up @@ -9427,7 +9429,7 @@ def wait_for_element_present(
original_selector = selector
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
return self.cdp.select(selector)
return self.cdp.select(selector, timeout=timeout)
elif self.__is_shadow_selector(selector):
return self.__wait_for_shadow_element_present(selector, timeout)
return page_actions.wait_for_element_present(
Expand All @@ -9449,7 +9451,7 @@ def wait_for_element(self, selector, by="css selector", timeout=None):
original_selector = selector
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
return self.cdp.select(selector)
return self.cdp.select(selector, timeout=timeout)
if self.recorder_mode and self.__current_url_is_recordable():
if self.get_session_storage_item("pause_recorder") == "no":
if by == By.XPATH:
Expand Down Expand Up @@ -9492,7 +9494,7 @@ def wait_for_query_selector(
timeout = self.__get_new_timeout(timeout)
css_selector = self.convert_to_css_selector(selector, by=by)
if self.__is_cdp_swap_needed():
return self.cdp.select(css_selector)
return self.cdp.select(css_selector, timeout=timeout)
return js_utils.wait_for_css_query_selector(
self.driver, css_selector, timeout
)
Expand Down Expand Up @@ -9713,7 +9715,7 @@ def wait_for_text_visible(
text = self.__get_type_checked_text(text)
selector, by = self.__recalculate_selector(selector, by)
if self.__is_cdp_swap_needed():
return self.cdp.find_element(selector)
return self.cdp.find_element(selector, timeout=timeout)
elif self.__is_shadow_selector(selector):
return self.__wait_for_shadow_text_visible(text, selector, timeout)
return page_actions.wait_for_text_visible(
Expand Down Expand Up @@ -10093,7 +10095,7 @@ def assert_link_text(self, link_text, timeout=None):
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
timeout = self.__get_new_timeout(timeout)
if self.__is_cdp_swap_needed():
self.cdp.find_element(link_text)
self.cdp.find_element(link_text, timeout=timeout)
return
self.wait_for_link_text_visible(link_text, timeout=timeout)
if self.demo_mode:
Expand Down
Loading