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

add APIs for dash docs testings #918

Merged
merged 5 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions dash/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Unreleased

### Added

- [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs in browser, adds `raw_command` option (it aslo has higher priority than
byronz marked this conversation as resolved.
Show resolved Hide resolved
the default waitress one) and optional `start_timeout` argument to handle large application within process runner

### Fixed

- [#915](https://github.com/plotly/dash/issues/915) Fixes `dash-generate-components` on Windows
Expand Down
30 changes: 23 additions & 7 deletions dash/testing/application_runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,23 +179,39 @@ def __init__(self, keep_open=False, stop_timeout=3):
self.proc = None

# pylint: disable=arguments-differ
def start(self, app_module, application_name="app", port=8050):
def start(
byronz marked this conversation as resolved.
Show resolved Hide resolved
self,
app_module=None,
application_name="app",
raw_command=None,
port=8050,
start_timeout=3,
):
"""Start the server with waitress-serve in process flavor """
entrypoint = "{}:{}.server".format(app_module, application_name)
if not (app_module or raw_command): # need to set a least one
logging.error(
"the process runner needs to start with"
" at least one valid command"
)
return
self.port = port

args = shlex.split(
"waitress-serve --listen=0.0.0.0:{} {}".format(port, entrypoint),
raw_command
if raw_command
else "waitress-serve --listen=0.0.0.0:{} {}:{}.server".format(
port, app_module, application_name
),
posix=not self.is_windows,
)

logger.debug("start dash process with %s", args)

try:
self.proc = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
# wait until server is able to answer http request
wait.until(lambda: self.accessible(self.url), timeout=3)
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)

except (OSError, ValueError):
logger.exception("process server has encountered an error")
Expand Down Expand Up @@ -233,7 +249,7 @@ def __init__(self, keep_open=False, stop_timeout=3):
self.proc = None

# pylint: disable=arguments-differ
def start(self, app):
def start(self, app, start_timeout=2):
"""Start the server with waitress-serve in process flavor """

# app is a R string chunk
Expand Down Expand Up @@ -267,7 +283,7 @@ def start(self, app):
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
# wait until server is able to answer http request
wait.until(lambda: self.accessible(self.url), timeout=2)
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)

except (OSError, ValueError):
logger.exception("process server has encountered an error")
Expand Down
24 changes: 24 additions & 0 deletions dash/testing/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,20 @@ def wait_for_element_by_css_selector(self, selector, timeout=None):
),
)

def wait_for_element_by_id(self, element_id, timeout=None):
byronz marked this conversation as resolved.
Show resolved Hide resolved
"""explicit wait until the element is present,
timeout if not set, equals to the fixture's `wait_timeout`
shortcut to `WebDriverWait` with `EC.presence_of_element_located`
"""
return self._wait_for(
EC.presence_of_element_located,
((By.ID, element_id),),
timeout,
"timeout {}s => waiting for element id {}".format(
timeout if timeout else self._wait_timeout, element_id
),
)

def wait_for_style_to_equal(self, selector, style, val, timeout=None):
"""explicit wait until the element's style has expected `value`
timeout if not set, equals to the fixture's `wait_timeout`
Expand Down Expand Up @@ -433,6 +447,16 @@ def reset_log_timestamp(self):
if entries:
self._last_ts = entries[-1]["timestamp"]

def visit_and_snapshot(self, resource_path, hook_id):
try:
self.driver.get(self.server_url + resource_path)
self.wait_for_element_by_id(hook_id)
self.percy_snapshot(resource_path)
self.driver.back()
except WebDriverException as e:
logger.exception("snapshot at resource %s error", resource_path)
raise e

@property
def driver(self):
"""expose the selenium webdriver as fixture property"""
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_app_runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_threaded_server_smoke(dash_thread_server):
sys.version_info < (3,), reason="requires python3 for process testing"
)
def test_process_server_smoke(dash_process_server):
dash_process_server("simple_app")
dash_process_server('simple_app')
r = requests.get(dash_process_server.url)
assert r.status_code == 200, "the server is reachable"
assert 'id="react-entry-point"' in r.text, "the entrypoint is present"