diff --git a/examples/run_my_first_test_in_chrome.sh b/examples/run_my_first_test_in_chrome.sh deleted file mode 100755 index 35fcb79706d..00000000000 --- a/examples/run_my_first_test_in_chrome.sh +++ /dev/null @@ -1 +0,0 @@ -nosetests my_first_test.py --browser=chrome --logging-level=INFO -s \ No newline at end of file diff --git a/examples/run_my_first_test_in_firefox.sh b/examples/run_my_first_test_in_firefox.sh deleted file mode 100755 index 6454764ba4c..00000000000 --- a/examples/run_my_first_test_in_firefox.sh +++ /dev/null @@ -1 +0,0 @@ -nosetests my_first_test.py --browser=firefox --logging-level=INFO -s \ No newline at end of file diff --git a/examples/run_rate_limiting_test.sh b/examples/run_rate_limiting_test.sh deleted file mode 100755 index bb8fb46ace3..00000000000 --- a/examples/run_rate_limiting_test.sh +++ /dev/null @@ -1 +0,0 @@ -nosetests rate_limiting_test.py -s \ No newline at end of file diff --git a/examples/run_test_fail_with_logging.sh b/examples/run_test_fail_with_logging.sh deleted file mode 100755 index 25f8420b3ef..00000000000 --- a/examples/run_test_fail_with_logging.sh +++ /dev/null @@ -1 +0,0 @@ -nosetests test_fail.py --with-testing_base \ No newline at end of file diff --git a/examples/swag_labs_suite.py b/examples/swag_labs_suite.py new file mode 100755 index 00000000000..6c9b8d98265 --- /dev/null +++ b/examples/swag_labs_suite.py @@ -0,0 +1,89 @@ +import pytest +from parameterized import parameterized +from seleniumbase import BaseCase + + +class SwagLabsTests(BaseCase): + + def login(self, user="standard_user"): + """ Login to Swag Labs and assert that the login was successful. """ + if user not in (["standard_user", "problem_user"]): + raise Exception("Invalid user!") + self.open("https://www.saucedemo.com/") + self.update_text("#user-name", user) + self.update_text("#password", "secret_sauce") + self.click('input[type="submit"]') + self.assert_text("Products", "div.product_label") + self.assert_element("#inventory_container") + + @parameterized.expand([ + ["standard_user"], + ["problem_user"], + ]) + @pytest.mark.run(order=1) + def test_swag_labs_basic_functional_flow(self, user): + """ This test checks for basic functional flow in the Swag Labs store. + The test is parameterized, and receives the user to use for login. + """ + self.login(user) + + # Verify that the "Test.allTheThings() T-Shirt" appears on the page + item_name = "Test.allTheThings() T-Shirt" + self.assert_text(item_name) + + # Verify that a reverse-alphabetical sort works as expected + self.select_option_by_value("select.product_sort_container", "za") + if item_name not in self.get_text("div.inventory_item"): + raise Exception('Sort Failed! Expecting "%s" on top!' % item_name) + + # Add the "Test.allTheThings() T-Shirt" to the cart + self.assert_exact_text("ADD TO CART", "button.btn_inventory") + item_price = self.get_text("div.inventory_item_price") + self.click("button.btn_inventory") + self.assert_exact_text("REMOVE", "button.btn_inventory") + self.assert_exact_text("1", "span.shopping_cart_badge") + + # Verify your cart + self.click("#shopping_cart_container path") + self.assert_exact_text("Your Cart", "div.subheader") + self.assert_text(item_name, "div.inventory_item_name") + self.assert_exact_text("1", "div.cart_quantity") + self.assert_exact_text("REMOVE", "button.cart_button") + self.assert_element("link=CONTINUE SHOPPING") + + # Checkout - Add info + self.click("link=CHECKOUT") + self.assert_exact_text("Checkout: Your Information", "div.subheader") + self.assert_element("a.cart_cancel_link") + self.update_text("#first-name", "SeleniumBase") + self.update_text("#last-name", "Rocks") + self.update_text("#postal-code", "01720") + + # Checkout - Overview + self.click('input.btn_primary') + self.assert_exact_text("Checkout: Overview", "div.subheader") + self.assert_element("link=CANCEL") + self.assert_text(item_name, "div.inventory_item_name") + self.assert_text(item_price, "div.inventory_item_price") + self.assert_exact_text("1", "div.summary_quantity") + + # Finish Checkout and verify item is no longer in cart + self.click("link=FINISH") + self.assert_exact_text("THANK YOU FOR YOUR ORDER", "h2") + self.assert_element("div.pony_express") + self.click("#shopping_cart_container path") + self.assert_element_absent("div.inventory_item_name") + self.click("link=CONTINUE SHOPPING") + self.assert_element_absent("span.shopping_cart_badge") + + @parameterized.expand([ + ["standard_user"], + ["problem_user"], + ]) + @pytest.mark.run(order=2) + def test_swag_labs_products_page_resource_verification(self, user): + """ This test checks for 404 errors on the Swag Labs products page. + The test is parameterized, and receives the user to use for login. + """ + self.login(user) + self.assert_no_404_errors() diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index ebae3046210..f99da23ece3 100755 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -176,7 +176,9 @@ self.get_unique_links() self.get_link_status_code(link, allow_redirects=False, timeout=5) -self.assert_no_404_errors() +self.assert_link_status_code_is_not_404(link) + +self.assert_no_404_errors(multithreaded=True) self.print_unique_links_with_status_codes() diff --git a/requirements.txt b/requirements.txt index 072a11eeee3..24d046abc8b 100755 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ pytest-html>=1.20.0 pytest-metadata>=1.8.0 pytest-rerunfailures>=7.0 pytest-xdist>=1.28.0 +pytest-ordering>=0.6 parameterized>=0.7.0 beautifulsoup4>=4.6.0 colorama==0.4.1 diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 9c83733f2ac..9e0d892736a 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1640,14 +1640,24 @@ def get_link_status_code(self, link, allow_redirects=False, timeout=5): link, allow_redirects=allow_redirects, timeout=timeout) return status_code - def assert_no_404_errors(self): + def assert_link_status_code_is_not_404(self, link): + status_code = str(self.get_link_status_code(link)) + bad_link_str = 'Error: "%s" returned a 404!' % link + self.assert_not_equal(status_code, "404", bad_link_str) + + def assert_no_404_errors(self, multithreaded=True): """ Assert no 404 errors from page links obtained from: "a"->"href", "img"->"src", "link"->"href", and "script"->"src". """ links = self.get_unique_links() - for link in links: - status_code = str(self.get_link_status_code(link)) - bad_link_str = 'Error: "%s" returned a 404!' % link - self.assert_not_equal(status_code, "404", bad_link_str) + if multithreaded: + from multiprocessing.dummy import Pool as ThreadPool + pool = ThreadPool(10) + pool.map(self.assert_link_status_code_is_not_404, links) + pool.close() + pool.join() + else: + for link in links: + self.assert_link_status_code_is_not_404(link) def print_unique_links_with_status_codes(self): """ Finds all unique links in the html of the page source @@ -3031,6 +3041,7 @@ def __highlight_with_assert_success( except Exception: # Don't highlight if can't convert to CSS_SELECTOR return + self.__slow_scroll_to_element(element) o_bs = '' # original_box_shadow style = element.get_attribute('style') diff --git a/seleniumbase/fixtures/page_utils.py b/seleniumbase/fixtures/page_utils.py index b5c54f9e257..257ef666485 100755 --- a/seleniumbase/fixtures/page_utils.py +++ b/seleniumbase/fixtures/page_utils.py @@ -116,8 +116,12 @@ def _get_unique_links(page_url, soup): link = prefix + link elif link.startswith('/'): link = full_base_url + link + elif link.startswith('./'): + link = full_base_url + link[1:] elif link.startswith('#'): link = full_base_url + link + elif '//' not in link: + link = full_base_url + "/" + link else: pass unique_links.append(link) diff --git a/setup.py b/setup.py index 1fc0b89210b..f60449810cb 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( name='seleniumbase', - version='1.23.2', + version='1.23.3', description='Reliable Browser Automation & Testing Framework', long_description=long_description, long_description_content_type='text/markdown', @@ -68,6 +68,7 @@ 'pytest-metadata>=1.8.0', 'pytest-rerunfailures>=7.0', 'pytest-xdist>=1.28.0', + 'pytest-ordering>=0.6', 'parameterized>=0.7.0', 'beautifulsoup4>=4.6.0', # Keep at >=4.6.0 while using bs4 'colorama==0.4.1',