From f6737bc13f87c613c13c005cdf26e5af8e7c8c55 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Oct 2021 22:36:07 -0400 Subject: [PATCH 1/5] Refresh Recorder Mode with "codegen" and more --- seleniumbase/console_scripts/run.py | 75 +++++++++++++++------- seleniumbase/console_scripts/sb_mkfile.py | 4 +- seleniumbase/console_scripts/sb_mkrec.py | 18 ++++-- seleniumbase/extensions/recorder.zip | Bin 11494 -> 11498 bytes seleniumbase/js_code/recorder_js.py | 22 +++---- seleniumbase/plugins/pytest_plugin.py | 1 + seleniumbase/plugins/selenium_plugin.py | 1 + 7 files changed, 80 insertions(+), 41 deletions(-) diff --git a/seleniumbase/console_scripts/run.py b/seleniumbase/console_scripts/run.py index 6a2cb0c8..32e9b1f2 100644 --- a/seleniumbase/console_scripts/run.py +++ b/seleniumbase/console_scripts/run.py @@ -11,7 +11,7 @@ sbase methods sbase options sbase mkdir ui_tests sbase mkfile new_test.py -sbase mkrec new_test.py +sbase mkrec new_test.py # Same as "sbase codegen new_test.py" sbase mkpres new_presentation.py sbase mkchart new_chart.py sbase convert webdriver_unittest_file.py @@ -70,26 +70,26 @@ def show_basic_usage(): sc += ' * OR: "sbase [COMMAND] [PARAMETERS]"\n' sc += "\n" sc += "COMMANDS:\n" - sc += " install [DRIVER] [OPTIONS]\n" - sc += " methods (List common Python methods)\n" - sc += " options (List common pytest options)\n" - sc += " mkdir [DIRECTORY] [OPTIONS]\n" - sc += " mkfile [FILE.py] [OPTIONS]\n" - sc += " mkrec [FILE.py]\n" - sc += " mkpres [FILE.py] [LANG]\n" - sc += " mkchart [FILE.py] [LANG]\n" - sc += " print [FILE] [OPTIONS]\n" - sc += " translate [SB_FILE.py] [LANG] [ACTION]\n" - sc += " convert [WEBDRIVER_UNITTEST_FILE.py]\n" - sc += " extract-objects [SB_FILE.py]\n" - sc += " inject-objects [SB_FILE.py] [OPTIONS]\n" - sc += " objectify [SB_FILE.py] [OPTIONS]\n" - sc += " revert-objects [SB_FILE.py] [OPTIONS]\n" - sc += " encrypt (OR: obfuscate)\n" - sc += " decrypt (OR: unobfuscate)\n" - sc += " download server (The Selenium Grid JAR file)\n" - sc += " grid-hub [start|stop] [OPTIONS]\n" - sc += " grid-node [start|stop] --hub=[HOST/IP]\n" + sc += " install [DRIVER] [OPTIONS]\n" + sc += " methods (List common Python methods)\n" + sc += " options (List common pytest options)\n" + sc += " mkdir [DIRECTORY] [OPTIONS]\n" + sc += " mkfile [FILE.py] [OPTIONS]\n" + sc += " mkrec / codegen [FILE.py]\n" + sc += " mkpres [FILE.py] [LANG]\n" + sc += " mkchart [FILE.py] [LANG]\n" + sc += " print [FILE] [OPTIONS]\n" + sc += " translate [SB_FILE.py] [LANG] [ACTION]\n" + sc += " convert [WEBDRIVER_UNITTEST_FILE.py]\n" + sc += " extract-objects [SB_FILE.py]\n" + sc += " inject-objects [SB_FILE.py] [OPTIONS]\n" + sc += " objectify [SB_FILE.py] [OPTIONS]\n" + sc += " revert-objects [SB_FILE.py] [OPTIONS]\n" + sc += " encrypt / obfuscate\n" + sc += " decrypt / unobfuscate\n" + sc += " download server (Get Selenium Grid JAR file)\n" + sc += " grid-hub [start|stop] [OPTIONS]\n" + sc += " grid-node [start|stop] --hub=[HOST/IP]\n" sc += ' * (EXAMPLE: "sbase install chromedriver latest") *\n' sc += "" if "linux" not in sys.platform: @@ -176,7 +176,7 @@ def show_mkfile_usage(): print(" sbase mkfile new_test.py") print(" Options:") print(" -b / --basic (Basic boilerplate / single-line test)") - print(" -r / --recorder (Recorder Mode has ipdb breakpoint)") + print(" -r / --rec (adds ipdb breakpoint for Recorder Mode)") print(" Language Options:") print(" --en / --English | --zh / --Chinese") print(" --nl / --Dutch | --fr / --French") @@ -213,6 +213,24 @@ def show_mkrec_usage(): print("") +def show_codegen_usage(): + c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX + c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX + cr = colorama.Style.RESET_ALL + sc = " " + c2 + "** " + c3 + "codegen" + c2 + " **" + cr + print(sc) + print("") + print(" Usage:") + print(" seleniumbase codegen [FILE.py]") + print(" OR: sbase codegen [FILE.py]") + print(" Example:") + print(" sbase codegen new_test.py") + print(" Output:") + print(" Creates a new SeleniumBase test using the Recorder.") + print(" If the filename already exists, an error is raised.") + print("") + + def show_mkpres_usage(): c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX @@ -701,6 +719,7 @@ def show_detailed_help(): show_mkdir_usage() show_mkfile_usage() show_mkrec_usage() + show_codegen_usage() show_mkpres_usage() show_mkchart_usage() show_convert_usage() @@ -765,6 +784,14 @@ def main(): else: show_basic_usage() show_mkrec_usage() + elif command == "codegen": + if len(command_args) >= 1: + from seleniumbase.console_scripts import sb_mkrec + + sb_mkrec.main() + else: + show_basic_usage() + show_codegen_usage() elif command == "mkpres": if len(command_args) >= 1: from seleniumbase.console_scripts import sb_mkpres @@ -920,6 +947,10 @@ def main(): print("") show_mkrec_usage() return + elif command_args[0] == "codegen": + print("") + show_codegen_usage() + return elif command_args[0] == "mkpres": print("") show_mkpres_usage() diff --git a/seleniumbase/console_scripts/sb_mkfile.py b/seleniumbase/console_scripts/sb_mkfile.py index d402f21b..face2d98 100755 --- a/seleniumbase/console_scripts/sb_mkfile.py +++ b/seleniumbase/console_scripts/sb_mkfile.py @@ -11,7 +11,7 @@ Example: Options: -b / --basic (Basic boilerplate / single-line test) - -r / --recorder (Recorder Mode has ipdb breakpoint) + -r / --rec (adds ipdb breakpoint for Recorder Mode) Language Options: --en / --English | --zh / --Chinese @@ -46,7 +46,7 @@ def invalid_run_command(msg=None): exp += " sbase mkfile new_test.py\n" exp += " Options:\n" exp += " -b / --basic (Basic boilerplate / single-line test)\n" - exp += " -r / --recorder (Recorder Mode has ipdb breakpoint)\n" + exp += " -r / --rec (adds ipdb breakpoint for Recorder Mode)\n" exp += " Language Options:\n" exp += " --en / --English | --zh / --Chinese\n" exp += " --nl / --Dutch | --fr / --French\n" diff --git a/seleniumbase/console_scripts/sb_mkrec.py b/seleniumbase/console_scripts/sb_mkrec.py index 8dc00577..0bbda8be 100755 --- a/seleniumbase/console_scripts/sb_mkrec.py +++ b/seleniumbase/console_scripts/sb_mkrec.py @@ -3,11 +3,14 @@ Creates a new SeleniumBase test file using the Recorder. Usage: - seleniumbase mkrec [FILE.py] - or sbase mkrec [FILE.py] + seleniumbase mkrec [FILE.py] + sbase mkrec [FILE.py] + seleniumbase codegen [FILE.py] + sbase codegen [FILE.py] -Example: +Examples: sbase mkrec new_test.py + sbase codegen new_test.py Output: Creates a new SeleniumBase test using the Recorder. @@ -22,12 +25,15 @@ import sys def invalid_run_command(msg=None): - exp = " ** mkrec **\n\n" + exp = " ** mkrec / codegen **\n\n" exp += " Usage:\n" exp += " seleniumbase mkrec [FILE.py]\n" - exp += " OR sbase mkrec [FILE.py]\n" - exp += " Example:\n" + exp += " sbase mkrec [FILE.py]\n" + exp += " seleniumbase codegen [FILE.py]\n" + exp += " sbase codegen [FILE.py]\n" + exp += " Examples:\n" exp += " sbase mkrec new_test.py\n" + exp += " sbase codegen new_test.py\n" exp += " Output:\n" exp += " Creates a new SeleniumBase test using the Recorder.\n" exp += " If the filename already exists, an error is raised.\n" diff --git a/seleniumbase/extensions/recorder.zip b/seleniumbase/extensions/recorder.zip index 0995489f9fbbaef2fa31179411dc281ae170396b..cbf3999f5f35f69e128bd26ffef27c5c1b8c51c7 100644 GIT binary patch delta 5266 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 PdN!)b0RSG*`RxAys3EDN diff --git a/seleniumbase/js_code/recorder_js.py b/seleniumbase/js_code/recorder_js.py index c52ac918..bd2b8598 100755 --- a/seleniumbase/js_code/recorder_js.py +++ b/seleniumbase/js_code/recorder_js.py @@ -606,7 +606,7 @@ document.body.addEventListener('mouseup', function (event) { else if (ra_len > 0 && document.recorded_actions[ra_len-1][0] === 'mo_dn') { - // Probably an accidental drag & drop. + // Maybe an accidental drag & drop. document.recorded_actions.pop(); } json_rec_act = JSON.stringify(document.recorded_actions); @@ -642,14 +642,15 @@ document.body.addEventListener('keydown', function (event) { }); document.body.addEventListener('keyup', function (event) { reset_if_recorder_undefined(); - // Controls for Pausing & Resuming. + // Controls to Pause & Resume. pause_rec = sessionStorage.getItem('pause_recorder'); - if (event.key.toLowerCase() === 'escape' && pause_rec === 'no') + rec_mode = sessionStorage.getItem('recorder_mode'); + l_key = event.key.toLowerCase(); + if (l_key === 'escape' && pause_rec === 'no' && rec_mode === '1') { sessionStorage.setItem('pause_recorder', 'yes'); pause_rec = 'yes'; - sessionStorage.setItem('recorder_mode', '1'); - console.log('The SeleniumBase Recorder has paused.'); + console.log('SeleniumBase Recorder paused'); no_border = 'none'; document.querySelector('body').style.border = no_border; document.title = sessionStorage.getItem('recorder_title'); @@ -658,15 +659,14 @@ document.body.addEventListener('keyup', function (event) { { sessionStorage.setItem('pause_recorder', 'no'); pause_rec = 'no'; - sessionStorage.setItem('recorder_mode', '1'); - console.log('The SeleniumBase Recorder has resumed.'); + console.log('SeleniumBase Recorder resumed'); red_border = 'thick solid #EE3344'; document.querySelector('body').style.border = red_border; } else if (event.key === '^' && pause_rec === 'no') { sessionStorage.setItem('recorder_mode', '2'); - purple_border = 'thick solid #BF40BF'; + purple_border = 'thick solid #EF5BE9'; document.querySelector('body').style.border = purple_border; } else if (event.key === '&' && pause_rec === 'no') @@ -675,13 +675,13 @@ document.body.addEventListener('keyup', function (event) { orange_border = 'thick solid #F28C28'; document.querySelector('body').style.border = orange_border; } - else if (pause_rec === 'no' && event.key.toLowerCase() !== 'shift') + else if (pause_rec === 'no' && l_key !== 'shift' && l_key !== 'backspace') { sessionStorage.setItem('recorder_mode', '1'); red_border = 'thick solid #EE3344'; document.querySelector('body').style.border = red_border; } - // After checking for pause/resume controls. + // After controls for switching modes. if (sessionStorage.getItem('pause_recorder') === 'yes') return; const d_now = Date.now(); const element = event.target; @@ -692,7 +692,7 @@ document.body.addEventListener('keyup', function (event) { element.tagName.toLowerCase() === 'textarea') { ra_len = document.recorded_actions.length; - if (ra_len > 0 && event.key.toLowerCase() === 'enter' && + if (ra_len > 0 && l_key === 'enter' && document.recorded_actions[ra_len-1][0] === 'input' && document.recorded_actions[ra_len-1][1] === selector && !document.recorded_actions[ra_len-1][2].endsWith('\n')) diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py index 8a2b657f..85389ea9 100644 --- a/seleniumbase/plugins/pytest_plugin.py +++ b/seleniumbase/plugins/pytest_plugin.py @@ -660,6 +660,7 @@ def pytest_addoption(parser): "--recorder", "--record", "--rec", + "--codegen", action="store_true", dest="recorder_mode", default=False, diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index 07e3122f..ad84ca79 100755 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -421,6 +421,7 @@ class SeleniumBrowser(Plugin): "--recorder", "--record", "--rec", + "--codegen", action="store_true", dest="recorder_mode", default=False, From e28f37b29b0f80786afaa4b02249cfd8ee5efbf7 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Oct 2021 22:39:08 -0400 Subject: [PATCH 2/5] Update code related to deprecated methods --- seleniumbase/common/decorators.py | 13 +++++++------ seleniumbase/fixtures/base_case.py | 7 ++----- seleniumbase/fixtures/js_utils.py | 2 -- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/seleniumbase/common/decorators.py b/seleniumbase/common/decorators.py index 9f95eca7..8b94df0d 100755 --- a/seleniumbase/common/decorators.py +++ b/seleniumbase/common/decorators.py @@ -1,8 +1,6 @@ -import inspect import logging import math import sys -import threading import time import warnings from functools import wraps @@ -55,6 +53,8 @@ def rate_limited(max_per_second): If the limit is exceeded, the call will be held in a queue until enough time has passed. Useful when trying to avoid overloading a system with rapid calls.""" + import threading + min_interval = 1.0 / float(max_per_second) def decorate(func): @@ -88,13 +88,14 @@ def rate_limited(max_per_second): def deprecated(message=None): """This decorator marks methods as deprecated. A warning is displayed if the method is called.""" + import inspect def decorated_method_to_deprecate(func): if inspect.isclass(func): # Handle a deprecated class differently from a deprecated method - msg = "Class {}() is DEPRECATED! *** ".format(func.__name__) + msg = "Class {}() is DEPRECATED!".format(func.__name__) if message: - msg += "<> %s <>" % message + msg += " *** %s ***" % message warnings.simplefilter("always", DeprecationWarning) # See Warnings warnings.warn(msg, category=DeprecationWarning, stacklevel=2) warnings.simplefilter("default", DeprecationWarning) # Set Default @@ -102,9 +103,9 @@ def deprecated(message=None): @wraps(func) def new_func(*args, **kwargs): - msg = "Method {}() is DEPRECATED! *** ".format(func.__name__) + msg = "Method {}() is DEPRECATED!".format(func.__name__) if message: - msg += "<> %s <>" % message + msg += " *** %s ***" % message warnings.simplefilter("always", DeprecationWarning) # See Warnings warnings.warn(msg, category=DeprecationWarning, stacklevel=2) warnings.simplefilter("default", DeprecationWarning) # Set Default diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 4a969a7e..6f2a96ab 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -10095,12 +10095,9 @@ class BaseCase(unittest.TestCase): from seleniumbase.common import decorators - # Deprecated Methods (Replace these if they're still in your code!) - @decorators.deprecated( - "jq_format() is deprecated. Use re.escape() instead!" - ) + @decorators.deprecated("You should use re.escape() instead.") def jq_format(self, code): - # DEPRECATED - re.escape() already performs the intended action! + # DEPRECATED - re.escape() already performs the intended action. return js_utils._jq_format(code) ############ diff --git a/seleniumbase/fixtures/js_utils.py b/seleniumbase/fixtures/js_utils.py index 0176a149..1f8c7372 100755 --- a/seleniumbase/fixtures/js_utils.py +++ b/seleniumbase/fixtures/js_utils.py @@ -8,7 +8,6 @@ import time from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from seleniumbase import config as sb_config -from seleniumbase.common import decorators from seleniumbase.config import settings from seleniumbase.fixtures import constants from seleniumbase.fixtures import shared_utils @@ -976,7 +975,6 @@ def clear_out_console_logs(driver): pass -@decorators.deprecated("Use re.escape() instead, which does what you want!") def _jq_format(code): """ DEPRECATED - Use re.escape() instead, which performs the intended action. From 5a2eac4c160897f595238a52c869eb9344e9fe21 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Oct 2021 22:40:08 -0400 Subject: [PATCH 3/5] Move the position of an import statement --- seleniumbase/core/proxy_helper.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seleniumbase/core/proxy_helper.py b/seleniumbase/core/proxy_helper.py index 3e796357..869f5c99 100755 --- a/seleniumbase/core/proxy_helper.py +++ b/seleniumbase/core/proxy_helper.py @@ -1,5 +1,4 @@ import os -import threading import zipfile from seleniumbase.fixtures import constants @@ -65,6 +64,8 @@ def create_proxy_zip(proxy_string, proxy_user, proxy_pass): """"minimum_chrome_version":"22.0.0"\n""" """}""" ) + import threading + lock = threading.RLock() # Support multi-threaded test runs with Pytest with lock: abs_path = os.path.abspath(".") From 8cd85d6a53d92b116b7c977cda588c81e7503e31 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Oct 2021 22:40:56 -0400 Subject: [PATCH 4/5] Update the docs --- README.md | 98 ++++++++++++++------------ docs/requirements.txt | 2 +- help_docs/recorder_mode.md | 4 +- help_docs/verify_webdriver.md | 31 +++++++- help_docs/webdriver_installation.md | 7 ++ seleniumbase/console_scripts/ReadMe.md | 48 +++++++------ 6 files changed, 120 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 64ff7f0f..6e75e7f6 100755 --- a/README.md +++ b/README.md @@ -134,30 +134,31 @@ pip install seleniumbase * OR: "sbase [COMMAND] [PARAMETERS]" COMMANDS: - install [DRIVER] [OPTIONS] - methods (List common Python methods) - options (List common pytest options) - mkdir [DIRECTORY] [OPTIONS] - mkfile [FILE.py] [OPTIONS] - mkpres [FILE.py] [LANG] - mkchart [FILE.py] [LANG] - print [FILE] [OPTIONS] - translate [SB_FILE.py] [LANG] [ACTION] - convert [WEBDRIVER_UNITTEST_FILE.py] - extract-objects [SB_FILE.py] - inject-objects [SB_FILE.py] [OPTIONS] - objectify [SB_FILE.py] [OPTIONS] - revert-objects [SB_FILE.py] [OPTIONS] - encrypt (OR: obfuscate) - decrypt (OR: unobfuscate) - download server (The Selenium Grid JAR file) - grid-hub [start|stop] [OPTIONS] - grid-node [start|stop] --hub=[HOST/IP] - * (EXAMPLE: "sbase install chromedriver latest") * + install [DRIVER] [OPTIONS] + methods (List common Python methods) + options (List common pytest options) + mkdir [DIRECTORY] [OPTIONS] + mkfile [FILE.py] [OPTIONS] + mkrec / codegen [FILE.py] + mkpres [FILE.py] [LANG] + mkchart [FILE.py] [LANG] + print [FILE] [OPTIONS] + translate [SB_FILE.py] [LANG] [ACTION] + convert [WEBDRIVER_UNITTEST_FILE.py] + extract-objects [SB_FILE.py] + inject-objects [SB_FILE.py] [OPTIONS] + objectify [SB_FILE.py] [OPTIONS] + revert-objects [SB_FILE.py] [OPTIONS] + encrypt / obfuscate + decrypt / unobfuscate + download server (Get Selenium Grid JAR file) + grid-hub [start|stop] [OPTIONS] + grid-node [start|stop] --hub=[HOST/IP] + * (EXAMPLE: "sbase install chromedriver latest") * Type "sbase help [COMMAND]" for specific command info. For info on all commands, type: "seleniumbase --help". - * (Use "pytest" for running tests) * + Use "pytest" for running tests. ```

Download a webdriver:

@@ -213,26 +214,38 @@ pytest my_first_test.py --demo * Here are some common ``SeleniumBase`` methods that you might find in tests: ```python -self.open(URL) # Navigate to the web page -self.click(SELECTOR) # Click a page element -self.type(SELECTOR, TEXT) # Type text (Add "\n" to text for pressing enter/return.) -self.assert_element(SELECTOR) # Assert element is visible -self.assert_text(TEXT) # Assert text is visible (has optional SELECTOR arg) -self.assert_title(PAGE_TITLE) # Assert page title -self.assert_no_404_errors() # Assert no 404 errors from files on the page -self.assert_no_js_errors() # Assert no JavaScript errors on the page (Chrome-ONLY) -self.execute_script(JAVASCRIPT) # Execute JavaScript code -self.go_back() # Navigate to the previous URL -self.get_text(SELECTOR) # Get text from a selector -self.get_attribute(SELECTOR, ATTRIBUTE) # Get a specific attribute from a selector -self.is_element_visible(SELECTOR) # Determine if an element is visible on the page -self.is_text_visible(TEXT) # Determine if text is visible on the page (optional SELECTOR) -self.hover_and_click(HOVER_SELECTOR, CLICK_SELECTOR) # Mouseover element & click another -self.select_option_by_text(DROPDOWN_SELECTOR, OPTION_TEXT) # Select a dropdown option -self.switch_to_frame(FRAME_NAME) # Switch webdriver control to an iframe on the page -self.switch_to_default_content() # Switch webdriver control out of the current iframe -self.switch_to_window(WINDOW_NUMBER) # Switch to a different window/tab -self.save_screenshot(FILE_NAME) # Save a screenshot of the current page +self.open(url) # Navigate the browser window to the URL. +self.type(selector, text) # Update the field with the text. +self.click(selector) # Click the element with the selector. +self.click_link(link_text) # Click the link containing text. +self.go_back() # Navigate back to the previous URL. +self.select_option_by_text(dropdown_selector, option) +self.hover_and_click(hover_selector, click_selector) +self.drag_and_drop(drag_selector, drop_selector) +self.get_text(selector) # Get the text from the element. +self.get_current_url() # Get the URL of the current page. +self.get_page_source() # Get the HTML of the current page. +self.get_attribute(selector, attribute) # Get element attribute. +self.get_title() # Get the title of the current page. +self.switch_to_frame(frame) # Switch into the iframe container. +self.switch_to_default_content() # Leave the iframe container. +self.open_new_window() # Open a new window in the same browser. +self.switch_to_window(window) # Switch to the browser window. +self.switch_to_default_window() # Switch to the original window. +self.get_new_driver(OPTIONS) # Open a new driver with OPTIONS. +self.switch_to_driver(driver) # Switch to the browser driver. +self.switch_to_default_driver() # Switch to the original driver. +self.wait_for_element(selector) # Wait until element is visible. +self.is_element_visible(selector) # Return element visibility. +self.is_text_visible(text, selector) # Return text visibility. +self.sleep(seconds) # Do nothing for the given amount of time. +self.save_screenshot(name) # Save a screenshot in .png format. +self.assert_element(selector) # Verify the element is visible. +self.assert_text(text, selector) # Verify text in the element. +self.assert_title(title) # Verify the title of the web page. +self.assert_downloaded_file(file) # Verify file was downloaded. +self.assert_no_404_errors() # Verify there are no broken links. +self.assert_no_js_errors() # Verify there are no JS errors. ``` 🔵 For the complete list of SeleniumBase methods, see: Method Summary @@ -436,7 +449,6 @@ sbase mkdir ui_tests ```bash ui_tests/ -│ ├── __init__.py ├── my_first_test.py ├── parameterized_test.py @@ -445,7 +457,6 @@ ui_tests/ ├── setup.cfg ├── test_demo_site.py └── boilerplates/ - │ ├── __init__.py ├── base_test_case.py ├── boilerplate_test.py @@ -453,7 +464,6 @@ ui_tests/ ├── page_objects.py ├── sb_fixture_test.py └── samples/ - │ ├── __init__.py ├── google_objects.py ├── google_test.py diff --git a/docs/requirements.txt b/docs/requirements.txt index 108bbe40..c1a9d474 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -regex>=2021.10.8 +regex>=2021.10.21 tqdm>=4.62.3 livereload==2.6.3;python_version>="3.6" joblib==1.1.0;python_version>="3.6" diff --git a/help_docs/recorder_mode.md b/help_docs/recorder_mode.md index 1ec0f0f6..84dec0bf 100755 --- a/help_docs/recorder_mode.md +++ b/help_docs/recorder_mode.md @@ -70,7 +70,7 @@ class RecorderTest(BaseCase):

🔴 SeleniumBase 1.66.12 adds the ability to instantly create a new test recording by running sbase mkrec FILE.py. Once the browser spins up, you can open a new web page and start performing actions that will get recorded and saved to the file you specified.

-

🔴 SeleniumBase 1.66.13 lets you add assertions for elements and text while making a recording. To add an element assertion, press the [^]-key (SHIFT+6), (the border will become purple) then click on elements that you'd like to assert. To add a text assertion, press the [&]-key (SHIFT+7), (the border will become orange) then click on text elements that you'd like to assert. To go back to the regular Record Mode, press any other key. While in the special assertion modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without certain actions getting in the way.

+

🔴 SeleniumBase 1.66.13 lets you add assertions for elements and text while making a recording. To add an element assertion, press the {^}-key (SHIFT+6), (the border will become purple) then click on elements that you'd like to assert. To add a text assertion, press the {&}-key (SHIFT+7), (the border will become orange) then click on text elements that you'd like to assert. To go back to the regular Record Mode, press any other key. While in the special assertion modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without certain actions getting in the way.

🔴 SeleniumBase 1.66.14 improves the algorithm for converting recorded assertions into SeleniumBase code. Text assertions that contain the newline character will now be handled correctly. If a text assertion has a :contains selector, then the text assertion will be changed to an element assertion. Asserted text from multi-line assertions will use self.assert_text() on the first non-empty line. Asserted text from single-line assertions will use self.assert_exact_text(). Element assertions will be handled with self.assert_element().

@@ -78,6 +78,8 @@ class RecorderTest(BaseCase):

🔴 SeleniumBase 2.0.2 fixes a bug with Recorder Mode that was preventing the last recorded assert on a domain from being saved unless it was followed by a non-assert recorded action on the same domain.

+

🔴 SeleniumBase 2.0.4 lets you go back to regular Recorder Mode from Assert Mode by pressing [ESC] once. If you press it again, it will pause the Recorder. (Previously, pressing [ESC] would pause the Recorder right away if using Assert Mode). As before, pressing the {^}-key (SHIFT+6) will switch the Recorder into Assert Element Mode and pressing the {&}-key (SHIFT+7) will switch the Recorder into Assert Text Mode. You can switch back to regular Recorder Mode from Assert Mode by pressing any key other than [SHIFT] and [BACKSPACE]. Also, --codegen can be used in place of --recorder for Recorder initialization, and sbase codegen [FILE.py] can be used in place of sbase mkrec [FILE.py], which calls attention to the code-generation abilities of the Recorder.

+ --------
To learn more about SeleniumBase, check out the Docs Site:
diff --git a/help_docs/verify_webdriver.md b/help_docs/verify_webdriver.md index 388dbb9d..8fdb51d4 100755 --- a/help_docs/verify_webdriver.md +++ b/help_docs/verify_webdriver.md @@ -1,11 +1,36 @@ ## Verifying that web drivers are installed -*You can do this by checking inside a Python command prompt.* +On newer versions of SeleniumBase, the driver is automatically downloaded to the ``seleniumbase/drivers`` folder, and does not need to be on the System Path when running tests. + +Drivers can be manually downloaded with commands such as: + +```bash +sbase install chromedriver +sbase install chromedriver latest +sbase install geckodriver +sbase install edgedriver +``` + +-------- + +If you want to check that you have the correct driver installed on your System PATH (which is no longer necessary unless using the Selenium Grid), then continue reading below: + +*This assumes you've already downloaded a driver to your **System PATH** with a command such as:* + +```bash +sbase install chromedriver --path +``` + +(The above ``--path`` addition is for Linux/Mac only, which uses ``/usr/local/bin/``. The "Path" is different on Windows, and you'll need to manually copy the driver to your System Path, which is defined in the Control Panel's System Environment Variables.) + +*You can verify that the correct drivers exist on your System Path by checking inside a Python command prompt.* #### Verifying ChromeDriver + ```bash python ``` + ```python >>> from selenium import webdriver >>> driver = webdriver.Chrome() @@ -15,9 +40,11 @@ python ``` #### Verifying Geckodriver (Firefox WebDriver) + ```bash python ``` + ```python >>> from selenium import webdriver >>> driver = webdriver.Firefox() @@ -27,9 +54,11 @@ python ``` #### Verifying WebDriver for Safari + ```bash python ``` + ```python >>> from selenium import webdriver >>> driver = webdriver.Safari() diff --git a/help_docs/webdriver_installation.md b/help_docs/webdriver_installation.md index ca93841b..ab87d76e 100755 --- a/help_docs/webdriver_installation.md +++ b/help_docs/webdriver_installation.md @@ -26,6 +26,13 @@ sbase install chromedriver 88.0.4324.96 sbase install chromedriver 88 ``` +* You can run the following two commands on Mac/Linux (once you've installed SeleniumBase) to automatically upgrade your Chromedriver to match your version of Chrome: (``wget`` downloads the file, and ``pytest`` runs it.) + +```bash +wget https://raw.githubusercontent.com/seleniumbase/SeleniumBase/master/examples/upgrade_chromedriver.py +pytest upgrade_chromedriver.py -s +``` + If you plan on using the [Selenium Grid integration](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/utilities/selenium_grid/ReadMe.md) (which allows for remote webdriver), you'll need to put the drivers on your System PATH. On macOS and Linux, ``/usr/local/bin`` is a good PATH spot. On Windows, you may need to set the System PATH under Environment Variables to include the location where you placed the driver files. As a shortcut, you could place the driver files into your Python ``Scripts/`` folder in the location where you have Python installed, which should already be on your System PATH. Here's where you can go to manually install web drivers from the source: diff --git a/seleniumbase/console_scripts/ReadMe.md b/seleniumbase/console_scripts/ReadMe.md index ef4b7edd..dd41aed2 100755 --- a/seleniumbase/console_scripts/ReadMe.md +++ b/seleniumbase/console_scripts/ReadMe.md @@ -14,26 +14,26 @@ SeleniumBase console scripts help you get things done more easily, such as insta ``` COMMANDS: - install [DRIVER] [OPTIONS] - methods (List common Python methods) - options (List common pytest options) - mkdir [DIRECTORY] [OPTIONS] - mkfile [FILE.py] [OPTIONS] - mkrec [FILE.py] - mkpres [FILE.py] [LANG] - mkchart [FILE.py] [LANG] - print [FILE] [OPTIONS] - translate [SB_FILE.py] [LANG] [ACTION] - convert [WEBDRIVER_UNITTEST_FILE.py] - extract-objects [SB_FILE.py] - inject-objects [SB_FILE.py] [OPTIONS] - objectify [SB_FILE.py] [OPTIONS] - revert-objects [SB_FILE.py] [OPTIONS] - encrypt (OR: obfuscate) - decrypt (OR: unobfuscate) - download server (The Selenium Grid JAR file) - grid-hub [start|stop] [OPTIONS] - grid-node [start|stop] --hub=[HOST/IP] + install [DRIVER] [OPTIONS] + methods (List common Python methods) + options (List common pytest options) + mkdir [DIRECTORY] [OPTIONS] + mkfile [FILE.py] [OPTIONS] + mkrec / codegen [FILE.py] + mkpres [FILE.py] [LANG] + mkchart [FILE.py] [LANG] + print [FILE] [OPTIONS] + translate [SB_FILE.py] [LANG] [ACTION] + convert [WEBDRIVER_UNITTEST_FILE.py] + extract-objects [SB_FILE.py] + inject-objects [SB_FILE.py] [OPTIONS] + objectify [SB_FILE.py] [OPTIONS] + revert-objects [SB_FILE.py] [OPTIONS] + encrypt / obfuscate + decrypt / unobfuscate + download server (Get Selenium Grid JAR file) + grid-hub [start|stop] [OPTIONS] + grid-node [start|stop] --hub=[HOST/IP] * (EXAMPLE: "sbase install chromedriver latest") * Type "sbase help [COMMAND]" for specific command info. @@ -203,7 +203,7 @@ ui_tests/ * Options: ``-b`` / ``--basic`` (Basic boilerplate / single-line test) -``-r`` / ``--recorder`` (Recorder Mode has ipdb breakpoint) +``-r`` / ``--rec`` (adds ipdb breakpoint for Recorder Mode) * Language Options: ``--en`` / ``--English`` | ``--zh`` / ``--Chinese`` @@ -222,13 +222,15 @@ methods, which are "open", "type", "click", basic boilerplate option, only the "open" method is included. -

mkrec

+

mkrec / codegen

* Usage: ``sbase mkrec [FILE.py]`` +``sbase codegen [FILE.py]`` -* Example: +* Examples: ``sbase mkrec new_test.py`` +``sbase codegen new_test.py`` * Output: Creates a new SeleniumBase test using the Recorder. From 1ccb89b492185a41512ebbe663b6bafd3d3ca5ba Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Oct 2021 22:41:25 -0400 Subject: [PATCH 5/5] Version 2.0.4 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 0ae9b1d8..b8c71818 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "2.0.3" +__version__ = "2.0.4"