Merge pull request #364 from seleniumbase/updates-and-fixes
Updates and fixes
This commit is contained in:
commit
78bbf830d8
|
@ -230,6 +230,9 @@ self.hover_on_element(selector, by=By.CSS_SELECTOR)
|
||||||
self.hover_and_click(hover_selector, click_selector,
|
self.hover_and_click(hover_selector, click_selector,
|
||||||
hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)
|
hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)
|
||||||
|
|
||||||
|
self.hover_and_double_click(hover_selector, click_selector,
|
||||||
|
hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)
|
||||||
|
|
||||||
self.select_option_by_text(dropdown_selector, option,
|
self.select_option_by_text(dropdown_selector, option,
|
||||||
dropdown_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)
|
dropdown_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pip>=19.2.2
|
pip>=19.2.3
|
||||||
setuptools>=41.1.0
|
setuptools>=41.2.0
|
||||||
wheel>=0.33.4
|
wheel>=0.33.6
|
||||||
six>=1.12.0
|
six>=1.12.0
|
||||||
nose>=1.3.7
|
nose>=1.3.7
|
||||||
ipdb>=0.12.2
|
ipdb>=0.12.2
|
||||||
|
@ -11,7 +11,7 @@ requests>=2.22.0
|
||||||
selenium==3.141.0
|
selenium==3.141.0
|
||||||
pluggy>=0.12.0
|
pluggy>=0.12.0
|
||||||
pytest>=4.6.5;python_version<"3"
|
pytest>=4.6.5;python_version<"3"
|
||||||
pytest>=5.1.0;python_version>="3"
|
pytest>=5.1.2;python_version>="3"
|
||||||
pytest-cov>=2.7.1
|
pytest-cov>=2.7.1
|
||||||
pytest-forked>=1.0.2
|
pytest-forked>=1.0.2
|
||||||
pytest-html==1.22.0
|
pytest-html==1.22.0
|
||||||
|
|
|
@ -37,7 +37,7 @@ def show_basic_usage():
|
||||||
print("")
|
print("")
|
||||||
print('Usage: "seleniumbase [COMMAND] [PARAMETERS]"')
|
print('Usage: "seleniumbase [COMMAND] [PARAMETERS]"')
|
||||||
print("Commands:")
|
print("Commands:")
|
||||||
print(" install [DRIVER_NAME]")
|
print(" install [DRIVER_NAME] [OPTIONS]")
|
||||||
print(" mkdir [NEW_TEST_DIRECTORY_NAME]")
|
print(" mkdir [NEW_TEST_DIRECTORY_NAME]")
|
||||||
print(" convert [PYTHON_WEBDRIVER_UNITTEST_FILE]")
|
print(" convert [PYTHON_WEBDRIVER_UNITTEST_FILE]")
|
||||||
print(" extract-objects [SELENIUMBASE_PYTHON_FILE]")
|
print(" extract-objects [SELENIUMBASE_PYTHON_FILE]")
|
||||||
|
@ -55,11 +55,18 @@ def show_install_usage():
|
||||||
print(" ** install **")
|
print(" ** install **")
|
||||||
print("")
|
print("")
|
||||||
print(" Usage:")
|
print(" Usage:")
|
||||||
print(" seleniumbase install [DRIVER_NAME]")
|
print(" seleniumbase install [DRIVER_NAME] [OPTIONS]")
|
||||||
print(" (Drivers: chromedriver, geckodriver, edgedriver")
|
print(" (Drivers: chromedriver, geckodriver, edgedriver")
|
||||||
print(" iedriver, operadriver)")
|
print(" iedriver, operadriver)")
|
||||||
|
print(" Options:")
|
||||||
|
print(" VERSION - Specify the version (For Chromedriver ONLY).")
|
||||||
|
print(" (Default Chromedriver version = 2.44)")
|
||||||
|
print(' Use "latest" to get the latest Chromedriver.')
|
||||||
print(" Example:")
|
print(" Example:")
|
||||||
print(" seleniumbase install chromedriver")
|
print(" seleniumbase install chromedriver")
|
||||||
|
print(" seleniumbase install chromedriver 76.0.3809.126")
|
||||||
|
print(" seleniumbase install chromedriver latest")
|
||||||
|
print(" seleniumbase install geckodriver")
|
||||||
print(" Output:")
|
print(" Output:")
|
||||||
print(" Installs the specified webdriver.")
|
print(" Installs the specified webdriver.")
|
||||||
print(" (chromedriver is required for Chrome automation)")
|
print(" (chromedriver is required for Chrome automation)")
|
||||||
|
|
|
@ -3,7 +3,16 @@ Installs the specified web driver.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
seleniumbase install {chromedriver|geckodriver|edgedriver|
|
seleniumbase install {chromedriver|geckodriver|edgedriver|
|
||||||
iedriver|operadriver}
|
iedriver|operadriver} [OPTIONS]
|
||||||
|
Options:
|
||||||
|
VERSION - Specify the version (For Chromedriver ONLY)
|
||||||
|
(Default Chromedriver version = 2.44)
|
||||||
|
Use "latest" to get the latest Chromedriver.
|
||||||
|
Example:
|
||||||
|
seleniumbase install chromedriver
|
||||||
|
seleniumbase install chromedriver 76.0.3809.126
|
||||||
|
seleniumbase install chromedriver latest
|
||||||
|
seleniumbase install geckodriver
|
||||||
Output:
|
Output:
|
||||||
Installs the specified webdriver.
|
Installs the specified webdriver.
|
||||||
(chromedriver is required for Chrome automation)
|
(chromedriver is required for Chrome automation)
|
||||||
|
@ -24,16 +33,24 @@ import zipfile
|
||||||
from seleniumbase import drivers # webdriver storage folder for SeleniumBase
|
from seleniumbase import drivers # webdriver storage folder for SeleniumBase
|
||||||
urllib3.disable_warnings()
|
urllib3.disable_warnings()
|
||||||
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
|
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
|
||||||
|
DEFAULT_CHROMEDRIVER_VERSION = "2.44"
|
||||||
|
|
||||||
|
|
||||||
def invalid_run_command():
|
def invalid_run_command():
|
||||||
exp = (" ** install **\n\n")
|
exp = (" ** install **\n\n")
|
||||||
exp += " Usage:\n"
|
exp += " Usage:\n"
|
||||||
exp += " seleniumbase install [DRIVER_NAME]\n"
|
exp += " seleniumbase install [DRIVER_NAME] [OPTIONS]\n"
|
||||||
exp += " (Drivers: chromedriver, geckodriver, edgedriver,\n"
|
exp += " (Drivers: chromedriver, geckodriver, edgedriver,\n"
|
||||||
exp += " iedriver, operadriver)\n"
|
exp += " iedriver, operadriver)\n"
|
||||||
|
exp += " Options:\n"
|
||||||
|
exp += " VERSION - Specify the version (For Chromedriver ONLY)."
|
||||||
|
exp += " (Default Chromedriver version = 2.44)"
|
||||||
|
exp += ' Use "latest" to get the latest Chromedriver.'
|
||||||
exp += " Example:\n"
|
exp += " Example:\n"
|
||||||
exp += " seleniumbase install chromedriver\n"
|
exp += " seleniumbase install chromedriver\n"
|
||||||
|
exp += " seleniumbase install chromedriver 76.0.3809.126\n"
|
||||||
|
exp += " seleniumbase install chromedriver latest\n"
|
||||||
|
exp += " seleniumbase install geckodriver\n"
|
||||||
exp += " Output:\n"
|
exp += " Output:\n"
|
||||||
exp += " Installs the specified webdriver.\n"
|
exp += " Installs the specified webdriver.\n"
|
||||||
exp += " (chromedriver is required for Chrome automation)\n"
|
exp += " (chromedriver is required for Chrome automation)\n"
|
||||||
|
@ -56,11 +73,11 @@ def main():
|
||||||
num_args = len(sys.argv)
|
num_args = len(sys.argv)
|
||||||
if sys.argv[0].split('/')[-1].lower() == "seleniumbase" or (
|
if sys.argv[0].split('/')[-1].lower() == "seleniumbase" or (
|
||||||
sys.argv[0].split('\\')[-1].lower() == "seleniumbase"):
|
sys.argv[0].split('\\')[-1].lower() == "seleniumbase"):
|
||||||
if num_args < 3 or num_args > 3:
|
if num_args < 3 or num_args > 4:
|
||||||
invalid_run_command()
|
invalid_run_command()
|
||||||
else:
|
else:
|
||||||
invalid_run_command()
|
invalid_run_command()
|
||||||
name = sys.argv[num_args - 1].lower()
|
name = sys.argv[2].lower()
|
||||||
|
|
||||||
file_name = None
|
file_name = None
|
||||||
download_url = None
|
download_url = None
|
||||||
|
@ -71,52 +88,56 @@ def main():
|
||||||
inner_folder = None
|
inner_folder = None
|
||||||
|
|
||||||
if name == "chromedriver":
|
if name == "chromedriver":
|
||||||
latest_version = "2.44" # It's not the latest, but most compatible
|
use_version = DEFAULT_CHROMEDRIVER_VERSION
|
||||||
|
get_latest = False
|
||||||
|
if num_args == 4:
|
||||||
|
use_version = sys.argv[3]
|
||||||
|
if use_version.lower() == "latest":
|
||||||
|
get_latest = True
|
||||||
if "darwin" in sys_plat:
|
if "darwin" in sys_plat:
|
||||||
file_name = "chromedriver_mac64.zip"
|
file_name = "chromedriver_mac64.zip"
|
||||||
elif "linux" in sys_plat:
|
elif "linux" in sys_plat:
|
||||||
latest_version = "2.44" # Linux machines may need the old driver
|
|
||||||
file_name = "chromedriver_linux64.zip"
|
file_name = "chromedriver_linux64.zip"
|
||||||
elif "win32" in sys_plat or "win64" in sys_plat or "x64" in sys_plat:
|
elif "win32" in sys_plat or "win64" in sys_plat or "x64" in sys_plat:
|
||||||
file_name = "chromedriver_win32.zip" # Works for win32 / win_x64
|
file_name = "chromedriver_win32.zip" # Works for win32 / win_x64
|
||||||
else:
|
else:
|
||||||
raise Exception("Cannot determine which version of Chromedriver "
|
raise Exception("Cannot determine which version of Chromedriver "
|
||||||
"to download!")
|
"to download!")
|
||||||
download_url = ("http://chromedriver.storage.googleapis.com/"
|
found_chromedriver = False
|
||||||
"%s/%s" % (latest_version, file_name))
|
|
||||||
# Forcing Chromedriver v2.40 for now, even though it's not the latest.
|
|
||||||
get_latest = False
|
|
||||||
if get_latest:
|
if get_latest:
|
||||||
last = "http://chromedriver.storage.googleapis.com/LATEST_RELEASE"
|
last = "http://chromedriver.storage.googleapis.com/LATEST_RELEASE"
|
||||||
print('\nLocating the latest version of Chromedriver...')
|
url_request = requests.get(last)
|
||||||
latest_version = requests.get(last).text
|
if url_request.ok:
|
||||||
if not requests.get(download_url).ok:
|
found_chromedriver = True
|
||||||
fallback_version = "2.44"
|
use_version = url_request.text
|
||||||
download_url = ("http://chromedriver.storage.googleapis.com/"
|
download_url = ("http://chromedriver.storage.googleapis.com/"
|
||||||
"%s/%s" % (fallback_version, file_name))
|
"%s/%s" % (use_version, file_name))
|
||||||
else:
|
url_request = None
|
||||||
download_url = ("http://chromedriver.storage.googleapis.com/"
|
if not found_chromedriver:
|
||||||
"%s/%s" % (latest_version, file_name))
|
url_request = requests.get(download_url)
|
||||||
print("Found %s" % download_url)
|
if found_chromedriver or url_request.ok:
|
||||||
|
print("\nChromedriver version for download = %s" % use_version)
|
||||||
|
else:
|
||||||
|
raise Exception("Could not find Chromedriver to download!\n")
|
||||||
elif name == "geckodriver" or name == "firefoxdriver":
|
elif name == "geckodriver" or name == "firefoxdriver":
|
||||||
latest_version = "v0.24.0"
|
use_version = "v0.24.0"
|
||||||
if "darwin" in sys_plat:
|
if "darwin" in sys_plat:
|
||||||
file_name = "geckodriver-%s-macos.tar.gz" % latest_version
|
file_name = "geckodriver-%s-macos.tar.gz" % use_version
|
||||||
elif "linux" in sys_plat:
|
elif "linux" in sys_plat:
|
||||||
arch = platform.architecture()[0]
|
arch = platform.architecture()[0]
|
||||||
if "64" in arch:
|
if "64" in arch:
|
||||||
file_name = "geckodriver-%s-linux64.tar.gz" % latest_version
|
file_name = "geckodriver-%s-linux64.tar.gz" % use_version
|
||||||
else:
|
else:
|
||||||
file_name = "geckodriver-%s-linux32.tar.gz" % latest_version
|
file_name = "geckodriver-%s-linux32.tar.gz" % use_version
|
||||||
elif "win32" in sys_plat or "win64" in sys_plat or "x64" in sys_plat:
|
elif "win32" in sys_plat or "win64" in sys_plat or "x64" in sys_plat:
|
||||||
file_name = "geckodriver-%s-win64.zip" % latest_version
|
file_name = "geckodriver-%s-win64.zip" % use_version
|
||||||
else:
|
else:
|
||||||
raise Exception("Cannot determine which version of Geckodriver "
|
raise Exception("Cannot determine which version of Geckodriver "
|
||||||
"(Firefox Driver) to download!")
|
"(Firefox Driver) to download!")
|
||||||
|
|
||||||
download_url = ("https://github.com/mozilla/geckodriver/"
|
download_url = ("https://github.com/mozilla/geckodriver/"
|
||||||
"releases/download/"
|
"releases/download/"
|
||||||
"%s/%s" % (latest_version, file_name))
|
"%s/%s" % (use_version, file_name))
|
||||||
elif name == "edgedriver" or name == "microsoftwebdriver":
|
elif name == "edgedriver" or name == "microsoftwebdriver":
|
||||||
name = "edgedriver"
|
name = "edgedriver"
|
||||||
version_code = "F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD"
|
version_code = "F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD"
|
||||||
|
@ -141,7 +162,7 @@ def main():
|
||||||
"%s/%s" % (major_version, file_name))
|
"%s/%s" % (major_version, file_name))
|
||||||
elif name == "operadriver" or name == "operachromiumdriver":
|
elif name == "operadriver" or name == "operachromiumdriver":
|
||||||
name = "operadriver"
|
name = "operadriver"
|
||||||
latest_version = "v.2.40"
|
use_version = "v.2.40"
|
||||||
if "darwin" in sys_plat:
|
if "darwin" in sys_plat:
|
||||||
file_name = "operadriver_mac64.zip"
|
file_name = "operadriver_mac64.zip"
|
||||||
platform_code = "mac64"
|
platform_code = "mac64"
|
||||||
|
@ -176,7 +197,7 @@ def main():
|
||||||
|
|
||||||
download_url = ("https://github.com/operasoftware/operachromiumdriver/"
|
download_url = ("https://github.com/operasoftware/operachromiumdriver/"
|
||||||
"releases/download/"
|
"releases/download/"
|
||||||
"%s/%s" % (latest_version, file_name))
|
"%s/%s" % (use_version, file_name))
|
||||||
else:
|
else:
|
||||||
invalid_run_command()
|
invalid_run_command()
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ class BaseCase(unittest.TestCase):
|
||||||
|
|
||||||
def double_click(self, selector, by=By.CSS_SELECTOR,
|
def double_click(self, selector, by=By.CSS_SELECTOR,
|
||||||
timeout=settings.SMALL_TIMEOUT):
|
timeout=settings.SMALL_TIMEOUT):
|
||||||
from selenium.webdriver import ActionChains
|
from selenium.webdriver.common.action_chains import ActionChains
|
||||||
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
||||||
timeout = self.__get_new_timeout(timeout)
|
timeout = self.__get_new_timeout(timeout)
|
||||||
if page_utils.is_xpath_selector(selector):
|
if page_utils.is_xpath_selector(selector):
|
||||||
|
@ -1962,6 +1962,8 @@ class BaseCase(unittest.TestCase):
|
||||||
def hover_and_click(self, hover_selector, click_selector,
|
def hover_and_click(self, hover_selector, click_selector,
|
||||||
hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR,
|
hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR,
|
||||||
timeout=settings.SMALL_TIMEOUT):
|
timeout=settings.SMALL_TIMEOUT):
|
||||||
|
""" When you want to hover over an element or dropdown menu,
|
||||||
|
and then click an element that appears after that. """
|
||||||
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
||||||
timeout = self.__get_new_timeout(timeout)
|
timeout = self.__get_new_timeout(timeout)
|
||||||
hover_selector, hover_by = self.__recalculate_selector(
|
hover_selector, hover_by = self.__recalculate_selector(
|
||||||
|
@ -1985,6 +1987,35 @@ class BaseCase(unittest.TestCase):
|
||||||
self.__demo_mode_pause_if_active(tiny=True)
|
self.__demo_mode_pause_if_active(tiny=True)
|
||||||
return element
|
return element
|
||||||
|
|
||||||
|
def hover_and_double_click(self, hover_selector, click_selector,
|
||||||
|
hover_by=By.CSS_SELECTOR,
|
||||||
|
click_by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT):
|
||||||
|
""" When you want to hover over an element or dropdown menu,
|
||||||
|
and then double-click an element that appears after that. """
|
||||||
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
||||||
|
timeout = self.__get_new_timeout(timeout)
|
||||||
|
hover_selector, hover_by = self.__recalculate_selector(
|
||||||
|
hover_selector, hover_by)
|
||||||
|
hover_selector = self.convert_to_css_selector(
|
||||||
|
hover_selector, hover_by)
|
||||||
|
click_selector, click_by = self.__recalculate_selector(
|
||||||
|
click_selector, click_by)
|
||||||
|
hover_element = self.wait_for_element_visible(
|
||||||
|
hover_selector, by=hover_by, timeout=timeout)
|
||||||
|
self.__demo_mode_highlight_if_active(hover_selector, hover_by)
|
||||||
|
self.scroll_to(hover_selector, by=hover_by)
|
||||||
|
pre_action_url = self.driver.current_url
|
||||||
|
click_element = page_actions.hover_element_and_double_click(
|
||||||
|
self.driver, hover_element, click_selector,
|
||||||
|
click_by=By.CSS_SELECTOR, timeout=timeout)
|
||||||
|
if self.demo_mode:
|
||||||
|
if self.driver.current_url != pre_action_url:
|
||||||
|
self.__demo_mode_pause_if_active()
|
||||||
|
else:
|
||||||
|
self.__demo_mode_pause_if_active(tiny=True)
|
||||||
|
return click_element
|
||||||
|
|
||||||
def __select_option(self, dropdown_selector, option,
|
def __select_option(self, dropdown_selector, option,
|
||||||
dropdown_by=By.CSS_SELECTOR, option_by="text",
|
dropdown_by=By.CSS_SELECTOR, option_by="text",
|
||||||
timeout=settings.SMALL_TIMEOUT):
|
timeout=settings.SMALL_TIMEOUT):
|
||||||
|
@ -2409,6 +2440,13 @@ class BaseCase(unittest.TestCase):
|
||||||
############
|
############
|
||||||
|
|
||||||
def wait_for_ready_state_complete(self, timeout=settings.EXTREME_TIMEOUT):
|
def wait_for_ready_state_complete(self, timeout=settings.EXTREME_TIMEOUT):
|
||||||
|
try:
|
||||||
|
# If there's an alert, skip
|
||||||
|
self.driver.switch_to.alert
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
# If there's no alert, continue
|
||||||
|
pass
|
||||||
if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
|
if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
|
||||||
timeout = self.__get_new_timeout(timeout)
|
timeout = self.__get_new_timeout(timeout)
|
||||||
is_ready = js_utils.wait_for_ready_state_complete(self.driver, timeout)
|
is_ready = js_utils.wait_for_ready_state_complete(self.driver, timeout)
|
||||||
|
|
|
@ -158,6 +158,31 @@ def hover_element_and_click(driver, element, click_selector,
|
||||||
(click_selector, timeout))
|
(click_selector, timeout))
|
||||||
|
|
||||||
|
|
||||||
|
def hover_element_and_double_click(driver, element, click_selector,
|
||||||
|
click_by=By.CSS_SELECTOR,
|
||||||
|
timeout=settings.SMALL_TIMEOUT):
|
||||||
|
start_ms = time.time() * 1000.0
|
||||||
|
stop_ms = start_ms + (timeout * 1000.0)
|
||||||
|
hover = ActionChains(driver).move_to_element(element)
|
||||||
|
hover.perform()
|
||||||
|
for x in range(int(timeout * 10)):
|
||||||
|
try:
|
||||||
|
element_2 = driver.find_element(by=click_by, value=click_selector)
|
||||||
|
actions = ActionChains(driver)
|
||||||
|
actions.move_to_element(element_2)
|
||||||
|
actions.double_click(element_2)
|
||||||
|
actions.perform()
|
||||||
|
return element_2
|
||||||
|
except Exception:
|
||||||
|
now_ms = time.time() * 1000.0
|
||||||
|
if now_ms >= stop_ms:
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
raise NoSuchElementException(
|
||||||
|
"Element {%s} was not present after %s seconds!" %
|
||||||
|
(click_selector, timeout))
|
||||||
|
|
||||||
|
|
||||||
def wait_for_element_present(driver, selector, by=By.CSS_SELECTOR,
|
def wait_for_element_present(driver, selector, by=By.CSS_SELECTOR,
|
||||||
timeout=settings.LARGE_TIMEOUT):
|
timeout=settings.LARGE_TIMEOUT):
|
||||||
"""
|
"""
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -17,7 +17,7 @@ except IOError:
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='seleniumbase',
|
name='seleniumbase',
|
||||||
version='1.30.0',
|
version='1.31.0',
|
||||||
description='Fast, Easy, and Reliable Browser Automation & Testing.',
|
description='Fast, Easy, and Reliable Browser Automation & Testing.',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
@ -65,7 +65,7 @@ setup(
|
||||||
'selenium==3.141.0',
|
'selenium==3.141.0',
|
||||||
'pluggy>=0.12.0',
|
'pluggy>=0.12.0',
|
||||||
'pytest>=4.6.5;python_version<"3"', # For Python 2 compatibility
|
'pytest>=4.6.5;python_version<"3"', # For Python 2 compatibility
|
||||||
'pytest>=5.1.0;python_version>="3"',
|
'pytest>=5.1.2;python_version>="3"',
|
||||||
'pytest-cov>=2.7.1',
|
'pytest-cov>=2.7.1',
|
||||||
'pytest-forked>=1.0.2',
|
'pytest-forked>=1.0.2',
|
||||||
'pytest-html==1.22.0', # Keep at 1.22.0 unless tested on Windows
|
'pytest-html==1.22.0', # Keep at 1.22.0 unless tested on Windows
|
||||||
|
|
Loading…
Reference in New Issue