diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index f74fb37877..cdf0fb3afa 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -1,3 +1,9 @@ +## Unreleased + +### Added + +- [#937](https://github.com/plotly/dash/pull/937) `dash.testing` adds two APIs `zoom_in_graph_by_ratio` and `click_at_coord_fractions` about advanced interactions using mouse `ActionChain` + ## [1.3.1] - 2019-09-19 ### Changed - Bumped dash-core-components version from 1.2.0 to [1.2.1](https://github.com/plotly/dash-core-components/blob/master/CHANGELOG.md#120---2019-09-19) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index 8ed194accf..ad4f35d92a 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -13,7 +13,11 @@ from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.action_chains import ActionChains -from selenium.common.exceptions import WebDriverException, TimeoutException +from selenium.common.exceptions import ( + WebDriverException, + TimeoutException, + MoveTargetOutOfBoundsException, +) from dash.testing.wait import ( text_to_equal, @@ -429,6 +433,33 @@ def clear_input(self, elem): .send_keys(Keys.DELETE) ).perform() + def zoom_in_graph_by_ratio( + self, elem, start_fraction=0.5, zoom_box_fraction=0.2, compare=True + ): + """zoom out a graph with a zoom box fraction of component dimension + default start at middle with a rectangle of 1/5 of the dimension + use `compare` to control if we check the svg get changed + """ + prev = elem.get_attribute("innerHTML") + w, h = elem.size["width"], elem.size["height"] + try: + ActionChains(self.driver).move_to_element_with_offset( + elem, w * start_fraction, h * start_fraction + ).drag_and_drop_by_offset( + elem, w * zoom_box_fraction, h * zoom_box_fraction + ).perform() + except MoveTargetOutOfBoundsException: + logger.exception("graph offset outside of the boundary") + if compare: + assert prev != elem.get_attribute( + "innerHTML" + ), "SVG content should be different after zoom" + + def click_at_coord_fractions(self, elem, fx, fy): + ActionChains(self.driver).move_to_element_with_offset( + elem, elem.size["width"] * fx, elem.size["height"] * fy + ).click().perform() + def get_logs(self): """return a list of `SEVERE` level logs after last reset time stamps (default to 0, resettable by `reset_log_timestamp`. Chrome only @@ -453,10 +484,10 @@ def reset_log_timestamp(self): def visit_and_snapshot(self, resource_path, hook_id, assert_check=True): try: - path = resource_path.lstrip('/') + path = resource_path.lstrip("/") if path != resource_path: logger.warning("we stripped the left '/' in resource_path") - self.driver.get("{}/{}".format(self.server_url.rstrip('/'), 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: