diff --git a/.gitignore b/.gitignore index 0b4216d8f16..e34a2acfbe2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,9 +39,12 @@ nosetests.xml # Web Drivers chromedriver geckodriver +operadriver MicrosoftWebDriver.exe +IEDriverServer.exe chromedriver.exe geckodriver.exe +operadriver.exe # Logs logs diff --git a/.travis.yml b/.travis.yml index f16d03dc5d2..ab1508c2361 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,9 @@ before_script: # - "wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 && tar -xvf ./phantomjs-2.1.1-linux-x86_64.tar.bz2 && export PATH=$PWD/phantomjs-2.1.1-linux-x86_64/bin:$PATH" - "seleniumbase install chromedriver" - "seleniumbase install geckodriver" + - "seleniumbase mkdir browser_tests" script: + - "pytest browser_tests/boilerplates/boilerplate_test.py --headless --with-db_reporting" - "pytest examples/my_first_test.py --browser=chrome -s --headless --with-db_reporting" - "nosetests examples/boilerplates/boilerplate_test.py --browser=chrome --headless" - "pytest examples/my_first_test.py --browser=firefox -s --headless --with-db_reporting" diff --git a/README.md b/README.md index 34786a81224..a93f6dc2bbc 100755 --- a/README.md +++ b/README.md @@ -1,15 +1,29 @@ -## SeleniumBase Automation Framework + - +## SeleniumBase · [![](https://img.shields.io/pypi/v/seleniumbase.svg)](https://pypi.python.org/pypi/seleniumbase) [![Build Status](https://travis-ci.org/seleniumbase/SeleniumBase.svg?branch=master)](https://travis-ci.org/seleniumbase/SeleniumBase)
-[![](https://img.shields.io/pypi/v/seleniumbase.svg)](https://pypi.python.org/pypi/seleniumbase) [![Build Status](https://travis-ci.org/seleniumbase/SeleniumBase.svg?branch=master)](https://travis-ci.org/seleniumbase/SeleniumBase) [![Join the chat at https://gitter.im/seleniumbase/SeleniumBase](https://badges.gitter.im/seleniumbase/SeleniumBase.svg)](https://gitter.im/seleniumbase/SeleniumBase?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+SeleniumBase simplifies test automation with [WebDriver](https://docs.microsoft.com/en-us/microsoft-edge/webdriver) & [Pytest](https://github.com/pytest-dev/pytest). -SeleniumBase makes it easy to build & run [Selenium-WebDriver](https://github.com/SeleniumHQ/selenium) automation with [Pytest](https://docs.pytest.org/en/latest/). +#### Quick start in a few steps: (requires [Python](https://www.python.org/downloads/)) -**Watch [my_first_test.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py) run in [Demo Mode](#seleniumbase_demo_mode):**
+```bash +python -m pip install seleniumbase --upgrade +seleniumbase install chromedriver +seleniumbase mkdir browser_tests +cd browser_tests +pytest my_first_test.py --browser=chrome +``` + +The ``seleniumbase mkdir [NAME]`` command creates a new folder with some sample tests you can run. If you wish to use a different browser, you can use ``seleniumbase install [DRIVER]`` with other drivers such as ``edgedriver`` (Microsoft Edge) or ``geckodriver`` (Firefox). Then use ``--browser=edge`` or ``--browser=firefox`` to run tests on that browser (assuming you already have that web browser installed). ``--browser=chrome`` is the default option if not specified. + +**Slow-motion demo of [my_first_test.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py) running:**
![](https://cdn2.hubspot.net/hubfs/100006/images/sb_demo.gif "SeleniumBase")
-### [**Get Started**](#seleniumbase_installation), or Learn More: +There are many more examples to try out from the [SeleniumBase/examples](https://github.com/seleniumbase/SeleniumBase/blob/master/examples) directory, which you can run easily if you clone SeleniumBase. + +For more detailed steps on getting started, see the [**Detailed Instructions**](#seleniumbase_installation) section. + +### Learn More: **No more repetitive WebDriver code:**
SeleniumBase automatically handles common WebDriver actions such as spinning up web browsers, waiting for page objects to load, saving screenshots during test failures, using a proxy server, and more. ([Read about customizing test runs](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md).) @@ -29,6 +43,8 @@ pytest my_first_test.py --browser=chrome nosetests my_test_suite.py --browser=firefox ``` +Python methods that start with ``test_`` will automatically be run when using ``pytest`` or ``nosetests`` on a Python file, (or on folders containing Python files). + **No more messy code:**
This long line of standard WebDriver code, ```python @@ -53,15 +69,15 @@ SeleniumBase is compatible with [Selenium Grid](https://github.com/seleniumbase/ SeleniumBase makes it easy to automate tedious business tasks. (*To learn about businesses using SeleniumBase, [Click Here](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/happy_customers.md).*) **Extensively tested and made with love:**
-SeleniumBase was originally built for [testing HubSpot's platform](https://product.hubspot.com/blog/the-classic-qa-team-is-obsolete) and automating business processes. In 2014, SeleniumBase was open-sourced and spun off as its own independent entity to benefit users everywhere. +SeleniumBase was originally built for [testing HubSpot's platform](https://product.hubspot.com/blog/bid/88880/Automated-Integration-Testing-with-Selenium-at-HubSpot) and automating business processes. In 2014, SeleniumBase was open-sourced and spun off as its own independent entity to benefit users everywhere. -**Contains lots of additional features:**
+**Plenty of features:**
([Read more about SeleniumBase features here](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/features_list.md)) -
+
-## Get Started: +## Detailed Instructions: Before installation, **[install Python](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/install_python_pip_git.md)** and **[install a web driver](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/webdriver_installation.md)**. @@ -86,14 +102,14 @@ cd SeleniumBase If you're installing SeleniumBase from a cloned copy on your machine, use: ``` -pip install -r requirements.txt +pip install -r requirements.txt --upgrade python setup.py develop ``` If you're installing SeleniumBase from the [Python Package Index](https://pypi.python.org/pypi/seleniumbase), use: ```bash -pip install seleniumbase +pip install seleniumbase --upgrade ``` If you're installing SeleniumBase directly from GitHub, use: @@ -611,10 +627,10 @@ Now you can parse through the email if you're looking for specific text or want **Congratulations** on learning how to use **SeleniumBase**! -**Questions or Comments?**
+**Questions or Comments?**
[![Join the chat at https://gitter.im/seleniumbase/SeleniumBase](https://badges.gitter.im/seleniumbase/SeleniumBase.svg)](https://gitter.im/seleniumbase/SeleniumBase?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[https://github.com/mdmintz](https://github.com/mdmintz)
[https://www.linkedin.com/in/mdmintz](https://www.linkedin.com/in/mdmintz)
-
+
diff --git a/console_scripts/ReadMe.md b/console_scripts/ReadMe.md index 117ae1b9def..de92c6d7782 100755 --- a/console_scripts/ReadMe.md +++ b/console_scripts/ReadMe.md @@ -25,7 +25,7 @@ Installs the specified webdriver. ``seleniumbase mkdir [DIRECTORY_NAME]`` * Example: -``seleniumbase mkdir gui_tests`` +``seleniumbase mkdir browser_tests`` * Output: Creates a new folder for running SeleniumBase scripts. diff --git a/console_scripts/run.py b/console_scripts/run.py index c8c89b6af48..08832f0d962 100644 --- a/console_scripts/run.py +++ b/console_scripts/run.py @@ -6,7 +6,7 @@ Examples: seleniumbase install chromedriver -seleniumbase mkdir gui_tests +seleniumbase mkdir browser_tests seleniumbase convert my_old_webdriver_unittest.py seleniumbase grid-hub start seleniumbase grid-node start --hub=127.0.0.1 @@ -47,14 +47,17 @@ def show_install_usage(): print("") print(" Usage:") print(" seleniumbase install [DRIVER_NAME]") - print(" (Drivers: chromedriver, geckodriver, edgedriver)") + print(" (Drivers: chromedriver, geckodriver, edgedriver") + print(" iedriver, operadriver)") print(" Example:") print(" seleniumbase install chromedriver") print(" Output:") print(" Installs the specified webdriver.") print(" (chromedriver is required for Chrome automation)") print(" (geckodriver is required for Firefox automation)") - print(" (edgedriver is required for MS Edge automation)") + print(" (edgedriver is required for Microsoft Edge automation)") + print(" (iedriver is required for InternetExplorer automation)") + print(" (operadriver is required for Opera Browser automation)") print("") @@ -64,7 +67,7 @@ def show_mkdir_usage(): print(" Usage:") print(" seleniumbase mkdir [DIRECTORY_NAME]") print(" Example:") - print(" seleniumbase mkdir gui_tests") + print(" seleniumbase mkdir browser_tests") print(" Output:") print(" Creates a new folder for running SeleniumBase scripts.") print(" The new folder contains default config files,") diff --git a/console_scripts/sb_install.py b/console_scripts/sb_install.py index e92832dc5f2..49752075ef8 100755 --- a/console_scripts/sb_install.py +++ b/console_scripts/sb_install.py @@ -8,11 +8,14 @@ (chromedriver is required for Chrome automation) (geckodriver is required for Firefox automation) (edgedriver is required for MS Edge automation) + (iedriver is required for Internet Explorer automation) + (operadriver is required for Opera Browser automation) """ import os import platform import requests +import shutil import sys import tarfile import zipfile @@ -28,14 +31,17 @@ def invalid_run_command(): exp = (" ** install **\n\n") exp += " Usage:\n" exp += " seleniumbase install [DRIVER_NAME]\n" - exp += " (Drivers: chromedriver, geckodriver, edgedriver)\n" + exp += " (Drivers: chromedriver, geckodriver, edgedriver,\n" + exp += " iedriver, operadriver)\n" exp += " Example:\n" exp += " seleniumbase install chromedriver\n" exp += " Output:\n" exp += " Installs the specified webdriver.\n" exp += " (chromedriver is required for Chrome automation)\n" exp += " (geckodriver is required for Firefox automation)\n" - exp += " (edgedriver is required for MS Edge automation)\n" + exp += " (edgedriver is required for Microsoft Edge automation)\n" + exp += " (iedriver is required for InternetExplorer automation)\n" + exp += " (operadriver is required for Opera Browser automation)\n" print("") raise Exception('INVALID RUN COMMAND!\n\n%s' % exp) @@ -60,16 +66,20 @@ def main(): file_name = None download_url = None downloads_folder = DRIVER_DIR + sys_plat = sys.platform + expected_contents = None + platform_code = None + inner_folder = None if name == "chromedriver": - if "darwin" in sys.platform: + if "darwin" in sys_plat: file_name = "chromedriver_mac64.zip" - elif "linux" in sys.platform: + elif "linux" in sys_plat: file_name = "chromedriver_linux64.zip" - elif "win32" in sys.platform or "win64" in sys.platform: - file_name = "chromedriver_win32.zip" # Works for win32 and win64 + 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 else: - raise Exception("Cannon determine which version of Chromedriver " + raise Exception("Cannot determine which version of Chromedriver " "to download!") latest_version = requests.get( @@ -85,34 +95,85 @@ def main(): print("Found %s" % download_url) elif name == "geckodriver" or name == "firefoxdriver": latest_version = "v0.21.0" - if "darwin" in sys.platform: + if "darwin" in sys_plat: file_name = "geckodriver-%s-macos.tar.gz" % latest_version - elif "linux" in sys.platform: + elif "linux" in sys_plat: arch = platform.architecture()[0] if "64" in arch: file_name = "geckodriver-%s-linux64.tar.gz" % latest_version else: file_name = "geckodriver-%s-linux32.tar.gz" % latest_version - elif "win32" in sys.platform: + elif "win32" in sys_plat: file_name = "geckodriver-%s-win32.zip" % latest_version - elif "win64" in sys.platform: + elif "win64" in sys_plat or "x64" in sys_plat: file_name = "geckodriver-%s-win64.zip" % latest_version else: - raise Exception("Cannon determine which version of Geckodriver " + raise Exception("Cannot determine which version of Geckodriver " "(Firefox Driver) to download!") - download_url = ("http://github.com/mozilla/geckodriver/" + download_url = ("https://github.com/mozilla/geckodriver/" "releases/download/" "%s/%s" % (latest_version, file_name)) elif name == "edgedriver" or name == "microsoftwebdriver": - if "win32" in sys.platform or "win64" in sys.platform: - version_code = "F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD" + name = "edgedriver" + version_code = "F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD" + if "win32" in sys_plat or "win64" in sys_plat or "x64" in sys_plat: file_name = "MicrosoftWebDriver.exe" - download_url = ("https://download.microsoft.com/download/" - "%s/%s" % (version_code, file_name)) else: raise Exception("Sorry! Microsoft WebDriver / EdgeDriver is " "only for Windows-based operating systems!") + download_url = ("https://download.microsoft.com/download/" + "%s/%s" % (version_code, file_name)) + elif name == "iedriver": + major_version = "3.11" + full_version = "3.11.1" + if "win32" in sys_plat: + file_name = "IEDriverServer_Win32_%s.zip" % full_version + elif "win64" in sys_plat or "x64" in sys_plat: + file_name = "IEDriverServer_x64_%s.zip" % full_version + else: + raise Exception("Sorry! IEDriver is only for " + "Windows-based operating systems!") + download_url = ("http://selenium-release.storage.googleapis.com/" + "%s/%s" % (major_version, file_name)) + elif name == "operadriver" or name == "operachromiumdriver": + name = "operadriver" + latest_version = "v.2.37" + if "darwin" in sys_plat: + file_name = "operadriver_mac64.zip" + platform_code = "mac64" + inner_folder = "operadriver_%s/" % platform_code + expected_contents = (['operadriver_mac64/', + 'operadriver_mac64/operadriver', + 'operadriver_mac64/sha512_sum']) + elif "linux" in sys_plat: + file_name = "operadriver_linux64.zip" + platform_code = "linux64" + inner_folder = "operadriver_%s/" % platform_code + expected_contents = (['operadriver_linux64/', + 'operadriver_linux64/operadriver', + 'operadriver_linux64/sha512_sum']) + elif "win32" in sys_plat: + file_name = "operadriver_win32.zip" + platform_code = "win32" + inner_folder = "operadriver_%s/" % platform_code + expected_contents = (['operadriver_win32/', + 'operadriver_win32/operadriver.exe', + 'operadriver_win32/sha512_sum']) + elif "win64" in sys_plat or "x64" in sys_plat: + file_name = "operadriver_win64.zip" + platform_code = "win64" + inner_folder = "operadriver_%s/" % platform_code + expected_contents = (['operadriver_win64/', + 'operadriver_win64/operadriver.exe', + 'operadriver_win64/sha512_sum']) + else: + raise Exception("Cannot determine which version of Operadriver " + "to download!") + + download_url = ("https://github.com/operasoftware/operachromiumdriver/" + "releases/download/" + "%s/%s" % (latest_version, file_name)) else: invalid_run_command() @@ -135,6 +196,8 @@ def main(): zip_ref = zipfile.ZipFile(zip_file_path, 'r') contents = zip_ref.namelist() if len(contents) == 1: + if name == "operadriver": + raise Exception("Zip file for OperaDriver is missing content!") for f_name in contents: # remove existing version if exists new_file = downloads_folder + '/' + str(f_name) @@ -153,6 +216,46 @@ def main(): make_executable(new_file) print("%s is now ready for use!" % new_file) print("") + elif name == "operadriver": + if len(contents) != 3: + raise Exception("Unexpected content in OperaDriver Zip file!") + elif sorted(contents) != sorted(expected_contents): + raise Exception("Unexpected content in OperaDriver Zip file!") + # Zip file is valid. Proceed. + driver_path = None + driver_file = None + for f_name in contents: + # remove existing version if exists + str_name = str(f_name).split(inner_folder)[1] + new_file = downloads_folder + '/' + str_name + if str_name == "operadriver" or str_name == "operadriver.exe": + driver_file = str_name + driver_path = new_file + if os.path.exists(new_file): + os.remove(new_file) + if not driver_file or not driver_path: + raise Exception("Operadriver missing from Zip file!") + print('Extracting %s from %s ...' % (contents, file_name)) + zip_ref.extractall(downloads_folder) + zip_ref.close() + os.remove(zip_file_path) + print('Unzip Complete!\n') + inner_driver = downloads_folder + '/' + inner_folder + driver_file + inner_sha = downloads_folder + '/' + inner_folder + "sha512_sum" + shutil.copyfile(inner_driver, driver_path) + print("%s saved!\n" % driver_path) + print("Making %s executable ..." % driver_path) + make_executable(driver_path) + print("%s is now ready for use!" % driver_path) + # clean up extra files + if os.path.exists(inner_driver): + os.remove(inner_driver) + if os.path.exists(inner_sha): + os.remove(inner_sha) + if os.path.exists(downloads_folder + '/' + inner_folder): + # only works if the directory is empty + os.rmdir(downloads_folder + '/' + inner_folder) + print("") elif len(contents) == 0: raise Exception("Zip file %s is empty!" % zip_file_path) else: @@ -172,7 +275,7 @@ def main(): tar.extractall(downloads_folder) tar.close() os.remove(tar_file_path) - print('Untar Complete!\n') + print('Unzip Complete!\n') for f_name in contents: new_file = downloads_folder + '/' + str(f_name) print("%s saved!\n" % new_file) diff --git a/console_scripts/sb_mkdir.py b/console_scripts/sb_mkdir.py index f8605cd781e..6381cdbb130 100755 --- a/console_scripts/sb_mkdir.py +++ b/console_scripts/sb_mkdir.py @@ -21,7 +21,7 @@ def invalid_run_command(): exp += " Usage:\n" exp += " seleniumbase mkdir [DIRECTORY_NAME]\n" exp += " Example:\n" - exp += " seleniumbase mkdir gui_tests\n" + exp += " seleniumbase mkdir browser_tests\n" exp += " Output:\n" exp += " Creates a new folder for running SeleniumBase scripts.\n" exp += " The new folder contains default config files,\n" @@ -180,7 +180,8 @@ def main(): data.append("class BingTests(BaseCase):") data.append("") data.append(" def test_bing(self):") - data.append(" self.open('https://www.bing.com/')") + data.append(" self.open('https://bing.com')") + data.append(" self.assert_text('Bing', Page.logo_box)") data.append(" self.update_text(Page.search_box, 'github')") data.append(" self.assert_element('li[query=\"github\"]')") data.append(" self.click(Page.search_button)") @@ -196,6 +197,7 @@ def main(): data = [] data.append("class Page(object):") + data.append(" logo_box = '#sbox div[class*=logo]'") data.append(" search_box = 'input.b_searchbox'") data.append(" search_button = 'input[name=\"go\"]'") data.append(" search_results = '#b_results'") @@ -213,7 +215,15 @@ def main(): data.append("class GoogleTests(BaseCase):") data.append("") data.append(" def test_google_dot_com(self):") - data.append(" self.open('https://www.google.com')") + data.append(" self.open('https://google.com')") + data.append(" try:") + data.append(" # Remove the Privacy Checkup box if present.") + data.append(" self.assert_text('Privacy Checkup', " + "HomePage.dialog_box, timeout=3)") + data.append(" self.click('link=NO, THANKS')") + data.append(" except Exception:") + data.append(" # Google may have removed it. Continue test.") + data.append(" pass") data.append(" self.assert_element(HomePage.search_button)") data.append( " self.assert_element(HomePage.feeling_lucky_button)") @@ -234,6 +244,7 @@ def main(): data = [] data.append("class HomePage(object):") + data.append(" dialog_box = '[role=\"dialog\"] div'") data.append(" search_box = 'input[title=\"Search\"]'") data.append(" search_button = 'input[value=\"Google Search\"]'") data.append( diff --git a/examples/boilerplates/samples/bing_objects.py b/examples/boilerplates/samples/bing_objects.py index 80a895b79e6..49090545512 100755 --- a/examples/boilerplates/samples/bing_objects.py +++ b/examples/boilerplates/samples/bing_objects.py @@ -3,6 +3,7 @@ ''' class Page(object): + logo_box = '#sbox div[class*=logo]' search_box = 'input.b_searchbox' search_button = 'input[name="go"]' search_results = '#b_results' diff --git a/examples/boilerplates/samples/bing_test.py b/examples/boilerplates/samples/bing_test.py index 8e8ddc570b6..9811b3f758e 100755 --- a/examples/boilerplates/samples/bing_test.py +++ b/examples/boilerplates/samples/bing_test.py @@ -9,7 +9,8 @@ class BingTests(BaseCase): def test_bing(self): - self.open('https://www.bing.com/') + self.open('https://bing.com') + self.assert_text('Bing', Page.logo_box) self.update_text(Page.search_box, 'github') self.assert_element('li[query="github"]') self.click(Page.search_button) diff --git a/examples/boilerplates/samples/google_objects.py b/examples/boilerplates/samples/google_objects.py index c3bb454599d..067711e1236 100755 --- a/examples/boilerplates/samples/google_objects.py +++ b/examples/boilerplates/samples/google_objects.py @@ -4,6 +4,7 @@ class HomePage(object): + dialog_box = '[role="dialog"] div' search_box = 'input[title="Search"]' search_button = 'input[value="Google Search"]' feeling_lucky_button = '''input[value="I'm Feeling Lucky"]''' diff --git a/examples/boilerplates/samples/google_test.py b/examples/boilerplates/samples/google_test.py index 4160ef55162..48121fcdefb 100755 --- a/examples/boilerplates/samples/google_test.py +++ b/examples/boilerplates/samples/google_test.py @@ -9,7 +9,13 @@ class GoogleTests(BaseCase): def test_google_dot_com(self): - self.open('https://www.google.com') + self.open('https://google.com') + try: + # Remove the Privacy Checkup box if present. + self.assert_text('Privacy Checkup', HomePage.dialog_box, timeout=3) + self.click('link=NO, THANKS') + except Exception: + pass # Google may have removed the Privacy Checkup. Continue test. self.assert_element(HomePage.search_button) self.assert_element(HomePage.feeling_lucky_button) self.update_text(HomePage.search_box, 'github\n') diff --git a/examples/master_qa/ReadMe.md b/examples/master_qa/ReadMe.md new file mode 100755 index 00000000000..66ef45cea00 --- /dev/null +++ b/examples/master_qa/ReadMe.md @@ -0,0 +1,7 @@ +## MasterQA + +MasterQA combines web automation with manual verification to create a flexible testing experience that greatly enhances pure manual QA. + +### More info on MasterQA can be found [here](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/masterqa/ReadMe.md). + +![](http://cdn2.hubspot.net/hubfs/100006/images/masterqa_gif.gif "MasterQA")
diff --git a/help_docs/webdriver_installation.md b/help_docs/webdriver_installation.md index e8b4dcf27d6..a19d07a751a 100755 --- a/help_docs/webdriver_installation.md +++ b/help_docs/webdriver_installation.md @@ -21,6 +21,8 @@ Here's where you can go to manually install web drivers from the source: * For Safari, get [Safari Driver](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/using_safari_driver.md) on your System PATH. +* For Opera, get [Opera Chromium Driver](https://github.com/operasoftware/operachromiumdriver/releases) on your System PATH.. + * For PhantomJS headless browser automation, get [PhantomJS](http://phantomjs.org/download.html) on your System PATH. (NOTE: PhantomJS is no longer officially supported by SeleniumHQ) **Mac**: diff --git a/integrations/selenium_ide/convert_ide.py b/integrations/selenium_ide/convert_ide.py index 484c07afdb2..6a971ce9485 100755 --- a/integrations/selenium_ide/convert_ide.py +++ b/integrations/selenium_ide/convert_ide.py @@ -319,6 +319,7 @@ def main(): if data: whitespace = data.group(1) xpath = '%s' % data.group(2) + uni = "" if '(u"' in line: uni = "u" has_unicode = True diff --git a/seleniumbase/config/settings.py b/seleniumbase/config/settings.py index 83c37a3a528..b777bd3ff16 100755 --- a/seleniumbase/config/settings.py +++ b/seleniumbase/config/settings.py @@ -60,7 +60,7 @@ # Default time to wait after each browser action performed during Demo Mode. # Use Demo Mode when you want others to see what your automation is doing. # Usage: "--demo_mode". (Can be overwritten by using "--demo_sleep=TIME".) -DEFAULT_DEMO_MODE_TIMEOUT = 1.0 +DEFAULT_DEMO_MODE_TIMEOUT = 0.5 # Number of times to repeat the demo_mode highlight animation. # Each loop is about 0.18 seconds. (Override by using "--highlights=TIMES".) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index bb848bb2f64..3b365b8c5c2 100755 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -12,16 +12,20 @@ from seleniumbase.fixtures import page_utils import drivers # webdriver storage folder for SeleniumBase DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__)) +PLATFORM = sys.platform LOCAL_CHROMEDRIVER = None LOCAL_GECKODRIVER = None LOCAL_EDGEDRIVER = None -if "darwin" in sys.platform or "linux" in sys.platform: +LOCAL_OPERADRIVER = None +if "darwin" in PLATFORM or "linux" in PLATFORM: LOCAL_CHROMEDRIVER = DRIVER_DIR + '/chromedriver' LOCAL_GECKODRIVER = DRIVER_DIR + '/geckodriver' -elif "win32" in sys.platform or "win64" in sys.platform: + LOCAL_OPERADRIVER = DRIVER_DIR + '/operadriver' +elif "win32" in PLATFORM or "win64" in PLATFORM or "x64" in PLATFORM: LOCAL_EDGEDRIVER = DRIVER_DIR + '/MicrosoftWebDriver.exe' LOCAL_CHROMEDRIVER = DRIVER_DIR + '/chromedriver.exe' LOCAL_GECKODRIVER = DRIVER_DIR + '/geckodriver.exe' + LOCAL_OPERADRIVER = DRIVER_DIR + '/operadriver.exe' else: # Cannot determine system pass # SeleniumBase will use web drivers from the System PATH by default @@ -217,6 +221,11 @@ def get_remote_driver(browser_name, headless, servername, port, proxy_string): command_executor=address, desired_capabilities=( webdriver.DesiredCapabilities.SAFARI)) + elif browser_name == constants.Browser.OPERA: + return webdriver.Remote( + command_executor=address, + desired_capabilities=( + webdriver.DesiredCapabilities.OPERA)) elif browser_name == constants.Browser.PHANTOM_JS: with warnings.catch_warnings(): # Ignore "PhantomJS has been deprecated" UserWarning @@ -282,6 +291,12 @@ def get_local_driver(browser_name, headless, proxy_string): return webdriver.Edge(capabilities=edge_capabilities) elif browser_name == constants.Browser.SAFARI: return webdriver.Safari() + elif browser_name == constants.Browser.OPERA: + if LOCAL_OPERADRIVER and os.path.exists(LOCAL_OPERADRIVER): + make_driver_executable_if_not(LOCAL_OPERADRIVER) + return webdriver.Opera(executable_path=LOCAL_OPERADRIVER) + else: + return webdriver.Opera() elif browser_name == constants.Browser.PHANTOM_JS: with warnings.catch_warnings(): # Ignore "PhantomJS has been deprecated" UserWarning diff --git a/seleniumbase/fixtures/constants.py b/seleniumbase/fixtures/constants.py index fdc06ae1131..156f476cb56 100755 --- a/seleniumbase/fixtures/constants.py +++ b/seleniumbase/fixtures/constants.py @@ -18,33 +18,37 @@ class Files: class ValidBrowsers: - valid_browsers = ["firefox", "ie", "edge", "safari", "chrome", "phantomjs"] + valid_browsers = ( + ["chrome", "edge", "firefox", "ie", "opera", "phantomjs", "safari"]) class Browser: + GOOGLE_CHROME = "chrome" + EDGE = "edge" FIREFOX = "firefox" INTERNET_EXPLORER = "ie" - EDGE = "edge" - SAFARI = "safari" - GOOGLE_CHROME = "chrome" + OPERA = "opera" PHANTOM_JS = "phantomjs" + SAFARI = "safari" VERSION = { + "chrome": None, + "edge": None, "firefox": None, "ie": None, - "edge": None, - "safari": None, - "chrome": None, - "phantomjs": None + "opera": None, + "phantomjs": None, + "safari": None } LATEST = { + "chrome": None, + "edge": None, "firefox": None, "ie": None, - "edge": None, - "safari": None, - "chrome": None, - "phantomjs": None + "opera": None, + "phantomjs": None, + "safari": None } diff --git a/seleniumbase/masterqa/ReadMe.md b/seleniumbase/masterqa/ReadMe.md index f28d8b82b70..ee0a58a5790 100755 --- a/seleniumbase/masterqa/ReadMe.md +++ b/seleniumbase/masterqa/ReadMe.md @@ -1,6 +1,6 @@ # MasterQA -### MasterQA combines SeleniumBase automation with manual verification to greatly improve the productivity and sanity of QA teams. (**Works only for Chrome right now.**) +### MasterQA combines SeleniumBase automation with manual verification to greatly improve the productivity and sanity of QA teams. (**Works only for Chrome & Edge right now.**) ![](http://cdn2.hubspot.net/hubfs/100006/images/masterqa_gif.gif "MasterQA") diff --git a/setup.py b/setup.py index d1d2e1fd215..3d562531f9c 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name='seleniumbase', - version='1.13.2', + version='1.13.3', description='Web Automation & Testing Framework - http://seleniumbase.com', long_description='Web Automation and Testing Framework - seleniumbase.com', platforms='Mac * Windows * Linux * Docker',