From 974fd8d511f2a8c860f562649beece54ac2d136a Mon Sep 17 00:00:00 2001 From: byron Date: Tue, 10 Sep 2019 10:07:34 -0400 Subject: [PATCH 1/5] add APIs for dash docs testings --- dash/testing/application_runners.py | 10 ++++++---- dash/testing/browser.py | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/dash/testing/application_runners.py b/dash/testing/application_runners.py index a0a248fdc7..272b6a69b7 100644 --- a/dash/testing/application_runners.py +++ b/dash/testing/application_runners.py @@ -179,7 +179,9 @@ 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, application_name="app", port=8050, start_timeout=3 + ): """Start the server with waitress-serve in process flavor """ entrypoint = "{}:{}.server".format(app_module, application_name) self.port = port @@ -195,7 +197,7 @@ def start(self, app_module, application_name="app", port=8050): 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") @@ -233,7 +235,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 @@ -267,7 +269,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") diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 0283845202..51b7557903 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -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` @@ -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""" From 095811000fcd4724c0cceb0913916e7f2726b7a1 Mon Sep 17 00:00:00 2001 From: byron Date: Tue, 10 Sep 2019 10:12:42 -0400 Subject: [PATCH 2/5] :pencil2: update changelog --- dash/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index d9fea4be7e..2f70db70fe 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased +### Added + +- [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs, adds optional `start_timeout` argument for process runner + ### Fixed - [#915](https://github.com/plotly/dash/issues/915) Fixes `dash-generate-components` on Windows From b298256164c5f812dfbcb6fc0a63742435d4b797 Mon Sep 17 00:00:00 2001 From: byron Date: Tue, 10 Sep 2019 16:58:48 -0400 Subject: [PATCH 3/5] :boom: needs more flexible for the arguments, hard to tune waitress with debug mode --- dash/CHANGELOG.md | 2 +- dash/testing/application_runners.py | 17 +++++++++++++---- tests/unit/test_app_runners.py | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 2f70db70fe..9bfceaf17e 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -2,7 +2,7 @@ ### Added -- [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs, adds optional `start_timeout` argument for process runner +- 💥 [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs, change the process command options and adds optional `start_timeout` argument for process runner ### Fixed diff --git a/dash/testing/application_runners.py b/dash/testing/application_runners.py index 272b6a69b7..53847bb12a 100644 --- a/dash/testing/application_runners.py +++ b/dash/testing/application_runners.py @@ -180,16 +180,25 @@ def __init__(self, keep_open=False, stop_timeout=3): # pylint: disable=arguments-differ def start( - self, app_module, application_name="app", port=8050, start_timeout=3 + self, waitress_module=None, 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 (waitress_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:{} {}".format( + port, waitress_module + ), posix=not self.is_windows, ) + logger.debug("start dash process with %s", args) try: diff --git a/tests/unit/test_app_runners.py b/tests/unit/test_app_runners.py index 22bca7407a..65110cc306 100644 --- a/tests/unit/test_app_runners.py +++ b/tests/unit/test_app_runners.py @@ -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(waitress_module="simple_app:app.server") 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" From 72dfad959f370d2cb129703d37b25195c4eb966b Mon Sep 17 00:00:00 2001 From: byron Date: Tue, 10 Sep 2019 17:20:20 -0400 Subject: [PATCH 4/5] make it compatible --- dash/CHANGELOG.md | 3 ++- dash/testing/application_runners.py | 13 +++++++++---- tests/unit/test_app_runners.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 9bfceaf17e..05eafef609 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -2,7 +2,8 @@ ### Added -- 💥 [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs, change the process command options and adds optional `start_timeout` argument for process runner +- [#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 +the default waitress one) and optional `start_timeout` argument to handle large application within process runner ### Fixed diff --git a/dash/testing/application_runners.py b/dash/testing/application_runners.py index 53847bb12a..c9575d2e3c 100644 --- a/dash/testing/application_runners.py +++ b/dash/testing/application_runners.py @@ -180,10 +180,15 @@ def __init__(self, keep_open=False, stop_timeout=3): # pylint: disable=arguments-differ def start( - self, waitress_module=None, raw_command=None, port=8050, start_timeout=3 + self, + app_module=None, + application_name="app", + raw_command=None, + port=8050, + start_timeout=3, ): """Start the server with waitress-serve in process flavor """ - if not (waitress_module or raw_command): # need to set a least one + 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" @@ -193,8 +198,8 @@ def start( args = shlex.split( raw_command if raw_command - else "waitress-serve --listen=0.0.0.0:{} {}".format( - port, waitress_module + else "waitress-serve --listen=0.0.0.0:{} {}:{}.server".format( + port, app_module, application_name ), posix=not self.is_windows, ) diff --git a/tests/unit/test_app_runners.py b/tests/unit/test_app_runners.py index 65110cc306..784a8ff358 100644 --- a/tests/unit/test_app_runners.py +++ b/tests/unit/test_app_runners.py @@ -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(waitress_module="simple_app:app.server") + 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" From ecd2b195b254131bddcad0bc8da6c68e5b5878b5 Mon Sep 17 00:00:00 2001 From: Byron Zhu Date: Tue, 10 Sep 2019 17:49:03 -0400 Subject: [PATCH 5/5] Update dash/CHANGELOG.md Co-Authored-By: alexcjohnson --- dash/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 05eafef609..401c34cfde 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -2,7 +2,7 @@ ### 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 +- [#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