Skip to content

Add multithreading to link checking; and other improvements #318

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/run_my_first_test_in_chrome.sh

This file was deleted.

1 change: 0 additions & 1 deletion examples/run_my_first_test_in_firefox.sh

This file was deleted.

1 change: 0 additions & 1 deletion examples/run_rate_limiting_test.sh

This file was deleted.

1 change: 0 additions & 1 deletion examples/run_test_fail_with_logging.sh

This file was deleted.

89 changes: 89 additions & 0 deletions examples/swag_labs_suite.py
Original file line number Diff line number Diff line change
@@ -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()
4 changes: 3 additions & 1 deletion help_docs/method_summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 16 additions & 5 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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')
Expand Down
4 changes: 4 additions & 0 deletions seleniumbase/fixtures/page_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down