From 427054bede9a39aff0aa0f4f70a0b2cfb3696f22 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 20:40:09 -0400 Subject: [PATCH 01/11] make percy assets configurable --- dash/testing/browser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 51b7557903..355ff5bcf7 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -39,6 +39,7 @@ def __init__( options=None, download_path=None, percy_finalize=True, + percy_assets_root='tests/assets', wait_timeout=10, ): self._browser = browser.lower() @@ -67,7 +68,7 @@ def __init__( loader=percy.ResourceLoader( webdriver=self.driver, base_url="/assets", - root_dir="tests/assets", + root_dir=percy_assets_root, ) ) self.percy_runner.initialize_build() From 3fc2894961b6b5e7ae87e1c9142abd06c9fbbc82 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 20:43:04 -0400 Subject: [PATCH 02/11] black and add log --- dash/testing/browser.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 355ff5bcf7..886e591300 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -39,7 +39,7 @@ def __init__( options=None, download_path=None, percy_finalize=True, - percy_assets_root='tests/assets', + percy_assets_root="tests/assets", wait_timeout=10, ): self._browser = browser.lower() @@ -76,6 +76,9 @@ def __init__( logger.debug("initialize browser with arguments") logger.debug(" headless => %s", self._headless) logger.debug(" download_path => %s", self._download_path) + logger.debug( + " percy asset root => %s", os.path.abspath(percy_assets_root) + ) def __enter__(self): return self From 77854a4fb57b91e895f1c72f0936e91ee62c900d Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 21:32:08 -0400 Subject: [PATCH 03/11] add stop in case exception --- dash/testing/application_runners.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dash/testing/application_runners.py b/dash/testing/application_runners.py index c9575d2e3c..131e1b5bbe 100644 --- a/dash/testing/application_runners.py +++ b/dash/testing/application_runners.py @@ -216,6 +216,7 @@ def start( except (OSError, ValueError): logger.exception("process server has encountered an error") self.started = False + self.stop() return self.started = True From 6c3b9714be71df023d526df29883b8d37c8db1a2 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 21:32:32 -0400 Subject: [PATCH 04/11] add configure for percy assets path --- dash/testing/browser.py | 10 +++++----- dash/testing/plugin.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 886e591300..213016ca43 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -39,7 +39,7 @@ def __init__( options=None, download_path=None, percy_finalize=True, - percy_assets_root="tests/assets", + percy_assets_root=None, wait_timeout=10, ): self._browser = browser.lower() @@ -73,10 +73,10 @@ def __init__( ) self.percy_runner.initialize_build() - logger.debug("initialize browser with arguments") - logger.debug(" headless => %s", self._headless) - logger.debug(" download_path => %s", self._download_path) - logger.debug( + logger.info("initialize browser with arguments") + logger.info(" headless => %s", self._headless) + logger.info(" download_path => %s", self._download_path) + logger.info( " percy asset root => %s", os.path.abspath(percy_assets_root) ) diff --git a/dash/testing/plugin.py b/dash/testing/plugin.py index 847928b7bc..1e154552d8 100644 --- a/dash/testing/plugin.py +++ b/dash/testing/plugin.py @@ -48,6 +48,13 @@ def pytest_addoption(parser): help="set this flag to run in headless mode", ) + dash.addoption( + "--percy-assets", + action="store", + default='tests/assets', + help="configure how Percy will discover your app's assets" + ) + dash.addoption( "--nopercyfinalize", action="store_false", @@ -117,6 +124,7 @@ def dash_br(request, tmpdir): headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, + percy_assets_root=request.config.getoption("percy_assets"), percy_finalize=request.config.getoption("nopercyfinalize"), ) as browser: yield browser @@ -132,6 +140,7 @@ def dash_duo(request, dash_thread_server, tmpdir): headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, + percy_assets_root=request.config.getoption("percy_assets"), percy_finalize=request.config.getoption("nopercyfinalize"), ) as dc: yield dc @@ -147,6 +156,7 @@ def dashr(request, dashr_server, tmpdir): headless=request.config.getoption("headless"), options=request.config.hook.pytest_setup_options(), download_path=tmpdir.mkdir("download").strpath, + percy_assets_root=request.config.getoption("percy_assets"), percy_finalize=request.config.getoption("nopercyfinalize"), ) as dc: yield dc From 73d1f07390dbfba87bc051cb6b48f41fb9d2da19 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 21:35:04 -0400 Subject: [PATCH 05/11] :pencil: changelog --- dash/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 401c34cfde..4524ade973 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -2,6 +2,8 @@ ### Added +- [#923](https://github.com/plotly/dash/pull/923) Adds one configuration `--percy-assets` in `pytest` to specify extra application assets path if needed + - [#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 From 3aa510c3b01c90e7edd9cfba6bfd62ba8caf1e93 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 21:38:37 -0400 Subject: [PATCH 06/11] :lipstick: fix unittest --- dash/testing/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 213016ca43..f82fda8ca1 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -37,9 +37,9 @@ def __init__( remote_url=None, headless=False, options=None, - download_path=None, + download_path='', percy_finalize=True, - percy_assets_root=None, + percy_assets_root='', wait_timeout=10, ): self._browser = browser.lower() From cff37abff22b4d0eb7bbd54c7a404dea54048d25 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 22:55:27 -0400 Subject: [PATCH 07/11] add devtool check in api, this will fail the test case, so we don't risk miss that from some weird percy auto merge --- dash/testing/browser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index f82fda8ca1..ed40508c7f 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -37,9 +37,9 @@ def __init__( remote_url=None, headless=False, options=None, - download_path='', + download_path="", percy_finalize=True, - percy_assets_root='', + percy_assets_root="", wait_timeout=10, ): self._browser = browser.lower() @@ -456,6 +456,9 @@ def visit_and_snapshot(self, resource_path, hook_id): self.driver.get(self.server_url + resource_path) self.wait_for_element_by_id(hook_id) self.percy_snapshot(resource_path) + assert not self.driver.find_elements_by_css_selector( + "div.dash-debug-alert" + ), "devtools should not raise an error alert" self.driver.back() except WebDriverException as e: logger.exception("snapshot at resource %s error", resource_path) From a52aeb3f646a3a6b1dbcdd89ed7a2432c7f3ec2a Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 23:28:41 -0400 Subject: [PATCH 08/11] add '/' for url --- dash/testing/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index ed40508c7f..e011e46503 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -453,7 +453,7 @@ def reset_log_timestamp(self): def visit_and_snapshot(self, resource_path, hook_id): try: - self.driver.get(self.server_url + resource_path) + self.driver.get("{}/{}".format(self.server_url, resource_path)) self.wait_for_element_by_id(hook_id) self.percy_snapshot(resource_path) assert not self.driver.find_elements_by_css_selector( From 43ede3d07cd197781481f99f69cbfd11fb8747c0 Mon Sep 17 00:00:00 2001 From: byron Date: Fri, 13 Sep 2019 23:59:55 -0400 Subject: [PATCH 09/11] add switch for assert check --- dash/testing/browser.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index e011e46503..2d66f2e0de 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -451,14 +451,15 @@ def reset_log_timestamp(self): if entries: self._last_ts = entries[-1]["timestamp"] - def visit_and_snapshot(self, resource_path, hook_id): + def visit_and_snapshot(self, resource_path, hook_id, assert_check=True): try: self.driver.get("{}/{}".format(self.server_url, resource_path)) self.wait_for_element_by_id(hook_id) self.percy_snapshot(resource_path) - assert not self.driver.find_elements_by_css_selector( - "div.dash-debug-alert" - ), "devtools should not raise an error alert" + if assert_check: + assert not self.driver.find_elements_by_css_selector( + "div.dash-debug-alert" + ), "devtools should not raise an error alert" self.driver.back() except WebDriverException as e: logger.exception("snapshot at resource %s error", resource_path) From 42d886188634a284e8beb265d183078d57762729 Mon Sep 17 00:00:00 2001 From: byron Date: Sat, 14 Sep 2019 17:08:25 -0400 Subject: [PATCH 10/11] :ok_hand: add lstrip --- dash/testing/browser.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 2d66f2e0de..9265597dd0 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -453,16 +453,19 @@ def reset_log_timestamp(self): def visit_and_snapshot(self, resource_path, hook_id, assert_check=True): try: - self.driver.get("{}/{}".format(self.server_url, resource_path)) + path = resource_path.lstrip('/') + if path != resource_path: + logger.warning("we stripped the left '/' in resource_path") + self.driver.get("{}/{}".format(self.server_url, path)) self.wait_for_element_by_id(hook_id) - self.percy_snapshot(resource_path) + self.percy_snapshot(path) if assert_check: assert not self.driver.find_elements_by_css_selector( "div.dash-debug-alert" ), "devtools should not raise an error alert" self.driver.back() except WebDriverException as e: - logger.exception("snapshot at resource %s error", resource_path) + logger.exception("snapshot at resource %s error", path) raise e @property From e0519f30f5e97839c21742796c6bf178a138db01 Mon Sep 17 00:00:00 2001 From: byron Date: Sat, 14 Sep 2019 17:50:41 -0400 Subject: [PATCH 11/11] rstrip for server_url --- dash/testing/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 9265597dd0..8ed194accf 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -456,7 +456,7 @@ def visit_and_snapshot(self, resource_path, hook_id, assert_check=True): path = resource_path.lstrip('/') if path != resource_path: logger.warning("we stripped the left '/' in resource_path") - self.driver.get("{}/{}".format(self.server_url, path)) + self.driver.get("{}/{}".format(self.server_url.rstrip('/'), path)) self.wait_for_element_by_id(hook_id) self.percy_snapshot(path) if assert_check: