diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index c7031b8e4f5..95e3aa6a6ea 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -345,8 +345,6 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb: ### 🐙 CDP Mode API / Methods -(Some method args have been left out for simplicity. Eg: timeout) - ```python sb.cdp.get(url) sb.cdp.open(url) @@ -354,16 +352,16 @@ sb.cdp.reload(ignore_cache=True, script_to_evaluate_on_load=None) sb.cdp.refresh() sb.cdp.get_event_loop() sb.cdp.add_handler(event, handler) -sb.cdp.find_element(selector) -sb.cdp.find(selector) -sb.cdp.locator(selector) -sb.cdp.find_element_by_text(text, tag_name=None) -sb.cdp.find_all(selector) +sb.cdp.find_element(selector, best_match=False, timeout=None) +sb.cdp.find(selector, best_match=False, timeout=None) +sb.cdp.locator(selector, best_match=False, timeout=None) +sb.cdp.find_element_by_text(text, tag_name=None, timeout=None) +sb.cdp.find_all(selector, timeout=None) sb.cdp.find_elements_by_text(text, tag_name=None) -sb.cdp.select(selector) -sb.cdp.select_all(selector) -sb.cdp.find_elements(selector) -sb.cdp.find_visible_elements(selector) +sb.cdp.select(selector, timeout=None) +sb.cdp.select_all(selector, timeout=None) +sb.cdp.find_elements(selector, timeout=None) +sb.cdp.find_visible_elements(selector, timeout=None) sb.cdp.click_nth_element(selector, number) sb.cdp.click_nth_visible_element(selector, number) sb.cdp.click_link(link_text) @@ -375,17 +373,17 @@ sb.cdp.get_all_cookies(*args, **kwargs) sb.cdp.set_all_cookies(*args, **kwargs) sb.cdp.save_cookies(*args, **kwargs) sb.cdp.load_cookies(*args, **kwargs) -sb.cdp.clear_cookies(*args, **kwargs) +sb.cdp.clear_cookies() sb.cdp.sleep(seconds) sb.cdp.bring_active_window_to_front() sb.cdp.bring_to_front() sb.cdp.get_active_element() sb.cdp.get_active_element_css() -sb.cdp.click(selector) +sb.cdp.click(selector, timeout=None) sb.cdp.click_active_element() sb.cdp.click_if_visible(selector) sb.cdp.click_visible_elements(selector, limit=0) -sb.cdp.mouse_click(selector) +sb.cdp.mouse_click(selector, timeout=None) sb.cdp.nested_click(parent_selector, selector) sb.cdp.get_nested_element(parent_selector, selector) sb.cdp.select_option_by_text(dropdown_selector, option) @@ -396,10 +394,10 @@ sb.cdp.highlight_overlay(selector) sb.cdp.remove_element(selector) sb.cdp.remove_from_dom(selector) sb.cdp.remove_elements(selector) -sb.cdp.send_keys(selector, text) -sb.cdp.press_keys(selector, text) -sb.cdp.type(selector, text) -sb.cdp.set_value(selector, text) +sb.cdp.send_keys(selector, text, timeout=None) +sb.cdp.press_keys(selector, text, timeout=None) +sb.cdp.type(selector, text, timeout=None) +sb.cdp.set_value(selector, text, timeout=None) sb.cdp.evaluate(expression) sb.cdp.js_dumps(obj_name) sb.cdp.maximize() @@ -420,11 +418,11 @@ sb.cdp.get_screen_rect() sb.cdp.get_window_rect() sb.cdp.get_window_size() sb.cdp.get_window_position() -sb.cdp.get_element_rect(selector) -sb.cdp.get_element_size(selector) -sb.cdp.get_element_position(selector) -sb.cdp.get_gui_element_rect(selector) -sb.cdp.get_gui_element_center(selector) +sb.cdp.get_element_rect(selector, timeout=None) +sb.cdp.get_element_size(selector, timeout=None) +sb.cdp.get_element_position(selector, timeout=None) +sb.cdp.get_gui_element_rect(selector, timeout=None) +sb.cdp.get_gui_element_center(selector, timeout=None) sb.cdp.get_document() sb.cdp.get_flattened_document() sb.cdp.get_element_attributes(selector) @@ -452,19 +450,19 @@ sb.cdp.uncheck_if_checked(selector) sb.cdp.unselect_if_selected(selector) sb.cdp.is_element_present(selector) sb.cdp.is_element_visible(selector) -sb.cdp.wait_for_element_visible(selector) -sb.cdp.assert_element(selector) -sb.cdp.assert_element_visible(selector) -sb.cdp.assert_element_present(selector) -sb.cdp.assert_element_absent(selector) -sb.cdp.assert_element_not_visible(selector) +sb.cdp.wait_for_element_visible(selector, timeout=None) +sb.cdp.assert_element(selector, timeout=None) +sb.cdp.assert_element_visible(selector, timeout=None) +sb.cdp.assert_element_present(selector, timeout=None) +sb.cdp.assert_element_absent(selector, timeout=None) +sb.cdp.assert_element_not_visible(selector, timeout=None) sb.cdp.assert_element_attribute(selector, attribute, value=None) sb.cdp.assert_title(title) sb.cdp.assert_title_contains(substring) sb.cdp.assert_url(url) sb.cdp.assert_url_contains(substring) -sb.cdp.assert_text(text, selector="html") -sb.cdp.assert_exact_text(text, selector="html") +sb.cdp.assert_text(text, selector="html", timeout=None) +sb.cdp.assert_exact_text(text, selector="html", timeout=None) sb.cdp.assert_true() sb.cdp.assert_false() sb.cdp.assert_equal(first, second) diff --git a/examples/cdp_mode/raw_gettyimages.py b/examples/cdp_mode/raw_gettyimages.py new file mode 100644 index 00000000000..d2cf0a4f732 --- /dev/null +++ b/examples/cdp_mode/raw_gettyimages.py @@ -0,0 +1,11 @@ +from seleniumbase import SB + +with SB(uc=True, test=True, locale_code="en", pls="none") as sb: + sb.activate_cdp_mode("https://www.gettyimages.com/") + sb.cdp.click('label:contains("Editorial")') + sb.cdp.press_keys("form input", "comic con 2024 sci fi panel\n") + sb.sleep(3) + items = sb.cdp.find_elements("figure picture img") + for item in items: + item.flash(color="44CC88") + sb.sleep(0.08) diff --git a/examples/cdp_mode/raw_kohls.py b/examples/cdp_mode/raw_kohls.py new file mode 100644 index 00000000000..a29fa7ca374 --- /dev/null +++ b/examples/cdp_mode/raw_kohls.py @@ -0,0 +1,25 @@ +from seleniumbase import SB + +with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb: + url = "https://www.kohls.com/" + sb.activate_cdp_mode(url) + sb.sleep(2.5) + search = "Mickey Mouse 100 friends teal pillow" + required_text = "Mickey" + sb.cdp.press_keys('input[name="search"]', search + "\n") + sb.sleep(5) + for item in sb.cdp.find_elements("div.products-container-right"): + if "Sponsored" in item.text: + item.remove_from_dom() + sb.cdp.remove_elements("#tce-sticky-wrapper") + sb.cdp.remove_elements("li.sponsored-product") + sb.cdp.remove_elements("#tce-dec-ces-3-banner") + print('*** Kohls Search for "%s":' % search) + for item in sb.cdp.find_elements("ul.products a img"): + if item: + item.flash(color="44CC88") + title = item.get_attribute("title") + if title and required_text in title: + print("* " + title) + sb.sleep(0.1) + sb.sleep(1) diff --git a/examples/cdp_mode/raw_req_mod.py b/examples/cdp_mode/raw_req_mod.py index 560b14b6914..eaa5f8d142f 100644 --- a/examples/cdp_mode/raw_req_mod.py +++ b/examples/cdp_mode/raw_req_mod.py @@ -5,14 +5,13 @@ async def request_paused_handler(event, tab): r = event.request + rid = event.request_id is_image = ".png" in r.url or ".jpg" in r.url or ".gif" in r.url if not is_image: # Let the data through - tab.feed_cdp(mycdp.fetch.continue_request(request_id=event.request_id)) - else: # Modify the data (change the image) - tab.feed_cdp(mycdp.fetch.continue_request( - request_id=event.request_id, - url="https://seleniumbase.io/other/with_frakes.jpg" - )) + tab.feed_cdp(mycdp.fetch.continue_request(request_id=rid)) + else: # Modify the data (Change the image URL) + new_url = "https://seleniumbase.io/other/with_frakes.jpg" + tab.feed_cdp(mycdp.fetch.continue_request(request_id=rid, url=new_url)) with SB(uc=True, test=True, locale_code="en", pls="none") as sb: diff --git a/examples/cdp_mode/raw_theaters.py b/examples/cdp_mode/raw_theaters.py new file mode 100644 index 00000000000..f67b082b268 --- /dev/null +++ b/examples/cdp_mode/raw_theaters.py @@ -0,0 +1,16 @@ +"""Simple web-scraping example in CDP Mode""" +from seleniumbase import SB + +with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb: + url = "https://architectureofcities.com/roman-theaters" + sb.activate_cdp_mode(url) + sb.cdp.click_if_visible("#cn-close-notice") + sb.sleep(2) + print("*** " + sb.cdp.get_text("h1") + " ***") + for item in sb.cdp.find_elements("h3"): + if item.text and "." in item.text: + item.flash(color="44CC88") + sb.cdp.scroll_down(34) + print("* " + item.text.replace(" ", " ")) + sb.sleep(0.15) + sb.sleep(1) diff --git a/examples/cdp_mode/raw_tiktok.py b/examples/cdp_mode/raw_tiktok.py index 391a0e2a43f..98952a3c977 100644 --- a/examples/cdp_mode/raw_tiktok.py +++ b/examples/cdp_mode/raw_tiktok.py @@ -7,6 +7,6 @@ sb.cdp.click_if_visible('button:contains("Refresh")') sb.sleep(1.5) print(sb.cdp.get_text('h2[data-e2e="user-bio"]')) - for i in range(50): + for i in range(54): sb.cdp.scroll_down(12) sb.sleep(1) diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index 6a27bde9f43..ccce5ae7562 100644 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -13,275 +13,177 @@ For backwards compatibility, older versions of method names have remained to kee self.open(url) # Duplicates: self.open_url(url), self.visit(url), visit_url(url), # self.goto(url), self.go_to(url) - self.get(url) # If the url parameter is a URL: Perform self.open(url) # Otherwise: return self.get_element(URL_AS_A_SELECTOR) - self.click(selector, by="css selector", timeout=None, delay=0, scroll=True) - self.slow_click(selector, by="css selector", timeout=None) - self.double_click(selector, by="css selector", timeout=None) - self.context_click(selector, by="css selector", timeout=None) # Duplicates: # self.right_click(selector, by="css selector", timeout=None) - self.click_chain(selectors_list, by="css selector", timeout=None, spacing=0) - self.type(selector, text, by="css selector", timeout=None) # Duplicates: # self.update_text(selector, text, by="css selector", timeout=None) # self.input(selector, text, by="css selector", timeout=None) # self.fill(selector, text, by="css selector", timeout=None) # self.write(selector, text, by="css selector", timeout=None) - self.send_keys(selector, text, by="css selector", timeout=None) # Duplicates: # self.add_text(selector, text, by="css selector", timeout=None) - self.press_keys(selector, text, by="css selector", timeout=None) - self.submit(selector, by="css selector") - self.clear(selector, by="css selector", timeout=None) - self.focus(selector, by="css selector", timeout=None) - self.refresh() -# Duplicates: self.refresh_page(), self.reload_page(), self.reload() - +# Duplicates: +# self.refresh_page(), self.reload_page(), self.reload() self.get_current_url() - self.get_origin() - self.get_page_source() - self.get_title() -# Duplicates: self.get_page_title() - +# Duplicates: +# self.get_page_title() self.get_user_agent() - self.get_locale_code() - self.go_back() - self.go_forward() - self.open_start_page() - self.open_if_not_url(url) - self.is_element_present(selector, by="css selector") - self.is_element_visible(selector, by="css selector") - self.is_element_clickable(selector, by="css selector") - self.is_element_enabled(selector, by="css selector") - self.is_text_visible(text, selector="html", by="css selector") - self.is_exact_text_visible(text, selector="html", by="css selector") - self.is_non_empty_text_visible(selector="html", by="css selector") - self.is_attribute_present(selector, attribute, value=None, by="css selector") - self.is_link_text_visible(link_text) - self.is_partial_link_text_visible(partial_link_text) - self.is_link_text_present(link_text) - self.is_partial_link_text_present(link_text) - self.get_link_attribute(link_text, attribute, hard_fail=True) # Duplicates: # self.get_link_text_attribute(link_text, attribute, hard_fail=True) - self.get_partial_link_text_attribute(link_text, attribute, hard_fail=True) - self.click_link(link_text, timeout=None) # Duplicates: # self.click_link_text(link_text, timeout=None) - self.click_partial_link(partial_link_text, timeout=None) # Duplicates: # self.click_partial_link_text(partial_link_text, timeout=None) - self.get_text(selector="html", by="css selector", timeout=None) - self.get_attribute(selector, attribute, by="css selector", timeout=None, hard_fail=True) - self.set_attribute(selector, attribute, value, by="css selector", timeout=None, scroll=False) - self.set_attributes(selector, attribute, value, by="css selector") # Duplicates: # self.set_attribute_all(selector, attribute, value, by="css selector") - self.remove_attribute(selector, attribute, by="css selector", timeout=None) - self.remove_attributes(selector, attribute, by="css selector") - self.internalize_links() - self.get_property(selector, property, by="css selector", timeout=None) - self.get_text_content(selector="html", by="css selector", timeout=None) - self.get_property_value(selector, property, by="css selector", timeout=None) - self.get_image_url(selector, by="css selector", timeout=None) - self.find_elements(selector, by="css selector", limit=0) # Duplicates: # self.select_all(selector, by="css selector", limit=0) - self.find_visible_elements(selector, by="css selector", limit=0) - self.click_visible_elements(selector, by="css selector", limit=0, timeout=None) - self.click_nth_visible_element(selector, number, by="css selector", timeout=None) - self.click_if_visible(selector, by="css selector", timeout=0) - self.click_active_element() - self.click_with_offset( selector, x, y, by="css selector", mark=None, timeout=None, center=None) - self.double_click_with_offset( selector, x, y, by="css selector", mark=None, timeout=None, center=None) - self.is_checked(selector, by="css selector", timeout=None) # Duplicates: # self.is_selected(selector, by="css selector", timeout=None) - self.check_if_unchecked(selector, by="css selector") # Duplicates: # self.select_if_unselected(selector, by="css selector") - self.uncheck_if_checked(selector, by="css selector") # Duplicates: # self.unselect_if_selected(selector, by="css selector") - self.is_element_in_an_iframe(selector, by="css selector") - self.switch_to_frame_of_element(selector, by="css selector") - self.hover(selector, by="css selector", timeout=None) # Duplicates: # self.hover_on_element(selector, by="css selector", timeout=None) # self.hover_over_element(selector, by="css selector", timeout=None) - self.hover_and_click( hover_selector, click_selector, hover_by="css selector", click_by="css selector", timeout=None, js_click=False) - self.hover_and_js_click( hover_selector, click_selector, hover_by="css selector", click_by="css selector", timeout=None) - self.hover_and_double_click( hover_selector, click_selector, hover_by="css selector", click_by="css selector", timeout=None) - self.drag_and_drop( drag_selector, drop_selector, drag_by="css selector", drop_by="css selector", timeout=None, jquery=False) - self.drag_and_drop_with_offset( selector, x, y, by="css selector", timeout=None) - self.select_option_by_text( dropdown_selector, option, dropdown_by="css selector", timeout=None) - self.select_option_by_index( dropdown_selector, option, dropdown_by="css selector", timeout=None) - self.select_option_by_value( dropdown_selector, option, dropdown_by="css selector", timeout=None) - self.get_select_options( dropdown_selector, attribute="text", by="css selector", timeout=None) - self.load_html_string(html_string, new_page=True) - self.set_content(html_string, new_page=False) - self.load_html_file(html_file, new_page=True) - self.open_html_file(html_file) - self.execute_script(script, *args, **kwargs) - self.execute_cdp_cmd(script, *args, **kwargs) - self.execute_async_script(script, timeout=None) - self.safe_execute_script(script, *args, **kwargs) - self.get_element_at_x_y(x, y) - self.get_gui_element_rect(selector, by="css selector") - self.get_gui_element_center(selector, by="css selector") - self.get_screen_rect() - self.get_window_rect() - self.get_window_size() - self.get_window_position() - self.set_window_rect(x, y, width, height) - self.set_window_size(width, height) - self.set_window_position(x, y) - self.maximize_window() - self.minimize_window() - self.reset_window_size() - self.switch_to_frame(frame="iframe", timeout=None) - self.switch_to_default_content() - self.switch_to_parent_frame() - with self.frame_switch(frame, timeout=None): # Indented Code Block for Context Manager (Must use "with") - self.set_content_to_frame(frame, timeout=None) - self.set_content_to_default(nested=False) -# Duplicates: self.set_content_to_default_content(nested=False) - +# Duplicates: +# self.set_content_to_default_content(nested=False) self.set_content_to_parent() -# Duplicates: self.set_content_to_parent_frame() - +# Duplicates: +# self.set_content_to_parent_frame() self.open_new_window(switch_to=True) -# Duplicates: self.open_new_tab(switch_to=True) - +# Duplicates: +# self.open_new_tab(switch_to=True) self.switch_to_window(window, timeout=None) -# Duplicates: self.switch_to_tab(tab, timeout=None) - +# Duplicates: +# self.switch_to_tab(tab, timeout=None) self.switch_to_default_window() -# Duplicates: self.switch_to_default_tab() - +# Duplicates: +# self.switch_to_default_tab() self.switch_to_newest_window() -# Duplicates: self.switch_to_newest_tab() - +# Duplicates: +# self.switch_to_newest_tab() self.get_new_driver( browser=None, headless=None, @@ -340,323 +242,190 @@ self.get_new_driver( d_height=None, d_p_r=None, ) - self.switch_to_driver(driver) - self.switch_to_default_driver() - self.save_screenshot(name, folder=None, selector=None, by="css selector") - self.save_screenshot_to_logs(name=None, selector=None, by="css selector") - self.save_data_to_logs(data, file_name=None) - self.append_data_to_logs(data, file_name=None) - self.save_page_source(name, folder=None) - self.save_cookies(name="cookies.txt") - self.load_cookies(name="cookies.txt", expiry=False) - self.delete_all_cookies() -# Duplicates: self.clear_all_cookies() - +# Duplicates: +# self.clear_all_cookies() self.delete_saved_cookies(name="cookies.txt") - self.get_saved_cookies(name="cookies.txt") - self.get_cookie(name) - self.get_cookies() - self.get_cookie_string() - self.add_cookie(cookie_dict, expiry=False) - self.add_cookies(cookies, expiry=False) - self.wait_for_ready_state_complete(timeout=None) - self.wait_for_angularjs(timeout=None) - self.sleep(seconds) -# Duplicates: self.wait(seconds) - +# Duplicates: +# self.wait(seconds) self.install_addon(xpi_file) - self.activate_jquery() - self.activate_demo_mode() - self.deactivate_demo_mode() - self.activate_design_mode() - self.deactivate_design_mode() - self.activate_recorder() - self.save_recorded_actions() - self.bring_active_window_to_front() - self.bring_to_front(selector, by="css selector") - self.highlight_click(selector, by="css selector", loops=3, scroll=True, timeout=None) - self.highlight_type(selector, text, by="css selector", loops=3, scroll=True, timeout=None) # Duplicates: # self.highlight_update_text( # selector, text, by="css selector", loops=3, scroll=True, timeout=None) - self.highlight_if_visible(selector, by="css selector", loops=4, scroll=True) - self.highlight(selector, by="css selector", loops=4, scroll=True, timeout=None) - self.highlight_elements(selector, by="css selector", loops=4, scroll=True, limit=0) - self.press_up_arrow(selector="html", times=1, by="css selector") - self.press_down_arrow(selector="html", times=1, by="css selector") - self.press_left_arrow(selector="html", times=1, by="css selector") - self.press_right_arrow(selector="html", times=1, by="css selector") - self.scroll_to(selector, by="css selector", timeout=None) -# Duplicates: self.scroll_to_element(selector, by="css selector") - +# Duplicates: +# self.scroll_to_element(selector, by="css selector") self.slow_scroll_to(selector, by="css selector", timeout=None) -# Duplicates: self.slow_scroll_to_element(selector, by="css selector") - +# Duplicates: +# self.slow_scroll_to_element(selector, by="css selector") self.scroll_into_view(selector, by="css selector", timeout=None) - self.scroll_to_top() - self.scroll_to_bottom() - self.click_xpath(xpath) - self.js_click(selector, by="css selector", all_matches=False, timeout=None, scroll=True) - self.js_click_if_present(selector, by="css selector", timeout=0) - self.js_click_if_visible(selector, by="css selector", timeout=0) - self.js_click_all(selector, by="css selector", timeout=None) - self.jquery_click(selector, by="css selector", timeout=None) - self.jquery_click_all(selector, by="css selector", timeout=None) - self.hide_element(selector, by="css selector") - self.hide_elements(selector, by="css selector") - self.show_element(selector, by="css selector") - self.show_elements(selector, by="css selector") - self.remove_element(selector, by="css selector") - self.remove_elements(selector, by="css selector") - self.ad_block() -# Duplicates: self.block_ads() - +# Duplicates: +# self.block_ads() self.show_file_choosers() - self.disable_beforeunload() - self.get_domain_url(url) - self.get_active_element_css() - self.get_beautiful_soup(source=None) - self.get_unique_links() - self.get_link_status_code(link, allow_redirects=False, timeout=5, verify=False) - self.assert_link_status_code_is_not_404(link) - self.assert_no_404_errors(multithreaded=True, timeout=None) # Duplicates: # self.assert_no_broken_links(multithreaded=True, timeout=None) - self.print_unique_links_with_status_codes() - self.get_pdf_text( pdf, page=None, maxpages=None, password=None, codec='utf-8', wrap=False, nav=False, override=False, caching=True) - self.assert_pdf_text( pdf, text, page=None, maxpages=None, password=None, codec='utf-8', wrap=True, nav=False, override=False, caching=True) - self.create_folder(folder) - self.choose_file(selector, file_path, by="css selector", timeout=None) - self.save_element_as_image_file(selector, file_name, folder=None, overlay_text="") - self.download_file(file_url, destination_folder=None) - self.save_file_as(file_url, new_file_name, destination_folder=None) - self.save_data_as(data, file_name, destination_folder=None) - self.append_data_to_file(data, file_name, destination_folder=None) - self.get_file_data(file_name, folder=None) - self.get_downloads_folder() - self.get_browser_downloads_folder() - self.get_downloaded_files(regex=None, browser=False) - self.get_path_of_downloaded_file(file, browser=False) - self.get_data_from_downloaded_file(file, timeout=None, browser=False) - self.is_downloaded_file_present(file, browser=False) - self.is_downloaded_file_regex_present(regex, browser=False) - self.delete_downloaded_file_if_present(file, browser=False) -# Duplicates: self.delete_downloaded_file(file, browser=False) - +# Duplicates: +# self.delete_downloaded_file(file, browser=False) self.assert_downloaded_file(file, timeout=None, browser=False) - self.assert_downloaded_file_regex(regex, timeout=None, browser=False) - self.assert_data_in_downloaded_file(data, file, timeout=None, browser=False) - self.assert_true(expr, msg=None) - self.assert_false(expr, msg=None) - self.assert_equal(first, second, msg=None) - self.assert_not_equal(first, second, msg=None) - self.assert_in(first, second, msg=None) - self.assert_not_in(first, second, msg=None) - self.assert_raises(*args, **kwargs) - self.wait_for_attribute(selector, attribute, value=None, by="css selector", timeout=None) - self.assert_attribute(selector, attribute, value=None, by="css selector", timeout=None) - self.assert_title(title) - self.assert_title_contains(substring) - self.assert_url(url) - self.assert_url_contains(substring) - self.assert_no_js_errors(exclude=[]) - self.inspect_html() - self.is_valid_url(url) - self.is_alert_present() - self.is_online() - self.is_chromium() - self.get_chrome_version() - self.get_chromium_version() - self.get_chromedriver_version() - self.get_chromium_driver_version() - self.get_mfa_code(totp_key=None) # Duplicates: # self.get_totp_code(totp_key=None) # self.get_google_auth_password(totp_key=None) # self.get_google_auth_code(totp_key=None) - self.enter_mfa_code(selector, totp_key=None, by="css selector", timeout=None) # Duplicates: # self.enter_totp_code(selector, totp_key=None, by="css selector", timeout=None) - self.convert_css_to_xpath(css) - self.convert_xpath_to_css(xpath) - self.convert_to_css_selector(selector, by) - self.set_value(selector, text, by="css selector", timeout=None, scroll=True) - self.js_update_text(selector, text, by="css selector", timeout=None) # Duplicates: # self.js_type(selector, text, by="css selector", timeout=None) # self.set_text(selector, text, by="css selector", timeout=None) - self.set_text_content(selector, text, by="css selector", timeout=None, scroll=False) - self.jquery_update_text(selector, text, by="css selector", timeout=None) # Duplicates: # self.jquery_type(selector, text, by="css selector", timeout=None) - self.get_value(selector, by="css selector", timeout=None) - self.set_time_limit(time_limit) - self.set_default_timeout(timeout) - self.reset_default_timeout() - self.fail(msg=None) - self.skip(reason="") ############ self.start_recording_console_logs() - self.console_log_string(string) - self.console_log_script(script) - self.get_recorded_console_logs() ############ self.set_local_storage_item(key, value) - self.get_local_storage_item(key) - self.remove_local_storage_item(key) - self.clear_local_storage() -# Duplicates: delete_local_storage() - +# Duplicates: +# self.delete_local_storage() self.get_local_storage_keys() - self.get_local_storage_items() - self.set_session_storage_item(key, value) - self.get_session_storage_item(key) - self.remove_session_storage_item(key) - self.clear_session_storage() -# Duplicates: delete_session_storage() - +# Duplicates: +# self.delete_session_storage() self.get_session_storage_keys() - self.get_session_storage_items() ############ @@ -666,27 +435,19 @@ self.set_wire_proxy(string) # Requires "--wire"! ############ self.add_css_link(css_link) - self.add_js_link(js_link) - self.add_css_style(css_style) - self.add_js_code_from_link(js_link) - self.add_js_code(js_code) - self.add_meta_tag(http_equiv=None, content=None) ############ self.create_presentation(name=None, theme="default", transition="default") - self.add_slide( content=None, image=None, code=None, iframe=None, content2=None, notes=None, transition=None, name=None) - self.save_presentation(name=None, filename=None, show_notes=False, interval=0) - self.begin_presentation(name=None, filename=None, show_notes=False, interval=0) ############ @@ -695,95 +456,65 @@ self.create_pie_chart( chart_name=None, title=None, subtitle=None, data_name=None, unit=None, libs=True, labels=True, legend=True) - self.create_bar_chart( chart_name=None, title=None, subtitle=None, data_name=None, unit=None, libs=True, labels=True, legend=True) - self.create_column_chart( chart_name=None, title=None, subtitle=None, data_name=None, unit=None, libs=True, labels=True, legend=True) - self.create_line_chart( chart_name=None, title=None, subtitle=None, data_name=None, unit=None, zero=False, libs=True, labels=True, legend=True) - self.create_area_chart( chart_name=None, title=None, subtitle=None, data_name=None, unit=None, zero=False, libs=True, labels=True, legend=True) - self.add_series_to_chart(data_name=None, chart_name=None) - self.add_data_point(label, value, color=None, chart_name=None) - self.save_chart(chart_name=None, filename=None, folder=None) - self.display_chart(chart_name=None, filename=None, interval=0) - self.extract_chart(chart_name=None) ############ self.create_tour(name=None, theme=None) - self.create_shepherd_tour(name=None, theme=None) - self.create_bootstrap_tour(name=None) - self.create_hopscotch_tour(name=None) - self.create_introjs_tour(name=None) - self.set_introjs_colors(theme_color=None, hover_color=None) - self.add_tour_step(message, selector=None, name=None, title=None, theme=None, alignment=None) - self.play_tour(name=None, interval=0) # Duplicates: # self.start_tour(name=None, interval=0): - self.export_tour(name=None, filename="my_tour.js", url=None) ############ self.activate_jquery_confirm() - self.set_jqc_theme(theme, color=None, width=None) - self.reset_jqc_theme() - self.get_jqc_button_input(message, buttons, options=None) - self.get_jqc_text_input(message, button=None, options=None) - self.get_jqc_form_inputs(message, buttons, options=None) ############ self.activate_messenger() - self.post_message(message, duration=None, pause=True, style="info") - self.post_message_and_highlight(message, selector, by="css selector") - self.post_success_message(message, duration=None, pause=True) - self.post_error_message(message, duration=None, pause=True) - self.set_messenger_theme(theme="default", location="default", max_messages="default") ############ self.generate_referral(start_page, destination_page, selector=None) - self.generate_traffic(start_page, destination_page, loops=1, selector=None) - self.generate_referral_chain(pages) - self.generate_traffic_chain(pages, loops=1) ############ @@ -793,11 +524,8 @@ self.get_element(selector, by="css selector", timeout=None) # self.wait_for_selector(selector, by="css selector", timeout=None) # self.locator(selector, by="css selector", timeout=None) # self.wait_for_element_present(selector, by="css selector", timeout=None) - self.wait_for_query_selector(selector, by="css selector", timeout=None) - self.assert_element_present(selector, by="css selector", timeout=None) - self.assert_elements_present(*args, **kwargs) ############ @@ -806,11 +534,9 @@ self.find_element(selector, by="css selector", timeout=None) # Duplicates: # self.wait_for_element(selector, by="css selector", timeout=None) # self.wait_for_element_visible(selector, by="css selector", timeout=None) - self.assert_element(selector, by="css selector", timeout=None) # Duplicates: # self.assert_element_visible(selector, by="css selector", timeout=None) - self.assert_elements(*args, **kwargs) # Duplicates: # self.assert_elements_visible(*args, **kwargs) @@ -821,34 +547,27 @@ self.find_text(text, selector="html", by="css selector", timeout=None) # Duplicates: # self.wait_for_text(text, selector="html", by="css selector", timeout=None) # self.wait_for_text_visible(text, selector="html", by="css selector", timeout=None) - self.find_exact_text(text, selector="html", by="css selector", timeout=None) # Duplicates: # self.wait_for_exact_text(text, selector="html", by="css selector", timeout=None) # self.wait_for_exact_text_visible(text, selector="html", by="css selector", timeout=None) - self.find_non_empty_text(selector="html", by="css selector", timeout=None) # Duplicates: # self.wait_for_non_empty_text(selector="html", by="css selector", timeout=None) # self.wait_for_non_empty_text_visible(selector="html", by="css selector", timeout=None) - self.assert_text(text, selector="html", by="css selector", timeout=None) # Duplicates: # self.assert_text_visible(text, selector="html", by="css selector", timeout=None) - self.assert_exact_text(text, selector="html", by="css selector", timeout=None) ############ self.wait_for_link_text_present(link_text, timeout=None) - self.wait_for_partial_link_text_present(link_text, timeout=None) - self.find_link_text(link_text, timeout=None) # Duplicates: # self.wait_for_link_text(link_text, timeout=None) # self.wait_for_link_text_visible(link_text, timeout=None) - self.assert_link_text(link_text, timeout=None) # Duplicates: # self.assert_link(link_text, timeout=None) @@ -858,7 +577,6 @@ self.assert_link_text(link_text, timeout=None) self.find_partial_link_text(partial_link_text, timeout=None) # Duplicates: # self.wait_for_partial_link_text(partial_link_text, timeout=None) - self.assert_partial_link_text(partial_link_text, timeout=None) ############ @@ -866,7 +584,6 @@ self.assert_partial_link_text(partial_link_text, timeout=None) self.wait_for_element_absent(selector, by="css selector", timeout=None) # Duplicates: # self.wait_for_element_not_present(selector, by="css selector", timeout=None) - self.assert_element_absent(selector, by="css selector", timeout=None) # Duplicates: # self.assert_element_not_present(selector, by="css selector", timeout=None) @@ -878,26 +595,20 @@ self.wait_for_element_clickable(selector, by="css selector", timeout=None) ############ self.wait_for_element_not_visible(selector, by="css selector", timeout=None) - self.assert_element_not_visible(selector, by="css selector", timeout=None) ############ self.wait_for_text_not_visible(text, selector="html", by="css selector", timeout=None) - self.wait_for_exact_text_not_visible(text, selector="html", by="css selector", timeout=None) - self.assert_text_not_visible(text, selector="html", by="css selector", timeout=None) - self.assert_exact_text_not_visible(text, selector="html", by="css selector", timeout=None) - self.assert_non_empty_text(selector="html", by="css selector", timeout=None) ############ self.wait_for_attribute_not_present( selector, attribute, value=None, by="css selector", timeout=None) - self.assert_attribute_not_present( selector, attribute, value=None, by="css selector", timeout=None) @@ -906,11 +617,9 @@ self.assert_attribute_not_present( self.accept_alert(timeout=None) # Duplicates: # self.wait_for_and_accept_alert(timeout=None) - self.dismiss_alert(timeout=None) # Duplicates: # self.wait_for_and_dismiss_alert(timeout=None) - self.switch_to_alert(timeout=None) # Duplicates: # self.wait_for_and_switch_to_alert(timeout=None) @@ -929,45 +638,38 @@ self.deferred_assert_element(selector, by="css selector", timeout=None, fs=False # Duplicates: # self.delayed_assert_element( # selector, by="css selector", timeout=None, fs=False) - self.deferred_assert_element_present(selector, by="css selector", timeout=None, fs=False) # Duplicates: # self.delayed_assert_element_present( # selector, by="css selector", timeout=None, fs=False) - self.deferred_assert_text(text, selector="html", by="css selector", timeout=None, fs=False) # Duplicates: # self.delayed_assert_text( # text, selector="html", by="css selector", timeout=None, fs=False) - self.deferred_assert_exact_text( text, selector="html", by="css selector", timeout=None, fs=False) # Duplicates: # self.delayed_assert_exact_text( # text, selector="html", by="css selector", timeout=None, fs=False) - self.deferred_assert_non_empty_text( selector="html", by="css selector", timeout=None, fs=False) # Duplicates: # self.delayed_assert_non_empty_text( # selector="html", by="css selector", timeout=None, fs=False) - self.deferred_check_window( name="default", level=0, baseline=False, check_domain=True, full_diff=False, fs=False) # Duplicates: # self.delayed_check_window( # name="default", level=0, baseline=False, # check_domain=True, full_diff=False, fs=False) - self.process_deferred_asserts(print_only=False) -# Duplicates: self.process_delayed_asserts(print_only=False) +# Duplicates: +# self.process_delayed_asserts(print_only=False) ############ self.fail(msg=None) # Inherited from "unittest" - self._check_browser() # Fails test cleanly if the active window is closed - self._print(TEXT) # Calls Python's print() / Allows for translations ############ @@ -977,35 +679,22 @@ self._print(TEXT) # Calls Python's print() / Allows for translations # (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") ############ @@ -1013,93 +702,49 @@ 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 - driver.open(url) # Like driver.get(), but allows partial URLs without protocol - driver.click(selector) - driver.click_link(link_text) - driver.click_if_visible(selector) - driver.click_active_element() - driver.send_keys(selector, text) - driver.press_keys(selector, text) - driver.type(selector, text) - driver.submit(selector) - driver.assert_element(selector) - driver.assert_element_present(selector) - driver.assert_element_not_visible(selector) - driver.assert_text(text, selector) - driver.assert_exact_text(text, selector) - driver.find_element(selector) - driver.find_elements(selector) - driver.wait_for_element(selector) - driver.wait_for_element_visible(selector) - driver.wait_for_element_present(selector) - driver.wait_for_selector(selector) - driver.wait_for_text(text, selector) - driver.wait_for_exact_text(text, selector) - driver.wait_for_and_accept_alert() - driver.wait_for_and_dismiss_alert() - driver.is_element_present(selector) - driver.is_element_visible(selector) - driver.is_text_visible(text, selector) - driver.is_exact_text_visible(text, selector) - driver.is_attribute_present(selector, attribute) - driver.get_text(selector) - driver.js_click(selector) - driver.get_active_element_css() - driver.get_locale_code() - driver.get_origin() - driver.get_user_agent() - driver.highlight(selector) - driver.highlight_click(selector) - driver.highlight_if_visible(selector) - driver.sleep(seconds) - driver.locator(selector) - driver.get_attribute(selector, attribute) - driver.get_page_source() - driver.get_title() - driver.switch_to_frame(frame="iframe") ############ @@ -1107,35 +752,20 @@ driver.switch_to_frame(frame="iframe") # "driver"-specific methods added (or modified) by SeleniumBase for UC Mode: driver.get(url) # If UC Mode and site detects bots, then uc_open_with_tab(url) - driver.uc_open(url) # (Open in same tab with default reconnect_time) - driver.uc_open_with_tab(url) # (New tab with default reconnect_time) - driver.uc_open_with_reconnect(url, reconnect_time=None) # (New tab) - driver.uc_open_with_disconnect(url, timeout=None) # New tab + sleep() - 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 - driver.connect() # Starts the webdriver service to allow actions again - driver.uc_click(selector) # A stealthy click for evading bot-detection - driver.uc_gui_press_key(key) # Use PyAutoGUI to press the keyboard key - driver.uc_gui_press_keys(keys) # Use PyAutoGUI to press a list of keys - 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_handle_captcha(frame="iframe") ``` diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index d5962837b17..4608be4cd1e 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -2,14 +2,12 @@ # Minimum Python version: 3.9 (for generating docs only) regex>=2024.11.6 -pymdown-extensions>=10.12 +pymdown-extensions>=10.13 pipdeptree>=2.24.0 python-dateutil>=2.8.2 Markdown==3.7 markdown2==2.5.2 -MarkupSafe==3.0.2 -Jinja2==3.1.4 -click==8.1.7 +click==8.1.8 ghp-import==2.1.0 watchdog==6.0.0 cairocffi==1.7.1 @@ -20,7 +18,7 @@ lxml==5.3.0 pyquery==2.0.1 readtime==3.0.0 mkdocs==1.6.1 -mkdocs-material==9.5.48 +mkdocs-material==9.5.49 mkdocs-exclude-search==0.6.6 mkdocs-simple-hooks==0.1.5 mkdocs-material-extensions==1.3.1 diff --git a/requirements.txt b/requirements.txt index a52ab7e25da..806752a8c0d 100755 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ packaging>=24.2 setuptools~=70.2;python_version<"3.10" setuptools>=75.6.0;python_version>="3.10" wheel>=0.45.1 -attrs>=24.2.0 +attrs>=24.3.0 certifi>=2024.12.14 exceptiongroup>=1.2.2 websockets~=13.1;python_version<"3.9" @@ -14,7 +14,10 @@ mycdp>=1.1.0 pynose>=1.5.3 platformdirs>=4.3.6 typing-extensions>=4.12.2 -sbvirtualdisplay>=1.3.1 +sbvirtualdisplay>=1.4.0 +MarkupSafe==2.1.5;python_version<"3.9" +MarkupSafe>=3.0.2;python_version>="3.9" +Jinja2>=3.1.5 six>=1.17.0 parse>=1.20.2 parse-type>=0.6.4 @@ -26,9 +29,9 @@ tabcompleter>=1.4.0 pdbp>=1.6.1 idna==3.10 chardet==5.2.0 -charset-normalizer==3.4.0 +charset-normalizer==3.4.1 urllib3>=1.26.20,<2;python_version<"3.10" -urllib3>=1.26.20,<2.3.0;python_version>="3.10" +urllib3>=1.26.20,<2.4.0;python_version>="3.10" requests==2.32.3 sniffio==1.3.1 h11==0.14.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 46f03196f5e..5a2eda19a6a 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.33.11" +__version__ = "4.33.12" diff --git a/seleniumbase/core/log_helper.py b/seleniumbase/core/log_helper.py index ceb9c531a29..bd1ebe25be9 100644 --- a/seleniumbase/core/log_helper.py +++ b/seleniumbase/core/log_helper.py @@ -15,6 +15,11 @@ py311_patch2 = constants.PatchPy311.PATCH +def __is_cdp_swap_needed(driver): + """If the driver is disconnected, use a CDP method when available.""" + return shared_utils.is_cdp_swap_needed(driver) + + def log_screenshot(test_logpath, driver, screenshot=None, get=False): screenshot_name = settings.SCREENSHOT_NAME screenshot_path = os.path.join(test_logpath, screenshot_name) @@ -356,7 +361,11 @@ def log_page_source(test_logpath, driver, source=None): page_source = source else: try: - page_source = driver.page_source + page_source = None + if __is_cdp_swap_needed(driver): + page_source = driver.cdp.get_page_source() + else: + page_source = driver.page_source page_source = get_html_source_with_base_href(driver, page_source) except Exception: source = constants.Warnings.PAGE_SOURCE_UNDEFINED @@ -448,7 +457,11 @@ def get_test_name(test): def get_last_page(driver): try: - last_page = driver.current_url + last_page = None + if __is_cdp_swap_needed(driver): + last_page = driver.cdp.get_current_url() + else: + last_page = driver.current_url except Exception: last_page = "[WARNING! Browser Not Open!]" if len(last_page) < 5: diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 7cde2ee2f39..65a36be93e1 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -127,14 +127,14 @@ def get_event_loop(self): def add_handler(self, event, handler): self.page.add_handler(event, handler) - def find_element( - self, selector, best_match=False, timeout=settings.SMALL_TIMEOUT - ): + def find_element(self, selector, best_match=False, timeout=None): """Similar to select(), but also finds elements by text content. When using text-based searches, if best_match=False, then will find the first element with the text. If best_match=True, then if multiple elements have that text, then will use the element with the closest text-length to the text being searched for.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__add_light_pause() selector = self.__convert_to_css_if_xpath(selector) early_failure = False @@ -167,12 +167,12 @@ def find_element( self.__slow_mode_pause_if_set() return element - def find_element_by_text( - self, text, tag_name=None, timeout=settings.SMALL_TIMEOUT - ): + def find_element_by_text(self, text, tag_name=None, timeout=None): """Returns an element by matching text. Optionally, provide a tag_name to narrow down the search to an element with the given tag. (Eg: a, button, div, script, span)""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__add_light_pause() time_now = time.time() self.assert_text(text, timeout=timeout) @@ -218,7 +218,9 @@ def find_element_by_text( % (text, tag_name, timeout, plural) ) - def find_all(self, selector, timeout=settings.SMALL_TIMEOUT): + def find_all(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__add_light_pause() selector = self.__convert_to_css_if_xpath(selector) elements = self.loop.run_until_complete( @@ -272,8 +274,10 @@ def find_elements_by_text(self, text, tag_name=None): updated_elements.append(element) return updated_elements - def select(self, selector, timeout=settings.SMALL_TIMEOUT): + def select(self, selector, timeout=None): """Similar to find_element(), but without text-based search.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__add_light_pause() selector = self.__convert_to_css_if_xpath(selector) if (":contains(" in selector): @@ -307,7 +311,9 @@ def select(self, selector, timeout=settings.SMALL_TIMEOUT): self.__slow_mode_pause_if_set() return element - def select_all(self, selector, timeout=settings.SMALL_TIMEOUT): + def select_all(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__add_light_pause() selector = self.__convert_to_css_if_xpath(selector) elements = self.loop.run_until_complete( @@ -319,10 +325,14 @@ def select_all(self, selector, timeout=settings.SMALL_TIMEOUT): updated_elements.append(element) return updated_elements - def find_elements(self, selector, timeout=settings.SMALL_TIMEOUT): + def find_elements(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT return self.select_all(selector, timeout=timeout) - def find_visible_elements(self, selector, timeout=settings.SMALL_TIMEOUT): + def find_visible_elements(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT visible_elements = [] elements = self.select_all(selector, timeout=timeout) for element in elements: @@ -587,12 +597,12 @@ def load_cookies(self, *args, **kwargs): driver.cookies.load(*args, **kwargs) ) - def clear_cookies(self, *args, **kwargs): + def clear_cookies(self): driver = self.driver if hasattr(driver, "cdp_base"): driver = driver.cdp_base return self.loop.run_until_complete( - driver.cookies.clear(*args, **kwargs) + driver.cookies.clear() ) def sleep(self, seconds): @@ -616,7 +626,9 @@ def get_active_element_css(self): self.page.evaluate(js_code) ) - def click(self, selector, timeout=settings.SMALL_TIMEOUT): + def click(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() element = self.find_element(selector, timeout=timeout) element.scroll_into_view() @@ -672,8 +684,10 @@ def click_visible_elements(self, selector, limit=0): except Exception: break - def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT): + def mouse_click(self, selector, timeout=None): """(Attempt simulating a mouse click)""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() element = self.find_element(selector, timeout=timeout) element.scroll_into_view() @@ -771,7 +785,9 @@ def remove_elements(self, selector): with suppress(Exception): self.loop.run_until_complete(self.page.evaluate(js_code)) - def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT): + def send_keys(self, selector, text, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() element = self.select(selector, timeout=timeout) element.scroll_into_view() @@ -781,8 +797,10 @@ def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT): self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait()) - def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT): + def press_keys(self, selector, text, timeout=None): """Similar to send_keys(), but presses keys at human speed.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() element = self.select(selector, timeout=timeout) element.scroll_into_view() @@ -799,8 +817,10 @@ def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT): self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait()) - def type(self, selector, text, timeout=settings.SMALL_TIMEOUT): + def type(self, selector, text, timeout=None): """Similar to send_keys(), but clears the text field first.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() element = self.select(selector, timeout=timeout) element.scroll_into_view() @@ -812,8 +832,10 @@ def type(self, selector, text, timeout=settings.SMALL_TIMEOUT): self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait()) - def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT): + def set_value(self, selector, text, timeout=None): """Similar to send_keys(), but clears the text field first.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT self.__slow_mode_pause_if_set() selector = self.__convert_to_css_if_xpath(selector) element = self.select(selector, timeout=timeout) @@ -1036,7 +1058,9 @@ def get_window_position(self): coordinates["y"] = y if y else 0 return coordinates - def get_element_rect(self, selector, timeout=settings.SMALL_TIMEOUT): + def get_element_rect(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT selector = self.__convert_to_css_if_xpath(selector) self.select(selector, timeout=timeout) self.__add_light_pause() @@ -1049,23 +1073,29 @@ def get_element_rect(self, selector, timeout=settings.SMALL_TIMEOUT): ) return coordinates - def get_element_size(self, selector): - element_rect = self.get_element_rect(selector) + def get_element_size(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT + element_rect = self.get_element_rect(selector, timeout=timeout) coordinates = {} coordinates["width"] = element_rect["width"] coordinates["height"] = element_rect["height"] return coordinates - def get_element_position(self, selector): - element_rect = self.get_element_rect(selector) + def get_element_position(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT + element_rect = self.get_element_rect(selector, timeout=timeout) coordinates = {} coordinates["x"] = element_rect["x"] coordinates["y"] = element_rect["y"] return coordinates - def get_gui_element_rect(self, selector): + def get_gui_element_rect(self, selector, timeout=None): """(Coordinates are relative to the screen. Not the window.)""" - element_rect = self.get_element_rect(selector) + if not timeout: + timeout = settings.SMALL_TIMEOUT + element_rect = self.get_element_rect(selector, timeout=timeout) e_width = element_rect["width"] e_height = element_rect["height"] window_rect = self.get_window_rect() @@ -1079,9 +1109,11 @@ def get_gui_element_rect(self, selector): y = y + window_rect["scrollY"] return ({"height": e_height, "width": e_width, "x": x, "y": y}) - def get_gui_element_center(self, selector): + def get_gui_element_center(self, selector, timeout=None): """(Coordinates are relative to the screen. Not the window.)""" - element_rect = self.get_gui_element_rect(selector) + if not timeout: + timeout = settings.SMALL_TIMEOUT + element_rect = self.get_gui_element_rect(selector, timeout=timeout) e_width = element_rect["width"] e_height = element_rect["height"] e_x = element_rect["x"] @@ -1629,9 +1661,9 @@ def is_element_visible(self, selector): return True return False - def wait_for_element_visible( - self, selector, timeout=settings.SMALL_TIMEOUT - ): + def wait_for_element_visible(self, selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT try: self.select(selector, timeout=timeout) except Exception: @@ -1642,8 +1674,10 @@ def wait_for_element_visible( time.sleep(0.1) raise Exception("Element {%s} was not visible!" % selector) - def assert_element(self, selector, timeout=settings.SMALL_TIMEOUT): + def assert_element(self, selector, timeout=None): """Same as assert_element_visible()""" + if not timeout: + timeout = settings.SMALL_TIMEOUT try: self.select(selector, timeout=timeout) except Exception: @@ -1654,8 +1688,10 @@ def assert_element(self, selector, timeout=settings.SMALL_TIMEOUT): time.sleep(0.1) raise Exception("Element {%s} was not visible!" % selector) - def assert_element_visible(self, selector, timeout=settings.SMALL_TIMEOUT): + def assert_element_visible(self, selector, timeout=None): """Same as assert_element()""" + if not timeout: + timeout = settings.SMALL_TIMEOUT try: self.select(selector, timeout=timeout) except Exception: @@ -1666,16 +1702,20 @@ def assert_element_visible(self, selector, timeout=settings.SMALL_TIMEOUT): time.sleep(0.1) raise Exception("Element {%s} was not visible!" % selector) - def assert_element_present(self, selector, timeout=settings.SMALL_TIMEOUT): + def assert_element_present(self, selector, timeout=None): """Assert element is present in the DOM. (Visibility NOT required)""" + if not timeout: + timeout = settings.SMALL_TIMEOUT try: self.select(selector, timeout=timeout) except Exception: raise Exception("Element {%s} was not found!" % selector) return True - def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT): + def assert_element_absent(self, selector, timeout=None): """Assert element is not present in the DOM.""" + if not timeout: + timeout = settings.SMALL_TIMEOUT start_ms = time.time() * 1000.0 stop_ms = start_ms + (timeout * 1000.0) for i in range(int(timeout * 10)): @@ -1693,10 +1733,10 @@ def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT): % (selector, timeout, plural) ) - def assert_element_not_visible( - self, selector, timeout=settings.SMALL_TIMEOUT - ): + def assert_element_not_visible(self, selector, timeout=None): """Assert element is not visible on page. (May still be in DOM)""" + if not timeout: + timeout = settings.SMALL_TIMEOUT start_ms = time.time() * 1000.0 stop_ms = start_ms + (timeout * 1000.0) for i in range(int(timeout * 10)): @@ -1791,9 +1831,9 @@ def assert_url_contains(self, substring): if expected not in actual: raise Exception(error % (expected, actual)) - def assert_text( - self, text, selector="body", timeout=settings.SMALL_TIMEOUT - ): + def assert_text(self, text, selector="body", timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT start_ms = time.time() * 1000.0 stop_ms = start_ms + (timeout * 1000.0) text = text.strip() @@ -1816,9 +1856,9 @@ def assert_text( % (text, selector, element.text_all) ) - def assert_exact_text( - self, text, selector="body", timeout=settings.SMALL_TIMEOUT - ): + def assert_exact_text(self, text, selector="body", timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT start_ms = time.time() * 1000.0 stop_ms = start_ms + (timeout * 1000.0) text = text.strip() diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index d93fa380625..e8092ba0583 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -4492,7 +4492,8 @@ def save_page_source(self, name, folder=None): @Params name - The file name to save the current page's HTML to. folder - The folder to save the file to. (Default = current folder)""" - self.wait_for_ready_state_complete() + if not self.__is_cdp_swap_needed(): + self.wait_for_ready_state_complete() return page_actions.save_page_source(self.driver, name, folder) def save_cookies(self, name="cookies.txt"): @@ -4550,6 +4551,9 @@ def load_cookies(self, name="cookies.txt", expiry=False): def delete_all_cookies(self): """Deletes all cookies in the web browser. Does NOT delete the saved cookies file.""" + if self.__is_cdp_swap_needed(): + self.cdp.clear_cookies() + return self.wait_for_ready_state_complete() self.driver.delete_all_cookies() if self.recorder_mode: @@ -4561,7 +4565,6 @@ def delete_all_cookies(self): def delete_saved_cookies(self, name="cookies.txt"): """Deletes the cookies file from the "saved_cookies" folder. Does NOT delete the cookies from the web browser.""" - self.wait_for_ready_state_complete() if name.endswith("/"): raise Exception("Invalid filename for Cookies!") if "/" in name: @@ -4600,14 +4603,20 @@ def get_saved_cookies(self, name="cookies.txt"): return json.loads(json_cookies) def get_cookie(self, name): + self.__check_scope() + self._check_browser() return self.driver.get_cookie(name) def get_cookies(self): + self.__check_scope() + self._check_browser() return self.driver.get_cookies() def get_cookie_string(self): + self.__check_scope() if self.__is_cdp_swap_needed(): return self.cdp.get_cookie_string() + self._check_browser() return self.execute_script("return document.cookie;") def add_cookie(self, cookie_dict, expiry=False): @@ -4622,6 +4631,8 @@ def add_cookie(self, cookie_dict, expiry=False): If expiry > 0: Set "expiry" to expiry minutes in the future. If expiry == True: Set "expiry" to 24 hours in the future. """ + self.__check_scope() + self._check_browser() cookie = cookie_dict if "domain" in cookie: origin = self.get_origin() @@ -4646,6 +4657,8 @@ def add_cookies(self, cookies, expiry=False): If expiry > 0: Set "expiry" to expiry minutes in the future. If expiry == True: Set "expiry" to 24 hours in the future. """ + self.__check_scope() + self._check_browser() origin = self.get_origin() trim_origin = origin.split("://")[-1] for cookie in cookies: diff --git a/seleniumbase/fixtures/page_actions.py b/seleniumbase/fixtures/page_actions.py index f754ad2b334..bb5bf055f0b 100644 --- a/seleniumbase/fixtures/page_actions.py +++ b/seleniumbase/fixtures/page_actions.py @@ -1342,7 +1342,8 @@ def save_page_source(driver, name, folder=None): """ from seleniumbase.core import log_helper - _reconnect_if_disconnected(driver) + if not __is_cdp_swap_needed(driver): + _reconnect_if_disconnected(driver) # If disconnected without CDP if not name.endswith(".html"): name = name + ".html" if folder: @@ -1353,7 +1354,11 @@ def save_page_source(driver, name, folder=None): html_file_path = os.path.join(file_path, name) else: html_file_path = name - page_source = driver.page_source + page_source = None + if __is_cdp_swap_needed(driver): + page_source = driver.cdp.get_page_source() + else: + page_source = driver.page_source html_file = codecs.open(html_file_path, "w+", "utf-8") rendered_source = log_helper.get_html_source_with_base_href( driver, page_source diff --git a/setup.py b/setup.py index 8a50ea512c7..01615ed533e 100755 --- a/setup.py +++ b/setup.py @@ -152,7 +152,7 @@ 'setuptools~=70.2;python_version<"3.10"', # Newer ones had issues 'setuptools>=75.6.0;python_version>="3.10"', 'wheel>=0.45.1', - 'attrs>=24.2.0', + 'attrs>=24.3.0', "certifi>=2024.12.14", "exceptiongroup>=1.2.2", 'websockets~=13.1;python_version<"3.9"', @@ -163,7 +163,10 @@ "pynose>=1.5.3", 'platformdirs>=4.3.6', 'typing-extensions>=4.12.2', - "sbvirtualdisplay>=1.3.1", + "sbvirtualdisplay>=1.4.0", + 'MarkupSafe==2.1.5;python_version<"3.9"', + 'MarkupSafe>=3.0.2;python_version>="3.9"', + "Jinja2>=3.1.5", "six>=1.17.0", 'parse>=1.20.2', 'parse-type>=0.6.4', @@ -175,9 +178,9 @@ "pdbp>=1.6.1", "idna==3.10", 'chardet==5.2.0', - 'charset-normalizer==3.4.0', + 'charset-normalizer==3.4.1', 'urllib3>=1.26.20,<2;python_version<"3.10"', - 'urllib3>=1.26.20,<2.3.0;python_version>="3.10"', + 'urllib3>=1.26.20,<2.4.0;python_version>="3.10"', 'requests==2.32.3', 'sniffio==1.3.1', 'h11==0.14.0',