From 9ecf0f4cdc786e1991651f6cc35ca507f612ffdd Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 12:44:29 -0400 Subject: [PATCH 1/9] generalize testing Browser methods to accept elements or selectors --- dash/testing/browser.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/dash/testing/browser.py b/dash/testing/browser.py index ad4f35d92a..1e923023f9 100644 --- a/dash/testing/browser.py +++ b/dash/testing/browser.py @@ -145,6 +145,11 @@ def find_elements(self, selector): """ return self.driver.find_elements_by_css_selector(selector) + def _get_element(self, elem_or_selector): + if isinstance(elem_or_selector, str): + return self.find_element(elem_or_selector) + return elem_or_selector + def _wait_for(self, method, args, timeout, msg): """abstract generic pattern for explicit WebDriverWait""" _wait = ( @@ -262,8 +267,8 @@ def wait_for_page(self, url=None, timeout=10): ) ) - def select_dcc_dropdown(self, selector, value=None, index=None): - dropdown = self.driver.find_element_by_css_selector(selector) + def select_dcc_dropdown(self, elem_or_selector, value=None, index=None): + dropdown = self._get_element(elem_or_selector) dropdown.click() menu = dropdown.find_element_by_css_selector("div.Select-menu-outer") @@ -416,13 +421,15 @@ def _get_firefox(self): def _is_windows(): return sys.platform == "win32" - def multiple_click(self, selector, clicks): + def multiple_click(self, elem_or_selector, clicks): """multiple_click click the element with number of `clicks`""" for _ in range(clicks): - self.find_element(selector).click() + self._get_element(elem_or_selector).click() - def clear_input(self, elem): + def clear_input(self, elem_or_selector): """simulate key press to clear the input""" + elem = self._get_element(elem_or_selector) + ( ActionChains(self.driver) .click(elem) @@ -434,12 +441,18 @@ def clear_input(self, elem): ).perform() def zoom_in_graph_by_ratio( - self, elem, start_fraction=0.5, zoom_box_fraction=0.2, compare=True + self, + elem_or_selector, + 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 """ + elem = self._get_element(elem_or_selector) + prev = elem.get_attribute("innerHTML") w, h = elem.size["width"], elem.size["height"] try: @@ -455,7 +468,9 @@ def zoom_in_graph_by_ratio( "innerHTML" ), "SVG content should be different after zoom" - def click_at_coord_fractions(self, elem, fx, fy): + def click_at_coord_fractions(self, elem_or_selector, fx, fy): + elem = self._get_element(elem_or_selector) + ActionChains(self.driver).move_to_element_with_offset( elem, elem.size["width"] * fx, elem.size["height"] * fy ).click().perform() From 9d7ba787f4466c4a168d91a22e039d2d26505d8a Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 12:45:27 -0400 Subject: [PATCH 2/9] fix for toggling persistence on/off --- dash-renderer/src/persistence.js | 53 +++++---- .../integration/renderer/test_persistence.py | 101 ++++++++++++++++++ 2 files changed, 135 insertions(+), 19 deletions(-) diff --git a/dash-renderer/src/persistence.js b/dash-renderer/src/persistence.js index 0e2761887a..11606388f8 100644 --- a/dash-renderer/src/persistence.js +++ b/dash-renderer/src/persistence.js @@ -280,30 +280,34 @@ const getValsKey = (id, persistedProp, persistence) => `${id}.${persistedProp}.${JSON.stringify(persistence)}`; const getProps = layout => { - const {props} = layout; - const {id, persistence} = props; - if (!id || !persistence) { - // This component doesn't have persistence. To make downstream - // tests more efficient don't return either one, so we just have to - // test for truthy persistence. - // But we still need to return props for consumers that look for - // nested components + const {props, type, namespace} = layout; + if (!type || !namespace) { + // not a real component - just need the props for recursion return {props}; } + const {id, persistence} = props; const element = Registry.resolve(layout); const persisted_props = props.persisted_props || element.defaultProps.persisted_props; const persistence_type = props.persistence_type || element.defaultProps.persistence_type; - if (!persisted_props || !persistence_type) { - return {props}; - } - return {id, props, element, persistence, persisted_props, persistence_type}; + const canPersist = id && persisted_props && persistence_type; + + return { + canPersist, + id, + props, + element, + persistence, + persisted_props, + persistence_type, + }; }; export function recordUiEdit(layout, newProps, dispatch) { const { + canPersist, id, props, element, @@ -311,7 +315,7 @@ export function recordUiEdit(layout, newProps, dispatch) { persisted_props, persistence_type, } = getProps(layout); - if (!persistence) { + if (!canPersist || !persistence) { return; } @@ -378,6 +382,7 @@ function modProp(key, storage, element, props, persistedProp, update, undo) { function persistenceMods(layout, component, path, dispatch) { const { + canPersist, id, props, element, @@ -387,7 +392,7 @@ function persistenceMods(layout, component, path, dispatch) { } = getProps(component); let layoutOut = layout; - if (persistence) { + if (canPersist && persistence) { const storage = getStore(persistence_type, dispatch); const update = {}; forEach( @@ -443,6 +448,7 @@ function persistenceMods(layout, component, path, dispatch) { */ export function prunePersistence(layout, newProps, dispatch) { const { + canPersist, id, props, persistence, @@ -455,7 +461,7 @@ export function prunePersistence(layout, newProps, dispatch) { propName in newProps ? newProps[propName] : prevVal; const finalPersistence = getFinal('persistence', persistence); - if (!persistence && !finalPersistence) { + if (!canPersist || !(persistence || finalPersistence)) { return newProps; } @@ -471,6 +477,8 @@ export function prunePersistence(layout, newProps, dispatch) { const update = {}; + let depersistedProps = props; + if (persistenceChanged && persistence) { // clear previously-applied persistence const storage = getStore(persistence_type, dispatch); @@ -487,6 +495,7 @@ export function prunePersistence(layout, newProps, dispatch) { ), filter(notInNewProps, persisted_props) ); + depersistedProps = mergeRight(props, update); } if (finalPersistence) { @@ -497,10 +506,10 @@ export function prunePersistence(layout, newProps, dispatch) { forEach( persistedProp => modProp( - getValsKey(id, persistedProp, persistence), + getValsKey(id, persistedProp, finalPersistence), finalStorage, element, - props, + depersistedProps, persistedProp, update ), @@ -516,11 +525,17 @@ export function prunePersistence(layout, newProps, dispatch) { if (propTransforms) { for (const propPart in propTransforms) { finalStorage.removeItem( - getValsKey(id, `${propName}.${propPart}`, persistence) + getValsKey( + id, + `${propName}.${propPart}`, + finalPersistence + ) ); } } else { - finalStorage.removeItem(getValsKey(id, propName, persistence)); + finalStorage.removeItem( + getValsKey(id, propName, finalPersistence) + ); } } } diff --git a/tests/integration/renderer/test_persistence.py b/tests/integration/renderer/test_persistence.py index 034f920fb5..35a3bc1214 100644 --- a/tests/integration/renderer/test_persistence.py +++ b/tests/integration/renderer/test_persistence.py @@ -3,6 +3,7 @@ import dash from dash.dependencies import Input, Output +import dash_core_components as dcc import dash_html_components as html import dash_table as dt @@ -51,6 +52,7 @@ def report_props(columns, hidden_columns): return app + NEW_NAME = 'mango' @@ -354,3 +356,102 @@ def reset_names(n): dash_duo.find_element('#reset-names').click() # names are reset, but not hidden_columns check_table_names(dash_duo, ['a']) + + +def test_rdps010_toggle_persistence(dash_duo): + def make_input(persistence): + return dcc.Input(id='persisted', value='a', persistence=persistence) + + app = dash.Dash(__name__) + app.layout = html.Div([ + dcc.Input(id='persistence-val', value=''), + html.Div(make_input(''), id='persisted-container'), + html.Div(id='out') + ]) + + @app.callback( + Output('persisted-container', 'children'), + [Input('persistence-val', 'value')] + ) + def set_persistence(val): + return make_input(val) + + @app.callback(Output('out', 'children'), [Input('persisted', 'value')]) + def set_out(val): + return val + + dash_duo.start_server(app) + + dash_duo.wait_for_text_to_equal('#out', 'a') + dash_duo.find_element('#persisted').send_keys('lpaca') + dash_duo.wait_for_text_to_equal('#out', 'alpaca') + + dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.wait_for_text_to_equal('#out', 'a') + dash_duo.find_element('#persisted').send_keys('nchovies') + dash_duo.wait_for_text_to_equal('#out', 'anchovies') + + dash_duo.find_element('#persistence-val').send_keys('2') + dash_duo.wait_for_text_to_equal('#out', 'a') + dash_duo.find_element('#persisted').send_keys('ardvark') + dash_duo.wait_for_text_to_equal('#out', 'aardvark') + + # alpaca not saved with falsy persistence + dash_duo.clear_input('#persistence-val') + dash_duo.wait_for_text_to_equal('#out', 'a') + + # anchovies and aardvark saved + dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.wait_for_text_to_equal('#out', 'anchovies') + dash_duo.find_element('#persistence-val').send_keys('2') + dash_duo.wait_for_text_to_equal('#out', 'aardvark') + + +def test_rdps011_toggle_persistence2(dash_duo): + def make_input(persistence): + return dcc.Input(id='persisted', value='a', persistence=persistence) + + app = dash.Dash(__name__) + app.layout = html.Div([ + dcc.Input(id='persistence-val', value=''), + dcc.Input(id='persisted', value='a', persistence=''), + html.Div(id='out') + ]) + + # this is not a good way to set persistence, as it doesn't allow you to + # get the right initial value. Much better is to update the whole component + # as we do in the previous test case... but it shouldn't break this way. + @app.callback( + Output('persisted', 'persistence'), + [Input('persistence-val', 'value')] + ) + def set_persistence(val): + return val + + @app.callback(Output('out', 'children'), [Input('persisted', 'value')]) + def set_out(val): + return val + + dash_duo.start_server(app) + + dash_duo.wait_for_text_to_equal('#out', 'a') + + dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.wait_for_text_to_equal('#out', 'a') + dash_duo.find_element('#persisted').send_keys('pricot') + dash_duo.wait_for_text_to_equal('#out', 'apricot') + + dash_duo.find_element('#persistence-val').send_keys('2') + dash_duo.wait_for_text_to_equal('#out', 'a') + dash_duo.find_element('#persisted').send_keys('rtichoke') + dash_duo.wait_for_text_to_equal('#out', 'artichoke') + + # no persistence, still goes back to original value + dash_duo.clear_input('#persistence-val') + dash_duo.wait_for_text_to_equal('#out', 'a') + + # apricot and artichoke saved + dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.wait_for_text_to_equal('#out', 'apricot') + dash_duo.find_element('#persistence-val').send_keys('2') + dash_duo.wait_for_text_to_equal('#out', 'artichoke') From 8c01c83e3ffb516b464de6482bf3c09913b4f650 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 15:58:50 -0400 Subject: [PATCH 3/9] fix for components with no (default) props --- dash-renderer/src/persistence.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dash-renderer/src/persistence.js b/dash-renderer/src/persistence.js index 11606388f8..e1c45787cc 100644 --- a/dash-renderer/src/persistence.js +++ b/dash-renderer/src/persistence.js @@ -288,10 +288,9 @@ const getProps = layout => { const {id, persistence} = props; const element = Registry.resolve(layout); - const persisted_props = - props.persisted_props || element.defaultProps.persisted_props; - const persistence_type = - props.persistence_type || element.defaultProps.persistence_type; + const getVal = prop => props[prop] || (element.defaultProps || {})[prop]; + const persisted_props = getVal('persisted_props'); + const persistence_type = getVal('persistence_type'); const canPersist = id && persisted_props && persistence_type; return { From 18544506fd08100371569588f5b146e3cbd18019 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 16:08:08 -0400 Subject: [PATCH 4/9] changelog for persistence fix & testing selector/element flexibility --- dash-renderer/CHANGELOG.md | 4 ++++ dash/CHANGELOG.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dash-renderer/CHANGELOG.md b/dash-renderer/CHANGELOG.md index 9a0fd4279d..e5460f66ee 100644 --- a/dash-renderer/CHANGELOG.md +++ b/dash-renderer/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +# Unreleased +### Fixed +- [#944](https://github.com/plotly/dash/pull/944) fixed bug with persistence being toggled on/off on an existing component + ## [1.1.0] - 2019-09-17 ### Added - [#903](https://github.com/plotly/dash/pull/903) enables props edited by the user to persist across recreating the component or reloading the page. Components need to define three new props: `persistence`, `persisted_props`, and `persistence_type` as described in the lead comment of `src/persistence.js`. App developers then enable this behavior by, in the simplest case, setting `persistence: true` on the component. First use case is table, see [dash-table#566](https://github.com/plotly/dash-table/pull/566) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 2acaee5cca..7b1ea446cd 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased ### Added - +- [#944](https://github.com/plotly/dash/pull/944) relevant `dash.testing` methods can now be called with either an element or a CSS selector: `select_dcc_dropdown`, `multiple_click`, `clear_input`, `zoom_in_graph_by_ratio`, `click_at_coord_fractions` - [#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` - [#938](https://github.com/plotly/dash/issues/938) Adds debugging traces to dash backend about serving component suites, so we can use it to verify the installed packages whenever in doubt. From 457841c08570b43cecb6078372adfe7a5d30a681 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 16:57:25 -0400 Subject: [PATCH 5/9] test methods to clear storage, and use to try and robustify persistence tests --- dash/CHANGELOG.md | 4 +++- dash/testing/dash_page.py | 10 ++++++++++ tests/integration/renderer/test_persistence.py | 18 +++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dash/CHANGELOG.md b/dash/CHANGELOG.md index 7b1ea446cd..4b77a4a7d0 100644 --- a/dash/CHANGELOG.md +++ b/dash/CHANGELOG.md @@ -1,7 +1,9 @@ ## Unreleased ### Added -- [#944](https://github.com/plotly/dash/pull/944) relevant `dash.testing` methods can now be called with either an element or a CSS selector: `select_dcc_dropdown`, `multiple_click`, `clear_input`, `zoom_in_graph_by_ratio`, `click_at_coord_fractions` +- [#944](https://github.com/plotly/dash/pull/944) + - relevant `dash.testing` methods can now be called with either an element or a CSS selector: `select_dcc_dropdown`, `multiple_click`, `clear_input`, `zoom_in_graph_by_ratio`, `click_at_coord_fractions`. + - Three new `dash.testing` methods: `clear_local_storage`, `clear_session_storage`, and `clear_storage` (to clear both together) - [#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` - [#938](https://github.com/plotly/dash/issues/938) Adds debugging traces to dash backend about serving component suites, so we can use it to verify the installed packages whenever in doubt. diff --git a/dash/testing/dash_page.py b/dash/testing/dash_page.py index 069779d8eb..62b3b95e8b 100644 --- a/dash/testing/dash_page.py +++ b/dash/testing/dash_page.py @@ -49,3 +49,13 @@ def get_session_storage(self, session_id="session"): session_id ) ) + + def clear_local_storage(self): + self.driver.execute_script("window.localStorage.clear()") + + def clear_session_storage(self): + self.driver.execute_script("window.sessionStorage.clear()") + + def clear_storage(self): + self.clear_local_storage() + self.clear_session_storage() diff --git a/tests/integration/renderer/test_persistence.py b/tests/integration/renderer/test_persistence.py index 35a3bc1214..36b3b365a4 100644 --- a/tests/integration/renderer/test_persistence.py +++ b/tests/integration/renderer/test_persistence.py @@ -1,4 +1,5 @@ from multiprocessing import Value +import pytest import dash from dash.dependencies import Input, Output @@ -8,6 +9,12 @@ import dash_table as dt +@pytest.fixture(autouse=True) +def clear_storage(dash_duo): + yield + dash_duo.clear_storage() + + def table_columns(names, **extra_props): return [dict( id='c{}'.format(i), @@ -386,7 +393,7 @@ def set_out(val): dash_duo.find_element('#persisted').send_keys('lpaca') dash_duo.wait_for_text_to_equal('#out', 'alpaca') - dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persisted').send_keys('nchovies') dash_duo.wait_for_text_to_equal('#out', 'anchovies') @@ -401,16 +408,13 @@ def set_out(val): dash_duo.wait_for_text_to_equal('#out', 'a') # anchovies and aardvark saved - dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'anchovies') dash_duo.find_element('#persistence-val').send_keys('2') dash_duo.wait_for_text_to_equal('#out', 'aardvark') def test_rdps011_toggle_persistence2(dash_duo): - def make_input(persistence): - return dcc.Input(id='persisted', value='a', persistence=persistence) - app = dash.Dash(__name__) app.layout = html.Div([ dcc.Input(id='persistence-val', value=''), @@ -436,7 +440,7 @@ def set_out(val): dash_duo.wait_for_text_to_equal('#out', 'a') - dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persisted').send_keys('pricot') dash_duo.wait_for_text_to_equal('#out', 'apricot') @@ -451,7 +455,7 @@ def set_out(val): dash_duo.wait_for_text_to_equal('#out', 'a') # apricot and artichoke saved - dash_duo.find_element('#persistence-val').send_keys('save!') + dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') dash_duo.wait_for_text_to_equal('#out', 'artichoke') From 445e3b1d46aa11d8d97b73e1ca1598424304f44b Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Fri, 27 Sep 2019 17:25:32 -0400 Subject: [PATCH 6/9] try to robustify new persistence test --- tests/integration/renderer/test_persistence.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/integration/renderer/test_persistence.py b/tests/integration/renderer/test_persistence.py index 36b3b365a4..5d89675d59 100644 --- a/tests/integration/renderer/test_persistence.py +++ b/tests/integration/renderer/test_persistence.py @@ -1,5 +1,6 @@ from multiprocessing import Value import pytest +import time import dash from dash.dependencies import Input, Output @@ -418,7 +419,7 @@ def test_rdps011_toggle_persistence2(dash_duo): app = dash.Dash(__name__) app.layout = html.Div([ dcc.Input(id='persistence-val', value=''), - dcc.Input(id='persisted', value='a', persistence=''), + dcc.Input(id='persisted2', value='a', persistence=''), html.Div(id='out') ]) @@ -426,13 +427,13 @@ def test_rdps011_toggle_persistence2(dash_duo): # get the right initial value. Much better is to update the whole component # as we do in the previous test case... but it shouldn't break this way. @app.callback( - Output('persisted', 'persistence'), + Output('persisted2', 'persistence'), [Input('persistence-val', 'value')] ) def set_persistence(val): return val - @app.callback(Output('out', 'children'), [Input('persisted', 'value')]) + @app.callback(Output('out', 'children'), [Input('persisted2', 'value')]) def set_out(val): return val @@ -442,20 +443,24 @@ def set_out(val): dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'a') - dash_duo.find_element('#persisted').send_keys('pricot') + time.sleep(0.2) + dash_duo.find_element('#persisted2').send_keys('pricot') dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') dash_duo.wait_for_text_to_equal('#out', 'a') - dash_duo.find_element('#persisted').send_keys('rtichoke') + time.sleep(0.2) + dash_duo.find_element('#persisted2').send_keys('rtichoke') dash_duo.wait_for_text_to_equal('#out', 'artichoke') # no persistence, still goes back to original value dash_duo.clear_input('#persistence-val') dash_duo.wait_for_text_to_equal('#out', 'a') + time.sleep(0.2) # apricot and artichoke saved dash_duo.find_element('#persistence-val').send_keys('s') dash_duo.wait_for_text_to_equal('#out', 'apricot') + time.sleep(0.2) dash_duo.find_element('#persistence-val').send_keys('2') dash_duo.wait_for_text_to_equal('#out', 'artichoke') From acd9a75c3008685eafb0eaa7d5ea362da3f19e28 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Mon, 30 Sep 2019 10:35:14 -0400 Subject: [PATCH 7/9] extra log checks --- tests/integration/renderer/test_persistence.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/integration/renderer/test_persistence.py b/tests/integration/renderer/test_persistence.py index 5d89675d59..305d824daa 100644 --- a/tests/integration/renderer/test_persistence.py +++ b/tests/integration/renderer/test_persistence.py @@ -442,25 +442,31 @@ def set_out(val): dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persistence-val').send_keys('s') - dash_duo.wait_for_text_to_equal('#out', 'a') time.sleep(0.2) + assert not dash_duo.get_logs() + dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persisted2').send_keys('pricot') dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') - dash_duo.wait_for_text_to_equal('#out', 'a') time.sleep(0.2) + assert not dash_duo.get_logs() + dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persisted2').send_keys('rtichoke') dash_duo.wait_for_text_to_equal('#out', 'artichoke') # no persistence, still goes back to original value dash_duo.clear_input('#persistence-val') - dash_duo.wait_for_text_to_equal('#out', 'a') time.sleep(0.2) + assert not dash_duo.get_logs() + dash_duo.wait_for_text_to_equal('#out', 'a') # apricot and artichoke saved dash_duo.find_element('#persistence-val').send_keys('s') - dash_duo.wait_for_text_to_equal('#out', 'apricot') time.sleep(0.2) + assert not dash_duo.get_logs() + dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') + time.sleep(0.2) + assert not dash_duo.get_logs() dash_duo.wait_for_text_to_equal('#out', 'artichoke') From 0bd23bb1163f85b0108c1a6ceb06565b4fc47ce8 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Mon, 30 Sep 2019 11:39:27 -0400 Subject: [PATCH 8/9] no reinstalling dash-renderer also don't bother with sdist for dash, it has no artifacts --- .circleci/config.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4b8b7fc9c3..4ad2f05613 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,7 +108,6 @@ jobs: name: ️️🏗️ build core command: | . venv/bin/activate && pip install --no-cache-dir --upgrade -e . --progress-bar off && mkdir packages - python setup.py sdist && mv dist/* packages/ cd dash-renderer && renderer build && python setup.py sdist && mv dist/* ../packages/ && cd .. git clone --depth 1 https://github.com/plotly/dash-core-components.git cd dash-core-components && npm install --ignore-scripts && npm run build && python setup.py sdist && mv dist/* ../packages/ && cd .. @@ -200,10 +199,17 @@ jobs: - attach_workspace: at: ~/dash - run: - name: 🧪 Run Integration Tests + name: ️️🏗️ Install packages command: | . venv/bin/activate && cd packages && ls -la - find . -name "*.gz" | xargs pip install --no-cache-dir --ignore-installed && pip list | grep dash && cd .. + find . -name "*.gz" | xargs pip install --no-cache-dir --ignore-installed && cd .. + sed -i '/dash/d' requires-install.txt + pip install --no-cache-dir --ignore-installed . + pip list | grep dash + - run: + name: 🧪 Run Integration Tests + command: | + . venv/bin/activate TESTFILES=$(circleci tests glob "tests/integration/**/test_*.py" | circleci tests split --split-by=timings) pytest --headless --nopercyfinalize --junitxml=test-reports/junit_intg.xml ${TESTFILES} - store_artifacts: From f96c3ece429f3f92762f533cb70cd887306772ac Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Mon, 30 Sep 2019 11:52:06 -0400 Subject: [PATCH 9/9] pull back out persistence test debug code --- tests/integration/renderer/test_persistence.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/integration/renderer/test_persistence.py b/tests/integration/renderer/test_persistence.py index 305d824daa..70c62d49cc 100644 --- a/tests/integration/renderer/test_persistence.py +++ b/tests/integration/renderer/test_persistence.py @@ -449,24 +449,17 @@ def set_out(val): dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') - time.sleep(0.2) - assert not dash_duo.get_logs() dash_duo.wait_for_text_to_equal('#out', 'a') dash_duo.find_element('#persisted2').send_keys('rtichoke') dash_duo.wait_for_text_to_equal('#out', 'artichoke') # no persistence, still goes back to original value dash_duo.clear_input('#persistence-val') - time.sleep(0.2) - assert not dash_duo.get_logs() dash_duo.wait_for_text_to_equal('#out', 'a') # apricot and artichoke saved dash_duo.find_element('#persistence-val').send_keys('s') - time.sleep(0.2) - assert not dash_duo.get_logs() dash_duo.wait_for_text_to_equal('#out', 'apricot') dash_duo.find_element('#persistence-val').send_keys('2') - time.sleep(0.2) assert not dash_duo.get_logs() dash_duo.wait_for_text_to_equal('#out', 'artichoke')