Skip to content

Commit

Permalink
Merge pull request #918 from plotly/dash-testing-docs
Browse files Browse the repository at this point in the history
add APIs for dash docs testings
  • Loading branch information
byronz authored Sep 10, 2019
2 parents eb845b5 + ecd2b19 commit 9f1271b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
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 also has higher priority than
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(
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):
"""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"

0 comments on commit 9f1271b

Please sign in to comment.