From f6d8e5ad2d91fdcbb7a5bbb6378a14771b3f8a11 Mon Sep 17 00:00:00 2001 From: byron Date: Tue, 27 Aug 2019 13:43:26 -0400 Subject: [PATCH 1/8] tmp save --- dash/testing/browser.py | 17 +++++++++-------- dash/testing/plugin.py | 23 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 85f3fd678c..18526e4121 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -32,21 +32,24 @@ class Browser(DashPageMixin): def __init__( self, browser, + remote=False, + remote_url=None, headless=False, options=None, - remote=None, download_path=None, percy_finalize=True, wait_timeout=10, ): self._browser = browser.lower() + self._remote_url = remote_url + self._remote = remote self._headless = headless self._options = options self._download_path = download_path self._wait_timeout = wait_timeout self._percy_finalize = percy_finalize - self._driver = until(lambda: self.get_webdriver(remote), timeout=1) + self._driver = until(lambda: self.get_webdriver(), timeout=1) self._driver.implicitly_wait(2) self._wd_wait = WebDriverWait(self.driver, wait_timeout) @@ -285,16 +288,14 @@ def open_new_tab(self, url=None): ) ) - def get_webdriver(self, remote): + def get_webdriver(self): try: return ( getattr(self, "_get_{}".format(self._browser))() - if remote is None + if not self._remote else webdriver.Remote( - command_executor=remote, - desired_capabilities=getattr( - DesiredCapabilities, self._browser.upper() - ), + command_executor=self._remote_url, + desired_capabilities={'browserName': self._browser} ) ) except WebDriverException: diff --git a/dash/testing/plugin.py b/dash/testing/plugin.py index b6b8d48f10..256e31bd55 100644 --- a/dash/testing/plugin.py +++ b/dash/testing/plugin.py @@ -14,12 +14,10 @@ except ImportError: warnings.warn("run `pip install dash[testing]` if you need dash.testing") -WEBDRIVERS = {"Chrome", "Firefox", "Remote"} +WEBDRIVERS = {"Chrome", "Firefox"} def pytest_addoption(parser): - # Add options to the pytest parser, either on the commandline or ini - # TODO add more options for the selenium driver. dash = parser.getgroup("Dash", "Dash Integration Tests") dash.addoption( @@ -29,6 +27,19 @@ def pytest_addoption(parser): help="Name of the selenium driver to use", ) + dash.addoption( + "--remote", + action="store_true", + help="instruct pytest to use selenium grid" + ) + + dash.addoption( + "--remote_url", + action="store", + default="http://localhost:4444/wd/hub", + help="set a different selenium grid remote url if other than default" + ) + dash.addoption( "--headless", action="store_true", @@ -99,6 +110,8 @@ def dashr_server(): def dash_br(request, tmpdir): with Browser( browser=request.config.getoption("webdriver"), + remote=request.config.getoption("remote"), + remote_url=request.config.getoption("remote_url"), headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, @@ -112,6 +125,8 @@ def dash_duo(request, dash_thread_server, tmpdir): with DashComposite( dash_thread_server, browser=request.config.getoption("webdriver"), + remote=request.config.getoption("remote"), + remote_url=request.config.getoption("remote_url"), headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, @@ -125,6 +140,8 @@ def dashr(request, dashr_server, tmpdir): with DashRComposite( dashr_server, browser=request.config.getoption("webdriver"), + remote=request.config.getoption("remote"), + remote_url=request.config.getoption("remote_url"), headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, From 19e8063a92ba1bb2ea3028e5d536af2ed8725704 Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 12:42:40 -0400 Subject: [PATCH 2/8] :sparkles: :bug: add true remote for selenium --- dash/testing/browser.py | 36 ++++++++++++++++++++++-------------- dash/testing/plugin.py | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 18526e4121..6415325743 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -49,7 +49,7 @@ def __init__( self._wait_timeout = wait_timeout self._percy_finalize = percy_finalize - self._driver = until(lambda: self.get_webdriver(), timeout=1) + self._driver = until(self.get_webdriver, timeout=1) self._driver.implicitly_wait(2) self._wd_wait = WebDriverWait(self.driver, wait_timeout) @@ -290,17 +290,9 @@ def open_new_tab(self, url=None): def get_webdriver(self): try: - return ( - getattr(self, "_get_{}".format(self._browser))() - if not self._remote - else webdriver.Remote( - command_executor=self._remote_url, - desired_capabilities={'browserName': self._browser} - ) - ) + return getattr(self, "_get_{}".format(self._browser))() except WebDriverException: logger.exception("<<>>") - return None def _get_wd_options(self): options = ( @@ -334,8 +326,16 @@ def _get_chrome(self): }, ) - chrome = webdriver.Chrome( - options=options, desired_capabilities=capabilities + chrome = ( + webdriver.Remote( + command_executor=self._remote_url, + options=options, + desired_capabilities=capabilities, + ) + if self._remote + else webdriver.Chrome( + options=options, desired_capabilities=capabilities + ) ) # https://bugs.chromium.org/p/chromium/issues/detail?id=696481 @@ -373,8 +373,16 @@ def _get_firefox(self): "browser.helperApps.neverAsk.saveToDisk", "application/octet-stream", # this MIME is generic for binary ) - return webdriver.Firefox( - firefox_profile=fp, options=options, capabilities=capabilities + return ( + webdriver.Remote( + command_executor=self._remote_url, + options=options, + desired_capabilities=capabilities, + ) + if self._remote + else webdriver.Firefox( + firefox_profile=fp, options=options, capabilities=capabilities + ) ) @staticmethod diff --git a/dash/testing/plugin.py b/dash/testing/plugin.py index 256e31bd55..fb94455dee 100644 --- a/dash/testing/plugin.py +++ b/dash/testing/plugin.py @@ -34,7 +34,7 @@ def pytest_addoption(parser): ) dash.addoption( - "--remote_url", + "--remote-url", action="store", default="http://localhost:4444/wd/hub", help="set a different selenium grid remote url if other than default" From 35f4750828733aa205b9d0be4ca4f06a2bb619e3 Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 12:46:54 -0400 Subject: [PATCH 3/8] :pencil: changelog --- dash/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index bfaafb1f05..444db0060c 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -1,3 +1,9 @@ +## Unreleased + +### Fixed + +- [#829](https://github.com/plotly/dash/issues/829) Fixes the `--remote` pytest argument which was not effective in the code, adding a new argument `--remote-url` to support the selenium grid usage in the cloud. + ## [1.2.0] - 2019-08-27 ### Added - [#860](https://github.com/plotly/dash/pull/860) Adds a new arg `dev_tools_prune_errors` to `app.run_server` and `app.enable_dev_tools`. Default `True`, tracebacks only include user code and below. Set it to `False` for the previous behavior showing all the Dash and Flask parts of the stack. From 761728b9492cc066e2874a6643c6212961263ee8 Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 13:26:32 -0400 Subject: [PATCH 4/8] add a shortcut for remote --- dash/testing/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 6415325743..40d3227ade 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -42,7 +42,7 @@ def __init__( ): self._browser = browser.lower() self._remote_url = remote_url - self._remote = remote + self._remote = True if remote_url else remote self._headless = headless self._options = options self._download_path = download_path From 91e1a66c992ed7cce678f6adaecfbea0e1f82bab Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 13:43:40 -0400 Subject: [PATCH 5/8] :bug: prevent the wrong signal from default setting --- dash/testing/browser.py | 7 ++++++- dash/testing/plugin.py | 8 +++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 40d3227ade..2b43ede678 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -23,6 +23,7 @@ ) from dash.testing.dash_page import DashPageMixin from dash.testing.errors import DashAppLoadingError, BrowserError +from dash.testing.plugin import SELENIUM_GRID_DEFAULT logger = logging.getLogger(__name__) @@ -42,7 +43,11 @@ def __init__( ): self._browser = browser.lower() self._remote_url = remote_url - self._remote = True if remote_url else remote + self._remote = ( + True + if remote_url and remote_url != SELENIUM_GRID_DEFAULT + else remote + ) self._headless = headless self._options = options self._download_path = download_path diff --git a/dash/testing/plugin.py b/dash/testing/plugin.py index fb94455dee..26a97c43bb 100644 --- a/dash/testing/plugin.py +++ b/dash/testing/plugin.py @@ -1,6 +1,8 @@ # pylint: disable=missing-docstring,redefined-outer-name import warnings +SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" + try: import pytest @@ -30,14 +32,14 @@ def pytest_addoption(parser): dash.addoption( "--remote", action="store_true", - help="instruct pytest to use selenium grid" + help="instruct pytest to use selenium grid", ) dash.addoption( "--remote-url", action="store", - default="http://localhost:4444/wd/hub", - help="set a different selenium grid remote url if other than default" + default=SELENIUM_GRID_DEFAULT, + help="set a different selenium grid remote url if other than default", ) dash.addoption( From 683622070c3f77d6a69bca9447a1b82ccf9e3858 Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 15:03:04 -0400 Subject: [PATCH 6/8] no cyclic --- dash/testing/browser.py | 2 +- dash/testing/consts.py | 1 + dash/testing/plugin.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 dash/testing/consts.py diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 2b43ede678..0283845202 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -23,7 +23,7 @@ ) from dash.testing.dash_page import DashPageMixin from dash.testing.errors import DashAppLoadingError, BrowserError -from dash.testing.plugin import SELENIUM_GRID_DEFAULT +from dash.testing.consts import SELENIUM_GRID_DEFAULT logger = logging.getLogger(__name__) diff --git a/dash/testing/consts.py b/dash/testing/consts.py new file mode 100644 index 0000000000..3c0dfed509 --- /dev/null +++ b/dash/testing/consts.py @@ -0,0 +1 @@ +SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" \ No newline at end of file diff --git a/dash/testing/plugin.py b/dash/testing/plugin.py index 26a97c43bb..847928b7bc 100644 --- a/dash/testing/plugin.py +++ b/dash/testing/plugin.py @@ -1,7 +1,7 @@ # pylint: disable=missing-docstring,redefined-outer-name import warnings +from .consts import SELENIUM_GRID_DEFAULT -SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" try: import pytest From 5f206dad5e1d14adf53cfb2ce0e8e423b0d1e73a Mon Sep 17 00:00:00 2001 From: byron Date: Thu, 29 Aug 2019 15:07:24 -0400 Subject: [PATCH 7/8] :see_no_evil: I should set auto add newline --- dash/testing/consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/testing/consts.py b/dash/testing/consts.py index 3c0dfed509..ea62a2971b 100644 --- a/dash/testing/consts.py +++ b/dash/testing/consts.py @@ -1 +1 @@ -SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" \ No newline at end of file +SELENIUM_GRID_DEFAULT = "http://localhost:4444/wd/hub" From af862683cfc834c2a15e9e160a318eaf11411da1 Mon Sep 17 00:00:00 2001 From: byron Date: Mon, 2 Sep 2019 22:16:42 -0400 Subject: [PATCH 8/8] add unit tests for simple argument checks --- tests/unit/test_browser.py | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/unit/test_browser.py diff --git a/tests/unit/test_browser.py b/tests/unit/test_browser.py new file mode 100644 index 0000000000..a7aff954bb --- /dev/null +++ b/tests/unit/test_browser.py @@ -0,0 +1,44 @@ +import pytest +from dash.testing.browser import Browser +from dash.testing.consts import SELENIUM_GRID_DEFAULT + + +@pytest.mark.parametrize("browser_type", ("Chrome", "Firefox")) +def test_browser_smoke(browser_type, tmpdir): + + browser = Browser( + browser=browser_type, + remote=False, + remote_url=SELENIUM_GRID_DEFAULT, + headless=True, + options=None, + download_path=tmpdir.mkdir("download").strpath, + percy_finalize=True, + ) + assert browser.driver.name == browser_type.lower() + + +def test_browser_use_remote_webdriver(tmpdir): + # test creation with remote=True + with pytest.raises(Exception): + Browser( + browser="Chrome", + remote=True, + remote_url=SELENIUM_GRID_DEFAULT, + headless=True, + options=None, + download_path=tmpdir.mkdir("download").strpath, + percy_finalize=True, + ) + + # test creation with remote_url other than default + with pytest.raises(Exception): + Browser( + browser="Chrome", + remote=False, + remote_url="http://token@any.selenium.grid:3333", + headless=True, + options=None, + download_path=tmpdir.mkdir("download").strpath, + percy_finalize=True, + )