From 7d06ed2c6d53c0150537f77581ab1ece67c6ccb7 Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 15:20:24 +0200 Subject: [PATCH 1/8] Add search_value property to Dropdown --- src/components/Dropdown.react.js | 6 ++++++ tests/unit/Dropdown.test.js | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/components/Dropdown.react.js b/src/components/Dropdown.react.js index 82b8a1f3d..271941aad 100644 --- a/src/components/Dropdown.react.js +++ b/src/components/Dropdown.react.js @@ -100,6 +100,7 @@ export default class Dropdown extends Component { setProps({value}); } }} + onInputChange={search_value => setProps({search_value})} {...omit(['setProps', 'value'], this.props)} /> @@ -195,6 +196,11 @@ Dropdown.propTypes = { */ searchable: PropTypes.bool, + /** + * The value typed in the DropDown for searching. + */ + search_value: PropTypes.string, + /** * Dash-assigned callback that gets fired when the input changes */ diff --git a/tests/unit/Dropdown.test.js b/tests/unit/Dropdown.test.js index 2cd3176e2..1d6e96ed2 100644 --- a/tests/unit/Dropdown.test.js +++ b/tests/unit/Dropdown.test.js @@ -25,6 +25,7 @@ describe('Props can be set properly', () => { multi: false, placeholder: 'pick something', searchable: true, + search_value: "hello", style: {backgroundColor: 'hotpink'}, loading_state: { is_loading: false, @@ -52,6 +53,9 @@ describe('Props can be set properly', () => { expect(multiDD.props()).toEqual(multiProps); }); + test('search_value is being updated', () => { + }) + test('props.id is set as the outer element id', () => { // test if id is in the actual HTML string const ddTag = singleDD.render(); From 929f33727e316e78c3baff256ad4c4e785b27256 Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 16:01:54 +0200 Subject: [PATCH 2/8] Add intergity test to check that the search_value is updated --- .../integration/dropdown/test_search_value.py | 36 +++++++++++++++++++ tests/unit/Dropdown.test.js | 3 -- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/integration/dropdown/test_search_value.py diff --git a/tests/integration/dropdown/test_search_value.py b/tests/integration/dropdown/test_search_value.py new file mode 100644 index 000000000..43419d3b6 --- /dev/null +++ b/tests/integration/dropdown/test_search_value.py @@ -0,0 +1,36 @@ +from multiprocessing import Value +import dash +from dash.dependencies import Input, Output, State +import dash.testing.wait as wait +import dash_core_components as dcc +import dash_html_components as html + + +def test_search_value(dash_duo): + app = dash.Dash(__name__) + app.layout = html.Div( + [dcc.Dropdown(id="dropdown", search_value="something"), html.Div(id="output")] + ) + + call_count = Value("i", 0) + + @app.callback( + Output("output", "children"), inputs=[Input("dropdown", "search_value")] + ) + def update_output(search_value): + call_count.value += 1 + return 'search_value="{}"'.format(search_value) + + dash_duo.start_server(app) + + # Get the inner input used for search value. + input_ = dash_duo.find_element("#dropdown").find_element_by_tag_name("input") + + # callback gets called with initial input + wait.until(lambda: call_count.value == 1, timeout=1) + + assert dash_duo.wait_for_text_to_equal("#output", 'search_value="something"') + + input_.send_keys("x") + wait.until(lambda: call_count.value == 2, timeout=1) + assert dash_duo.wait_for_text_to_equal("#output", 'search_value="x"') diff --git a/tests/unit/Dropdown.test.js b/tests/unit/Dropdown.test.js index 1d6e96ed2..559add644 100644 --- a/tests/unit/Dropdown.test.js +++ b/tests/unit/Dropdown.test.js @@ -53,9 +53,6 @@ describe('Props can be set properly', () => { expect(multiDD.props()).toEqual(multiProps); }); - test('search_value is being updated', () => { - }) - test('props.id is set as the outer element id', () => { // test if id is in the actual HTML string const ddTag = singleDD.render(); From b20dbb4b4de56e0c34f082e9ee2526244dbbacf9 Mon Sep 17 00:00:00 2001 From: Pieter Mulder Date: Thu, 26 Sep 2019 19:19:20 +0200 Subject: [PATCH 3/8] Update tests/integration/dropdown/test_search_value.py Co-Authored-By: Byron Zhu --- tests/integration/dropdown/test_search_value.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/dropdown/test_search_value.py b/tests/integration/dropdown/test_search_value.py index 43419d3b6..4c2eeca3a 100644 --- a/tests/integration/dropdown/test_search_value.py +++ b/tests/integration/dropdown/test_search_value.py @@ -6,7 +6,7 @@ import dash_html_components as html -def test_search_value(dash_duo): +def test_ddsv001_search_value(dash_duo): app = dash.Dash(__name__) app.layout = html.Div( [dcc.Dropdown(id="dropdown", search_value="something"), html.Div(id="output")] From 8add84bd1d8ac1c3ab760f5962e801add54ee1e7 Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 19:23:17 +0200 Subject: [PATCH 4/8] Simplify search_value test --- tests/integration/dropdown/test_search_value.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/dropdown/test_search_value.py b/tests/integration/dropdown/test_search_value.py index 4c2eeca3a..11f731c11 100644 --- a/tests/integration/dropdown/test_search_value.py +++ b/tests/integration/dropdown/test_search_value.py @@ -24,13 +24,13 @@ def update_output(search_value): dash_duo.start_server(app) # Get the inner input used for search value. - input_ = dash_duo.find_element("#dropdown").find_element_by_tag_name("input") + input_ = dash_duo.find_element("#dropdown input") # callback gets called with initial input wait.until(lambda: call_count.value == 1, timeout=1) - assert dash_duo.wait_for_text_to_equal("#output", 'search_value="something"') + dash_duo.wait_for_text_to_equal("#output", 'search_value="something"') input_.send_keys("x") wait.until(lambda: call_count.value == 2, timeout=1) - assert dash_duo.wait_for_text_to_equal("#output", 'search_value="x"') + dash_duo.wait_for_text_to_equal("#output", 'search_value="x"') From 293b757da320aa248c037de3454307e68e7651f1 Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 20:34:09 +0200 Subject: [PATCH 5/8] Simplify test further --- tests/integration/dropdown/test_search_value.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/integration/dropdown/test_search_value.py b/tests/integration/dropdown/test_search_value.py index 11f731c11..16941350c 100644 --- a/tests/integration/dropdown/test_search_value.py +++ b/tests/integration/dropdown/test_search_value.py @@ -1,4 +1,3 @@ -from multiprocessing import Value import dash from dash.dependencies import Input, Output, State import dash.testing.wait as wait @@ -12,13 +11,10 @@ def test_ddsv001_search_value(dash_duo): [dcc.Dropdown(id="dropdown", search_value="something"), html.Div(id="output")] ) - call_count = Value("i", 0) - @app.callback( Output("output", "children"), inputs=[Input("dropdown", "search_value")] ) def update_output(search_value): - call_count.value += 1 return 'search_value="{}"'.format(search_value) dash_duo.start_server(app) @@ -26,11 +22,7 @@ def update_output(search_value): # Get the inner input used for search value. input_ = dash_duo.find_element("#dropdown input") - # callback gets called with initial input - wait.until(lambda: call_count.value == 1, timeout=1) - dash_duo.wait_for_text_to_equal("#output", 'search_value="something"') input_.send_keys("x") - wait.until(lambda: call_count.value == 2, timeout=1) dash_duo.wait_for_text_to_equal("#output", 'search_value="x"') From 7980fdf9dbc31072ed2659c4d9b3392a1c31917b Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 20:34:27 +0200 Subject: [PATCH 6/8] Add test for dynamic options from server --- .../dropdown/test_dynamic_options.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/integration/dropdown/test_dynamic_options.py diff --git a/tests/integration/dropdown/test_dynamic_options.py b/tests/integration/dropdown/test_dynamic_options.py new file mode 100644 index 000000000..81d50821f --- /dev/null +++ b/tests/integration/dropdown/test_dynamic_options.py @@ -0,0 +1,54 @@ +import dash +from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate +import dash.testing.wait as wait +import dash_core_components as dcc + + +def test_ddsv001_dynamic_options(dash_duo): + options=[ + {'label': 'New York City', 'value': 'NYC'}, + {'label': 'Montreal', 'value': 'MTL'}, + {'label': 'San Francisco', 'value': 'SF'} + ] + + app = dash.Dash(__name__) + app.layout = dcc.Dropdown(id="my-dynamic-dropdown", options=[]) + + @app.callback( + dash.dependencies.Output('my-dynamic-dropdown', 'options'), + [dash.dependencies.Input('my-dynamic-dropdown', 'search_value')], + ) + def update_options(search_value): + if not search_value: + raise PreventUpdate + return [o for o in options if search_value in o['label']] + + dash_duo.start_server(app) + + # Get the inner input used for search value. + dropdown = dash_duo.find_element("#my-dynamic-dropdown") + input_ = dropdown.find_element_by_css_selector("input") + + # Focus on the input to open the options menu + input_.send_keys("x") + + #No options to be found with `x` in them, should show the empty message. + dash_duo.wait_for_text_to_equal(".Select-noresults", "No results found") + + input_.clear() + input_.send_keys("o") + + options = dropdown.find_elements_by_css_selector(".VirtualizedSelectOption") + + # Should show all options. + assert len(options) == 3 + + # Searching for `on` + input_.send_keys("n") + + options = dropdown.find_elements_by_css_selector(".VirtualizedSelectOption") + + assert len(options) == 1 + print(options) + assert options[0].text == "Montreal" From 78c9463e40ad74020db2a777e3f05003decf44e8 Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 20:50:35 +0200 Subject: [PATCH 7/8] Reformat --- .../integration/dropdown/test_dynamic_options.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/integration/dropdown/test_dynamic_options.py b/tests/integration/dropdown/test_dynamic_options.py index 81d50821f..dacf69000 100644 --- a/tests/integration/dropdown/test_dynamic_options.py +++ b/tests/integration/dropdown/test_dynamic_options.py @@ -6,23 +6,23 @@ def test_ddsv001_dynamic_options(dash_duo): - options=[ - {'label': 'New York City', 'value': 'NYC'}, - {'label': 'Montreal', 'value': 'MTL'}, - {'label': 'San Francisco', 'value': 'SF'} + options = [ + {"label": "New York City", "value": "NYC"}, + {"label": "Montreal", "value": "MTL"}, + {"label": "San Francisco", "value": "SF"}, ] app = dash.Dash(__name__) app.layout = dcc.Dropdown(id="my-dynamic-dropdown", options=[]) @app.callback( - dash.dependencies.Output('my-dynamic-dropdown', 'options'), - [dash.dependencies.Input('my-dynamic-dropdown', 'search_value')], + dash.dependencies.Output("my-dynamic-dropdown", "options"), + [dash.dependencies.Input("my-dynamic-dropdown", "search_value")], ) def update_options(search_value): if not search_value: raise PreventUpdate - return [o for o in options if search_value in o['label']] + return [o for o in options if search_value in o["label"]] dash_duo.start_server(app) @@ -33,7 +33,7 @@ def update_options(search_value): # Focus on the input to open the options menu input_.send_keys("x") - #No options to be found with `x` in them, should show the empty message. + # No options to be found with `x` in them, should show the empty message. dash_duo.wait_for_text_to_equal(".Select-noresults", "No results found") input_.clear() From 3f57805648c5fd72b8b025290147f94349de78cd Mon Sep 17 00:00:00 2001 From: inytar Date: Thu, 26 Sep 2019 21:17:57 +0200 Subject: [PATCH 8/8] Make TCID unique --- tests/integration/dropdown/test_dynamic_options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/dropdown/test_dynamic_options.py b/tests/integration/dropdown/test_dynamic_options.py index dacf69000..c3d75917b 100644 --- a/tests/integration/dropdown/test_dynamic_options.py +++ b/tests/integration/dropdown/test_dynamic_options.py @@ -5,7 +5,7 @@ import dash_core_components as dcc -def test_ddsv001_dynamic_options(dash_duo): +def test_dddo001_dynamic_options(dash_duo): options = [ {"label": "New York City", "value": "NYC"}, {"label": "Montreal", "value": "MTL"},