Skip to content

Commit 9f1271b

Browse files
authored
Merge pull request #918 from plotly/dash-testing-docs
add APIs for dash docs testings
2 parents eb845b5 + ecd2b19 commit 9f1271b

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

Diff for: dash/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## Unreleased
22

3+
### Added
4+
5+
- [#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
6+
the default waitress one) and optional `start_timeout` argument to handle large application within process runner
7+
38
### Fixed
49

510
- [#915](https://github.com/plotly/dash/issues/915) Fixes `dash-generate-components` on Windows

Diff for: dash/testing/application_runners.py

+23-7
Original file line numberDiff line numberDiff line change
@@ -179,23 +179,39 @@ def __init__(self, keep_open=False, stop_timeout=3):
179179
self.proc = None
180180

181181
# pylint: disable=arguments-differ
182-
def start(self, app_module, application_name="app", port=8050):
182+
def start(
183+
self,
184+
app_module=None,
185+
application_name="app",
186+
raw_command=None,
187+
port=8050,
188+
start_timeout=3,
189+
):
183190
"""Start the server with waitress-serve in process flavor """
184-
entrypoint = "{}:{}.server".format(app_module, application_name)
191+
if not (app_module or raw_command): # need to set a least one
192+
logging.error(
193+
"the process runner needs to start with"
194+
" at least one valid command"
195+
)
196+
return
185197
self.port = port
186-
187198
args = shlex.split(
188-
"waitress-serve --listen=0.0.0.0:{} {}".format(port, entrypoint),
199+
raw_command
200+
if raw_command
201+
else "waitress-serve --listen=0.0.0.0:{} {}:{}.server".format(
202+
port, app_module, application_name
203+
),
189204
posix=not self.is_windows,
190205
)
206+
191207
logger.debug("start dash process with %s", args)
192208

193209
try:
194210
self.proc = subprocess.Popen(
195211
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
196212
)
197213
# wait until server is able to answer http request
198-
wait.until(lambda: self.accessible(self.url), timeout=3)
214+
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)
199215

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

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

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

272288
except (OSError, ValueError):
273289
logger.exception("process server has encountered an error")

Diff for: dash/testing/browser.py

+24
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ def wait_for_element_by_css_selector(self, selector, timeout=None):
173173
),
174174
)
175175

176+
def wait_for_element_by_id(self, element_id, timeout=None):
177+
"""explicit wait until the element is present,
178+
timeout if not set, equals to the fixture's `wait_timeout`
179+
shortcut to `WebDriverWait` with `EC.presence_of_element_located`
180+
"""
181+
return self._wait_for(
182+
EC.presence_of_element_located,
183+
((By.ID, element_id),),
184+
timeout,
185+
"timeout {}s => waiting for element id {}".format(
186+
timeout if timeout else self._wait_timeout, element_id
187+
),
188+
)
189+
176190
def wait_for_style_to_equal(self, selector, style, val, timeout=None):
177191
"""explicit wait until the element's style has expected `value`
178192
timeout if not set, equals to the fixture's `wait_timeout`
@@ -433,6 +447,16 @@ def reset_log_timestamp(self):
433447
if entries:
434448
self._last_ts = entries[-1]["timestamp"]
435449

450+
def visit_and_snapshot(self, resource_path, hook_id):
451+
try:
452+
self.driver.get(self.server_url + resource_path)
453+
self.wait_for_element_by_id(hook_id)
454+
self.percy_snapshot(resource_path)
455+
self.driver.back()
456+
except WebDriverException as e:
457+
logger.exception("snapshot at resource %s error", resource_path)
458+
raise e
459+
436460
@property
437461
def driver(self):
438462
"""expose the selenium webdriver as fixture property"""

Diff for: tests/unit/test_app_runners.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test_threaded_server_smoke(dash_thread_server):
2525
sys.version_info < (3,), reason="requires python3 for process testing"
2626
)
2727
def test_process_server_smoke(dash_process_server):
28-
dash_process_server("simple_app")
28+
dash_process_server('simple_app')
2929
r = requests.get(dash_process_server.url)
3030
assert r.status_code == 200, "the server is reachable"
3131
assert 'id="react-entry-point"' in r.text, "the entrypoint is present"

0 commit comments

Comments
 (0)