From ed6950c5cf7e8ad86099212003161b7b53692b3b Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 17:27:41 -0500 Subject: [PATCH 01/12] Add nosetests option for Demo Mode --- seleniumbase/plugins/selenium_plugin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index 9917e30c1db..d730a232c40 100755 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -46,6 +46,11 @@ def options(self, parser, env): default='4444', help="""Designates the port used by the test. Default: 4444.""") + parser.add_option('--demo_mode', action="store_true", + dest='demo_mode', + default=False, + help="""Using this slows down the automation so that + you can see what it's actually doing.""") def configure(self, options, conf): super(SeleniumBrowser, self).configure(options, conf) @@ -95,6 +100,7 @@ def beforeTest(self, test): else: version = "" test.test.browser = "%s%s" % (self.options.browser, version) + test.test.demo_mode = self.options.demo_mode except Exception as err: print "Error starting/connecting to Selenium:" print err From 9a7bcf09c84b2fa81cdb465a186186ef1d21524d Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 17:27:56 -0500 Subject: [PATCH 02/12] Add pytest option for Demo Mode --- conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/conftest.py b/conftest.py index 75007b42244..6e5657f1e00 100755 --- a/conftest.py +++ b/conftest.py @@ -34,6 +34,11 @@ def pytest_addoption(parser): parser.addoption('--log_path', dest='log_path', default='logs/', help='Where the log files are saved.') + parser.addoption('--demo_mode', action="store_true", + dest='demo_mode', + default=False, + help="""Using this slows down the automation so that + you can see what it's actually doing.""") def pytest_configure(config): @@ -41,6 +46,7 @@ def pytest_configure(config): with_testing_base = config.getoption('with_testing_base') browser = config.getoption('browser') log_path = config.getoption('log_path') + demo_mode = config.getoption('demo_mode') data = '' if config.getoption('data') is not None: data = config.getoption('data') @@ -52,6 +58,7 @@ def pytest_configure(config): config_file.write("data:::%s\n" % data) config_file.write("with_testing_base:::%s\n" % with_testing_base) config_file.write("log_path:::%s\n" % log_path) + config_file.write("demo_mode:::%s\n" % demo_mode) config_file.close() log_folder_setup(config) From 142ee4e1856b7c7eee7841f55b82b32862f018db Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 17:29:14 -0500 Subject: [PATCH 03/12] Add Demo Mode functionality --- seleniumbase/config/settings.py | 5 +++++ seleniumbase/fixtures/base_case.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/seleniumbase/config/settings.py b/seleniumbase/config/settings.py index 6ae63fc1784..d710c2d38f9 100755 --- a/seleniumbase/config/settings.py +++ b/seleniumbase/config/settings.py @@ -10,6 +10,11 @@ LARGE_TIMEOUT = 10 EXTREME_TIMEOUT = 30 +# 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 when run from the command line when using --with-selenium +DEMO_MODE_TIMEOUT = 1.2 + # If True, existing logs from past test runs will be saved and take up space. # If False, only the logs from the most recent test run will be saved locally. # This has no effect on Jenkins/S3/MySQL, which may still be saving test logs. diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 84bac6e87bb..7764fb668f7 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -38,6 +38,7 @@ def open(self, url): self.driver.get(url) if settings.WAIT_FOR_RSC_ON_PAGE_LOADS: self.wait_for_ready_state_complete() + self._demo_mode_pause_if_active() def open_url(self, url): """ In case people are mixing up self.open() with open(), @@ -48,9 +49,11 @@ def click(self, selector, by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT): element = page_actions.wait_for_element_visible( self.driver, selector, by, timeout=timeout) + self._demo_mode_scroll_if_active(selector, by) element.click() if settings.WAIT_FOR_RSC_ON_CLICKS: self.wait_for_ready_state_complete() + self._demo_mode_pause_if_active() def click_chain(self, selectors_list, by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT, spacing=0): @@ -66,12 +69,14 @@ def click_link_text(self, link_text, timeout=settings.SMALL_TIMEOUT): element.click() if settings.WAIT_FOR_RSC_ON_CLICKS: self.wait_for_ready_state_complete() + self._demo_mode_pause_if_active() def add_text(self, selector, new_value, timeout=settings.SMALL_TIMEOUT): """ The more-reliable version of driver.send_keys() Similar to update_text(), but won't clear the text field first. """ element = self.wait_for_element_visible(selector, timeout=timeout) element.send_keys(new_value) + self._demo_mode_pause_if_active() def send_keys(self, selector, new_value, timeout=settings.SMALL_TIMEOUT): """ Same as add_text() -> more reliable, but less name confusion. """ @@ -88,12 +93,14 @@ def update_text_value(self, selector, new_value, """ element = self.wait_for_element_visible(selector, timeout=timeout) element.clear() + self._demo_mode_pause_if_active(tiny=True) element.send_keys(new_value) if (retry and element.get_attribute('value') != new_value and ( not new_value.endswith('\n'))): logging.debug('update_text_value is falling back to jQuery!') selector = self.jq_format(selector) self.set_value(selector, new_value) + self._demo_mode_pause_if_active() def update_text(self, selector, new_value, timeout=settings.SMALL_TIMEOUT, retry=False): @@ -124,9 +131,11 @@ def execute_script(self, script): def set_window_size(self, width, height): return self.driver.set_window_size(width, height) + self._demo_mode_pause_if_active() def maximize_window(self): return self.driver.maximize_window() + self._demo_mode_pause_if_active() def activate_jquery(self): """ (It's not on by default on all website pages.) """ @@ -140,6 +149,7 @@ def scroll_to(self, selector): self.wait_for_element_visible(selector, timeout=settings.SMALL_TIMEOUT) self.driver.execute_script( "jQuery('%s')[0].scrollIntoView()" % selector) + self._demo_mode_pause_if_active(tiny=True) def scroll_click(self, selector): self.scroll_to(selector) @@ -147,6 +157,7 @@ def scroll_click(self, selector): def jquery_click(self, selector): self.driver.execute_script("jQuery('%s').click()" % selector) + self._demo_mode_pause_if_active() def jq_format(self, code): return page_utils.jq_format(code) @@ -154,6 +165,7 @@ def jq_format(self, code): def set_value(self, selector, value): val = json.dumps(value) self.driver.execute_script("jQuery('%s').val(%s)" % (selector, val)) + self._demo_mode_pause_if_active() def jquery_update_text_value(self, selector, new_value, timeout=settings.SMALL_TIMEOUT): @@ -162,6 +174,7 @@ def jquery_update_text_value(self, selector, new_value, % (selector, self.jq_format(new_value))) if new_value.endswith('\n'): element.send_keys('\n') + self._demo_mode_pause_if_active() def jquery_update_text(self, selector, new_value, timeout=settings.SMALL_TIMEOUT): @@ -175,6 +188,7 @@ def hover_and_click(self, hover_selector, click_selector, timeout=settings.SMALL_TIMEOUT): return page_actions.hover_and_click(self.driver, hover_selector, click_selector, click_by, timeout) + self._demo_mode_pause_if_active() def wait_for_element_present(self, selector, by=By.CSS_SELECTOR, timeout=settings.LARGE_TIMEOUT): @@ -221,6 +235,19 @@ def wait_for_and_switch_to_alert(self, timeout=settings.LARGE_TIMEOUT): def save_screenshot(self, name, folder=None): return page_actions.save_screenshot(self.driver, name, folder) + def _demo_mode_pause_if_active(self, tiny=False): + if self.demo_mode: + if not tiny: + time.sleep(settings.DEMO_MODE_TIMEOUT) + else: + time.sleep(settings.DEMO_MODE_TIMEOUT/3.0) + + def _demo_mode_scroll_if_active(self, selector, by): + if self.demo_mode: + if by == By.CSS_SELECTOR: + self.scroll_to(selector) + + # PyTest-Specific Code # def setUp(self): @@ -243,6 +270,7 @@ def setUp(self): self.log_path = pytest.config.option.log_path self.browser = pytest.config.option.browser self.data = pytest.config.option.data + self.demo_mode = pytest.config.option.demo_mode if self.with_selenium: self.driver = browser_launcher.get_driver(self.browser) From f9f6dc0abd9f456585170316da110313c0a987bc Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 17:31:26 -0500 Subject: [PATCH 04/12] Deflake pytest config file --- conftest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conftest.py b/conftest.py index 6e5657f1e00..ca1397a3181 100755 --- a/conftest.py +++ b/conftest.py @@ -35,10 +35,10 @@ def pytest_addoption(parser): default='logs/', help='Where the log files are saved.') parser.addoption('--demo_mode', action="store_true", - dest='demo_mode', - default=False, - help="""Using this slows down the automation so that - you can see what it's actually doing.""") + dest='demo_mode', + default=False, + help="""Using this slows down the automation so that + you can see what it's actually doing.""") def pytest_configure(config): From c2968021ed4454436ede3fcf03ebef59e8e87500 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 18:33:14 -0500 Subject: [PATCH 05/12] Updated ReadMe for Demo Mode --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d6d09112c13..a2012f597fe 100755 --- a/README.md +++ b/README.md @@ -199,11 +199,19 @@ nosetests my_first_test.py --browser=firefox --with-selenium -s ``` After the test completes, in the console output you'll see a dot on a new line, representing a passing test. (On test failures you'll see an F instead, and on test errors you'll see an E). It looks more like a moving progress bar when you're running a ton of unit tests side by side. This is part of nosetests. After all tests complete (in this case there is only one), you'll see the "Ran 1 test in ..." line, followed by an "OK" if all nosetests passed. -If the example is moving too fast for your eyes to see what's going on, there are 2 things you can do. Add either of the following: + +If the example is moving too fast for your eyes to see what's going on, there are a few things you can do. +You can add ``--demo_mode`` on the command line, which pauses the browser after each action: + +```bash +nosetests my_first_test.py --with-selenium -s --demo_mode +``` + +You can also add either of the following to your scripts: ```python -import time; time.sleep(5) # sleep for 5 seconds (add this after the line you want to pause on) -import ipdb; ipdb.set_trace() # waits for your command. n = next line of current method, c = continue, s = step / next executed line (will jump) +import time; time.sleep(5) # sleep for 5 seconds (add this after the line you want to pause on) +import ipdb; ipdb.set_trace() # waits for your command. n = next line of current method, c = continue, s = step / next executed line (will jump) ``` (NOTE: If you're using pytest instead of nosetests and you want to use ipdb in your script for debugging purposes, you'll either need to add "--capture=no" on the command line, or use "import pytest; pytest.set_trace()" instead of using ipdb. More info on that [here](http://stackoverflow.com/questions/2678792/can-i-debug-with-python-debugger-when-using-py-test-somehow).) From 0bbe9807d36f936f1b3a9409c44de8782f0f62b8 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 19:00:46 -0500 Subject: [PATCH 06/12] Runtime option to override Demo Mode sleep time (nosetests) --- seleniumbase/plugins/selenium_plugin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index d730a232c40..df506f8d4fb 100755 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -51,6 +51,10 @@ def options(self, parser, env): default=False, help="""Using this slows down the automation so that you can see what it's actually doing.""") + parser.add_option('--demo_sleep', action='store', dest='demo_sleep', + default=None, + help="""Setting this overrides the Demo Mode sleep + time that happens after browser actions.""") def configure(self, options, conf): super(SeleniumBrowser, self).configure(options, conf) @@ -101,6 +105,7 @@ def beforeTest(self, test): version = "" test.test.browser = "%s%s" % (self.options.browser, version) test.test.demo_mode = self.options.demo_mode + test.test.demo_sleep = self.options.demo_sleep except Exception as err: print "Error starting/connecting to Selenium:" print err From 6f2413a1902aee4651645c5c48c919ca826ee219 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 19:01:14 -0500 Subject: [PATCH 07/12] Runtime option to override Demo Mode sleep time (pytest) --- conftest.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/conftest.py b/conftest.py index ca1397a3181..50829f86204 100755 --- a/conftest.py +++ b/conftest.py @@ -39,6 +39,10 @@ def pytest_addoption(parser): default=False, help="""Using this slows down the automation so that you can see what it's actually doing.""") + parser.addoption('--demo_sleep', action='store', dest='demo_sleep', + default=None, + help="""Setting this overrides the Demo Mode sleep + time that happens after browser actions.""") def pytest_configure(config): @@ -47,7 +51,10 @@ def pytest_configure(config): browser = config.getoption('browser') log_path = config.getoption('log_path') demo_mode = config.getoption('demo_mode') + demo_sleep = '' data = '' + if config.getoption('demo_sleep') is not None: + demo_sleep = config.getoption('demo_sleep') if config.getoption('data') is not None: data = config.getoption('data') # Create a temporary config file while tests are running @@ -59,6 +66,7 @@ def pytest_configure(config): config_file.write("with_testing_base:::%s\n" % with_testing_base) config_file.write("log_path:::%s\n" % log_path) config_file.write("demo_mode:::%s\n" % demo_mode) + config_file.write("demo_sleep:::%s\n" % demo_sleep) config_file.close() log_folder_setup(config) From 59628c3d6044c835fa67f6487a5467549c1449cd Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 19:04:14 -0500 Subject: [PATCH 08/12] Using the command line demo_sleep value to override settings --- seleniumbase/fixtures/base_case.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 7764fb668f7..8a490e2d950 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -237,10 +237,14 @@ def save_screenshot(self, name, folder=None): def _demo_mode_pause_if_active(self, tiny=False): if self.demo_mode: + if self.demo_sleep: + wait_time = float(self.demo_sleep) + else: + wait_time = settings.DEFAULT_DEMO_MODE_TIMEOUT if not tiny: - time.sleep(settings.DEMO_MODE_TIMEOUT) + time.sleep(wait_time) else: - time.sleep(settings.DEMO_MODE_TIMEOUT/3.0) + time.sleep(wait_time/3.0) def _demo_mode_scroll_if_active(self, selector, by): if self.demo_mode: @@ -271,6 +275,7 @@ def setUp(self): self.browser = pytest.config.option.browser self.data = pytest.config.option.data self.demo_mode = pytest.config.option.demo_mode + self.demo_sleep = pytest.config.option.demo_sleep if self.with_selenium: self.driver = browser_launcher.get_driver(self.browser) From fdb45f61bccc2e7945e413e2fe79056b07f22a79 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 19:05:43 -0500 Subject: [PATCH 09/12] Using the renamed variable, and adding commentary --- seleniumbase/config/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seleniumbase/config/settings.py b/seleniumbase/config/settings.py index d710c2d38f9..c1a9d64ce71 100755 --- a/seleniumbase/config/settings.py +++ b/seleniumbase/config/settings.py @@ -13,7 +13,8 @@ # 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 when run from the command line when using --with-selenium -DEMO_MODE_TIMEOUT = 1.2 +# This value can be overwritten on the command line by using --demo_sleep=FLOAT +DEFAULT_DEMO_MODE_TIMEOUT = 1.2 # If True, existing logs from past test runs will be saved and take up space. # If False, only the logs from the most recent test run will be saved locally. From b2c8f4a1fe97fe82ef06922381449fe7b5084373 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 19:08:12 -0500 Subject: [PATCH 10/12] Update the ReadMe with the new demo_sleep specification --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2012f597fe..c05d6780735 100755 --- a/README.md +++ b/README.md @@ -201,13 +201,19 @@ nosetests my_first_test.py --browser=firefox --with-selenium -s After the test completes, in the console output you'll see a dot on a new line, representing a passing test. (On test failures you'll see an F instead, and on test errors you'll see an E). It looks more like a moving progress bar when you're running a ton of unit tests side by side. This is part of nosetests. After all tests complete (in this case there is only one), you'll see the "Ran 1 test in ..." line, followed by an "OK" if all nosetests passed. If the example is moving too fast for your eyes to see what's going on, there are a few things you can do. -You can add ``--demo_mode`` on the command line, which pauses the browser after each action: +You can add ``--demo_mode`` on the command line, which pauses the browser for about a second (by default) after each action: ```bash nosetests my_first_test.py --with-selenium -s --demo_mode ``` -You can also add either of the following to your scripts: +You can override the default wait time by either updating [settings.py](https://github.com/mdmintz/SeleniumBase/blob/master/seleniumbase/config/settings.py) or by using ``--demo_sleep={NUM}`` when using Demo Mode. (NOTE: If you use ``--demo_sleep={NUM}`` without using ``--demo_mode``, nothing will happen.) + +```bash +nosetests my_first_test.py --with-selenium -s --demo_mode --demo_sleep=1.2 +``` + +You can also add either of the following to your scripts to slow down the tests: ```python import time; time.sleep(5) # sleep for 5 seconds (add this after the line you want to pause on) From 2e838e6c4da91fb12246b65c28d2b808b3b52d3e Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 20:48:59 -0500 Subject: [PATCH 11/12] I had a lot of fun with jQuery last night. --- seleniumbase/fixtures/base_case.py | 43 ++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 8a490e2d950..f9dccbb9915 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -138,17 +138,40 @@ def maximize_window(self): self._demo_mode_pause_if_active() def activate_jquery(self): - """ (It's not on by default on all website pages.) """ + """ If "jQuery is not defined", use this method to activate it for use. + This happens because jQuery is not always defined on web sites. """ + try: + # Let's first find out if jQuery is already defined. + self.driver.execute_script("jQuery('html')") + # Since that command worked, jQuery is defined. Let's return. + return + except Exception: + # jQuery is not currently defined. Let's proceed by defining it. + pass self.driver.execute_script( '''var script = document.createElement("script"); ''' '''script.src = "https://ajax.googleapis.com/ajax/libs/jquery/1/''' '''jquery.min.js"; document.getElementsByTagName("head")[0]''' '''.appendChild(script);''') + for x in xrange(30): + # jQuery needs a small amount of time to activate. (At most 3s) + try: + self.driver.execute_script("jQuery('html')") + return + except Exception: + time.sleep(0.1) + # Since jQuery still isn't activating, give up and raise an exception + raise Exception("Exception: WebDriver could not activate jQuery!") def scroll_to(self, selector): self.wait_for_element_visible(selector, timeout=settings.SMALL_TIMEOUT) - self.driver.execute_script( - "jQuery('%s')[0].scrollIntoView()" % selector) + scroll_script = "jQuery('%s')[0].scrollIntoView()" % selector + try: + self.driver.execute_script(scroll_script) + except Exception: + # The likely reason this fails is because: "jQuery is not defined" + self.activate_jquery() # It's a good thing we can define it here + self.driver.execute_script(scroll_script) self._demo_mode_pause_if_active(tiny=True) def scroll_click(self, selector): @@ -156,6 +179,7 @@ def scroll_click(self, selector): self.click(selector) def jquery_click(self, selector): + self.scroll_to(selector) self.driver.execute_script("jQuery('%s').click()" % selector) self._demo_mode_pause_if_active() @@ -163,6 +187,7 @@ def jq_format(self, code): return page_utils.jq_format(code) def set_value(self, selector, value): + self.scroll_to(selector) val = json.dumps(value) self.driver.execute_script("jQuery('%s').val(%s)" % (selector, val)) self._demo_mode_pause_if_active() @@ -170,6 +195,7 @@ def set_value(self, selector, value): def jquery_update_text_value(self, selector, new_value, timeout=settings.SMALL_TIMEOUT): element = self.wait_for_element_visible(selector, timeout=timeout) + self.scroll_to(selector) self.driver.execute_script("""jQuery('%s').val('%s')""" % (selector, self.jq_format(new_value))) if new_value.endswith('\n'): @@ -181,14 +207,21 @@ def jquery_update_text(self, selector, new_value, self.jquery_update_text_value(selector, new_value, timeout=timeout) def hover_on_element(self, selector): + self.wait_for_element_visible(selector, timeout=settings.SMALL_TIMEOUT) + self.scroll_to(selector) + time.sleep(0.05) # Settle down from scrolling before hovering return page_actions.hover_on_element(self.driver, selector) def hover_and_click(self, hover_selector, click_selector, click_by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT): - return page_actions.hover_and_click(self.driver, hover_selector, - click_selector, click_by, timeout) + self.wait_for_element_visible(hover_selector, timeout=timeout) + self.scroll_to(hover_selector) + # Settle down from the scrolling before hovering + element = page_actions.hover_and_click( + self.driver, hover_selector, click_selector, click_by, timeout) self._demo_mode_pause_if_active() + return element def wait_for_element_present(self, selector, by=By.CSS_SELECTOR, timeout=settings.LARGE_TIMEOUT): From 5396e0d00b17b73846b682d64a870a1be361f818 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sat, 16 Jan 2016 20:52:22 -0500 Subject: [PATCH 12/12] Version upgraded to 1.1.16 --- docker/docker_setup.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/docker_setup.py b/docker/docker_setup.py index 89e17d791c4..baacb1bf155 100755 --- a/docker/docker_setup.py +++ b/docker/docker_setup.py @@ -8,7 +8,7 @@ setup( name='seleniumbase', - version='1.1.15', + version='1.1.16', author='Michael Mintz', author_email='@mintzworld', maintainer='Michael Mintz', diff --git a/setup.py b/setup.py index a67ae6b3a15..a1cc0e35c39 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='seleniumbase', - version='1.1.15', + version='1.1.16', url='https://github.com/mdmintz/SeleniumBase', author='Michael Mintz', author_email='@mintzworld',