Skip to content
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

Headless mode #805

Merged
merged 9 commits into from
Jul 5, 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
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ valid-metaclass-classmethod-first-arg=mcs
[DESIGN]

# Maximum number of arguments for function / method
max-args=5
max-args=10

# Maximum number of attributes for a class (see R0902).
max-attributes=20
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc37
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ valid-metaclass-classmethod-first-arg=mcs
[DESIGN]

# Maximum number of arguments for function / method.
max-args=5
max-args=10

# Maximum number of attributes for a class (see R0902).
max-attributes=20
Expand Down
2 changes: 2 additions & 0 deletions dash/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
- 💥 [#808](https://github.com/plotly/dash/pull/808) Remove strong `dash.testing` dependencies per community feedbacks.
Testing users should do `pip install dash[testing]` afterwards.

- [#805](https://github.com/plotly/dash/pull/805) Add headless mode for dash.testing, add `pytest_setup_options` hook for full configuration of `WebDriver Options`.

## [1.0.0] - 2019-06-20
### Changed
- 💥 [#761](https://github.com/plotly/dash/pull/761) Several breaking changes to the `dash.Dash` API:
Expand Down
38 changes: 29 additions & 9 deletions dash/testing/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.action_chains import ActionChains
Expand All @@ -25,8 +24,17 @@


class Browser(DashPageMixin):
def __init__(self, browser, remote=None, wait_timeout=10):
def __init__(
self,
browser,
headless=False,
options=None,
remote=None,
wait_timeout=10,
):
self._browser = browser.lower()
self._headless = headless
self._options = options
self._wait_timeout = wait_timeout

self._driver = self.get_webdriver(remote)
Expand Down Expand Up @@ -244,10 +252,20 @@ def get_webdriver(self, remote):
)
)

@staticmethod
def _get_chrome():
options = Options()
options.add_argument("--no-sandbox")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we lost --no-sandbox, is it important?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I removed this part as the options are fully configurable after this PR

def _get_wd_options(self):
options = (
self._options[0]
if self._options and isinstance(self._options, list)
else getattr(webdriver, self._browser).options.Options()
)

if self._headless:
options.headless = True

return options

def _get_chrome(self):
options = self._get_wd_options()

capabilities = DesiredCapabilities.CHROME
capabilities["loggingPrefs"] = {"browser": "SEVERE"}
Expand All @@ -261,8 +279,8 @@ def _get_chrome():
chrome.set_window_position(0, 0)
return chrome

@staticmethod
def _get_firefox():
def _get_firefox(self):
options = self._get_wd_options()

capabilities = DesiredCapabilities.FIREFOX
capabilities["loggingPrefs"] = {"browser": "SEVERE"}
Expand All @@ -278,7 +296,9 @@ def _get_firefox():
fp.set_preference("browser.download.folderList", 2)
fp.set_preference("browser.download.manager.showWhenStarting", False)

return webdriver.Firefox(fp, capabilities=capabilities)
return webdriver.Firefox(
fp, options=options, capabilities=capabilities
)

@staticmethod
def _is_windows():
Expand Down
7 changes: 3 additions & 4 deletions dash/testing/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@


class DashComposite(Browser):

def __init__(self, server, browser, remote=None, wait_timeout=10):
super(DashComposite, self).__init__(browser, remote, wait_timeout)
def __init__(self, server, **kwargs):
super(DashComposite, self).__init__(**kwargs)
self.server = server

def start_server(self, app, **kwargs):
'''start the local server with app'''
"""start the local server with app"""

# start server with app and pass Dash arguments
self.server(app, **kwargs)
Expand Down
2 changes: 2 additions & 0 deletions dash/testing/newhooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def pytest_setup_options():
"""called before webdriver is initialized"""
30 changes: 28 additions & 2 deletions dash/testing/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ def pytest_addoption(parser):
help="Name of the selenium driver to use",
)

dash.addoption(
"--headless",
action="store",
default=False,
help="Run tests in headless mode",
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we use "store_true" so you can simplify to pytest --headless, rather than pytest --headless True?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, I like the shorter version



@pytest.mark.tryfirst
def pytest_addhooks(pluginmanager):
# https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/plugin.py#L67
# avoid warnings with pytest-2.8
from dash.testing import newhooks

method = getattr(pluginmanager, "add_hookspecs", None)
if method is None:
method = pluginmanager.addhooks # pragma: no cover
method(newhooks)


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call): # pylint: disable=unused-argument
Expand Down Expand Up @@ -63,13 +82,20 @@ def dash_process_server():

@pytest.fixture
def dash_br(request):
with Browser(request.config.getoption("webdriver")) as browser:
with Browser(
browser=request.config.getoption("webdriver"),
headless=request.config.getoption("headless"),
options=request.config.hook.pytest_setup_options(),
) as browser:
yield browser


@pytest.fixture
def dash_duo(request, dash_thread_server):
with DashComposite(
dash_thread_server, request.config.getoption("webdriver")
dash_thread_server,
browser=request.config.getoption("webdriver"),
headless=request.config.getoption("headless"),
options=request.config.hook.pytest_setup_options(),
) as dc:
yield dc
2 changes: 1 addition & 1 deletion requires-install.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ plotly
dash_renderer==1.0.0
dash-core-components==1.0.0
dash-html-components==1.0.0
dash-table==4.0.0
dash-table==4.0.0