Skip to content

Commit 437b9ee

Browse files
committed
Fix dropdown integration tests
1 parent 59c3d69 commit 437b9ee

File tree

8 files changed

+92
-34
lines changed

8 files changed

+92
-34
lines changed

components/dash-core-components/src/components/css/dropdown.css

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
}
101101

102102
.dash-dropdown-search-icon,
103-
.dash-dropdown-search-clear {
103+
.dash-dropdown-clear {
104104
width: calc(var(--Dash-Spacing) * 3);
105105
height: calc(var(--Dash-Spacing) * 3);
106106
}
@@ -109,7 +109,7 @@
109109
color: var(--Dash-Fill-Interactive-Strong);
110110
}
111111

112-
.dash-dropdown-search-clear {
112+
.dash-dropdown-clear {
113113
background: none;
114114
border: none;
115115
cursor: pointer;
@@ -121,11 +121,11 @@
121121
color: var(--Dash-Text-Strong);
122122
}
123123

124-
.dash-dropdown-search-clear:hover {
124+
.dash-dropdown-clear:hover {
125125
color: var(--Dash-Fill-Interactive-Strong);
126126
}
127127

128-
.dash-dropdown-search-clear:focus {
128+
.dash-dropdown-clear:focus {
129129
outline: 2px solid var(--Dash-Fill-Interactive-Strong);
130130
outline-offset: 1px;
131131
border-radius: 2px;
@@ -139,6 +139,17 @@
139139
color: var(--Dash-Text-Strong);
140140
outline: none;
141141
padding: 0;
142+
143+
/* Hide the "x" clear button in search inputs */
144+
&::-webkit-search-cancel-button {
145+
-webkit-appearance: none;
146+
appearance: none;
147+
display: none;
148+
}
149+
150+
&::-ms-clear {
151+
display: none;
152+
}
142153
}
143154

144155
.dash-dropdown-actions {

components/dash-core-components/src/fragments/Dropdown.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ const DropdownOption: React.FC<DropdownOptionProps> = ({
6363
<input
6464
type="checkbox"
6565
checked={isSelected}
66+
value={
67+
typeof option.value === 'boolean'
68+
? `${option.value}`
69+
: option.value
70+
}
6671
disabled={!!option.disabled}
6772
onChange={() => onClick(option)}
6873
readOnly
@@ -449,7 +454,7 @@ const Dropdown = (props: DropdownProps) => {
449454
)}
450455
{clearable && !disabled && !!sanitizedValues.length && (
451456
<a
452-
className="dash-dropdown-search-clear"
457+
className="dash-dropdown-clear"
453458
onClick={e => {
454459
e.preventDefault();
455460
handleClear();
@@ -493,7 +498,7 @@ const Dropdown = (props: DropdownProps) => {
493498
{search_value && (
494499
<button
495500
type="button"
496-
className="dash-dropdown-search-clear"
501+
className="dash-dropdown-clear"
497502
onClick={handleClearSearch}
498503
aria-label="Clear search"
499504
>
@@ -544,6 +549,12 @@ const Dropdown = (props: DropdownProps) => {
544549
/>
545550
);
546551
})}
552+
{search_value &&
553+
displayOptions.length === 0 && (
554+
<span className="dash-dropdown-option">
555+
No options found
556+
</span>
557+
)}
547558
</div>
548559
)}
549560
</Popover.Content>

components/dash-core-components/tests/integration/dropdown/test_clearable_false.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import pytest
12
from dash import Dash, Input, Output, dcc, html
2-
3-
from selenium.webdriver.common.keys import Keys
3+
from selenium.common.exceptions import TimeoutException
4+
from selenium.webdriver.support.ui import WebDriverWait
45

56

67
def test_ddcf001_clearable_false_single(dash_duo):
@@ -30,12 +31,23 @@ def update_value(val):
3031

3132
dash_duo.start_server(app)
3233

33-
dropdown = dash_duo.find_element("#my-unclearable-dropdown input")
34-
dropdown.send_keys(Keys.BACKSPACE)
35-
dash_duo.find_element("#dropdown-value").click()
34+
with pytest.raises(TimeoutException):
35+
WebDriverWait(dash_duo.driver, 1).until(
36+
lambda _: dash_duo.find_element(
37+
"#my-unclearable-dropdown .dash-dropdown-clear"
38+
)
39+
)
40+
41+
output_text = dash_duo.find_element("#dropdown-value").text
3642

37-
assert len(dash_duo.find_element("#dropdown-value").text) > 0
43+
dash_duo.find_element("#my-unclearable-dropdown ").click()
3844

45+
# Clicking the selected item should not de-select it.
46+
selected_item = dash_duo.find_element(
47+
f'#my-unclearable-dropdown input[value="{output_text}"]'
48+
)
49+
selected_item.click()
50+
assert dash_duo.find_element("#dropdown-value").text == output_text
3951
assert dash_duo.get_logs() == []
4052

4153

@@ -52,6 +64,7 @@ def test_ddcf002_clearable_false_multi(dash_duo):
5264
],
5365
value=["MTL", "SF"],
5466
multi=True,
67+
closeOnSelect=False,
5568
clearable=False,
5669
),
5770
html.Div(id="dropdown-value", style={"height": "10px", "width": "10px"}),
@@ -67,11 +80,22 @@ def update_value(val):
6780

6881
dash_duo.start_server(app)
6982

70-
dropdown = dash_duo.find_element("#my-unclearable-dropdown input")
71-
dropdown.send_keys(Keys.BACKSPACE)
72-
dropdown.send_keys(Keys.BACKSPACE)
73-
dash_duo.find_element("#dropdown-value").click()
83+
with pytest.raises(TimeoutException):
84+
WebDriverWait(dash_duo.driver, 1).until(
85+
lambda _: dash_duo.find_element(
86+
"#my-unclearable-dropdown .dash-dropdown-clear"
87+
)
88+
)
89+
90+
assert dash_duo.find_element("#dropdown-value").text == "MTL, SF"
91+
92+
dash_duo.find_element("#my-unclearable-dropdown ").click()
93+
94+
# Attempt to deselect all items. Everything should deselect until we get to
95+
# the last item which cannot be cleared.
96+
selected = dash_duo.find_elements("#my-unclearable-dropdown input[checked]")
97+
[el.click() for el in selected]
7498

75-
assert len(dash_duo.find_element("#dropdown-value").text) > 0
99+
assert dash_duo.find_element("#dropdown-value").text == "SF"
76100

77101
assert dash_duo.get_logs() == []

components/dash-core-components/tests/integration/dropdown/test_dynamic_options.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,34 @@ def update_options(search_value):
2727

2828
dash_dcc.start_server(app)
2929

30+
dropdown = dash_dcc.find_element("#my-dynamic-dropdown")
31+
dropdown.click()
32+
3033
# Get the inner input used for search value.
3134
input_ = dash_dcc.find_element("#my-dynamic-dropdown input")
3235

3336
# Focus on the input to open the options menu
3437
input_.send_keys("x")
3538

3639
# No options to be found with `x` in them, should show the empty message.
37-
dash_dcc.wait_for_text_to_equal(".Select-noresults", "No results found")
40+
dash_dcc.wait_for_text_to_equal(".dash-dropdown-options", "No options found")
3841

3942
input_.clear()
4043
input_.send_keys("o")
4144

42-
options = dash_dcc.find_elements("#my-dynamic-dropdown .VirtualizedSelectOption")
45+
time.sleep(0.25)
46+
options = dash_dcc.find_elements("#my-dynamic-dropdown .dash-dropdown-option")
4347

4448
# Should show all options.
4549
assert len(options) == 3
4650

4751
# Searching for `on`
4852
input_.send_keys("n")
4953

50-
options = dash_dcc.find_elements("#my-dynamic-dropdown .VirtualizedSelectOption")
54+
time.sleep(0.25)
55+
options = dash_dcc.find_elements("#my-dynamic-dropdown .dash-dropdown-option")
5156

5257
assert len(options) == 1
53-
print(options)
5458
assert options[0].text == "Montreal"
5559

5660
assert dash_dcc.get_logs() == []
@@ -68,7 +72,7 @@ def test_dddo002_array_comma_value(dash_dcc):
6872

6973
dash_dcc.start_server(app)
7074

71-
dash_dcc.wait_for_text_to_equal("#react-select-2--value-0", "San Francisco, CA\n ")
75+
dash_dcc.wait_for_text_to_equal(".dash-dropdown-value", "San Francisco, CA")
7276

7377
assert dash_dcc.get_logs() == []
7478

@@ -118,11 +122,15 @@ def update_options(search_value):
118122

119123
dash_dcc.start_server(app)
120124

121-
input_ = dash_dcc.find_element("#dropdown input")
125+
dropdown = dash_dcc.find_element("#dropdown")
126+
dropdown.click()
127+
input_ = dash_dcc.find_element(".dash-dropdown-search")
122128

123129
input_.send_keys("aa1")
124-
input_.send_keys(Keys.ENTER)
130+
input_.send_keys(Keys.ESCAPE)
125131

132+
dropdown.click()
133+
input_ = dash_dcc.find_element(".dash-dropdown-search")
126134
input_.send_keys("b")
127135

128136
time.sleep(1)

components/dash-core-components/tests/integration/dropdown/test_remove_option.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import json
2-
32
import pytest
4-
53
from dash import Dash, html, dcc, Output, Input, State, Patch
64
from dash.exceptions import PreventUpdate
75

@@ -183,9 +181,11 @@ def on_value(value):
183181

184182
dash_dcc.wait_for_text_to_equal("#count-output", "1")
185183

186-
select_input = dash_dcc.find_element("#drop input")
184+
dropdown = dash_dcc.find_element("#drop")
185+
dropdown.click()
186+
select_input = dash_dcc.find_element("#drop .dash-dropdown-search")
187187
select_input.send_keys("a")
188-
select_input.send_keys(Keys.ENTER)
188+
dash_dcc.find_element("#drop .dash-dropdown-option").send_keys(Keys.SPACE)
189189

190190
dash_dcc.wait_for_text_to_equal("#output", "Value=a")
191191
dash_dcc.wait_for_text_to_equal("#count-output", "2")

components/dash-core-components/tests/integration/dropdown/test_search_value.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ def update_output(search_value):
1616
dash_duo.start_server(app)
1717

1818
# Get the inner input used for search value.
19-
input_ = dash_duo.find_element("#dropdown input")
19+
dropdown = dash_duo.find_element("#dropdown")
20+
dropdown.click()
21+
input_ = dash_duo.find_element(".dash-dropdown-search")
2022

2123
dash_duo.wait_for_text_to_equal("#output", 'search_value="something"')
2224

25+
dash_duo.find_element(
26+
".dash-dropdown-search-container .dash-dropdown-clear"
27+
).click()
2328
input_.send_keys("x")
2429
dash_duo.wait_for_text_to_equal("#output", 'search_value="x"')
2530

components/dash-core-components/tests/integration/dropdown/test_styles.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ def test_ddst001_cursor_should_be_pointer(dash_duo):
4040
dash_duo.start_server(app)
4141

4242
dash_duo.find_element("#dropdown").click()
43-
dash_duo.wait_for_element("#dropdown .Select-menu-outer")
43+
dash_duo.wait_for_element("#dropdown .dash-dropdown-options")
4444

4545
items = dash_duo.find_elements(
46-
"#dropdown .Select-menu-outer .VirtualizedSelectOption"
46+
"#dropdown .dash-dropdown-options .dash-dropdown-option"
4747
)
4848

4949
assert items[0].value_of_css_property("cursor") == "pointer"

components/dash-core-components/tests/integration/dropdown/test_visibility.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_ddvi001_fixed_table(dash_duo):
4040
dash_duo.start_server(app)
4141

4242
dash_duo.find_element("#dropdown").click()
43-
dash_duo.wait_for_element("#dropdown .Select-menu-outer")
43+
dash_duo.wait_for_element("#dropdown .dash-dropdown-options")
4444

4545
dash_duo.percy_snapshot("dcc.Dropdown dropdown overlaps table fixed rows/columns")
4646

@@ -59,8 +59,7 @@ def test_ddvi002_maxHeight(dash_duo):
5959
dash_duo.start_server(app)
6060

6161
dash_duo.find_element("#dropdown").click()
62-
dash_duo.wait_for_element("#dropdown .Select-menu-outer")
63-
62+
dash_duo.wait_for_element("#dropdown .dash-dropdown-options")
6463
dash_duo.percy_snapshot("dcc.Dropdown dropdown menu maxHeight 800px")
6564

6665
assert dash_duo.get_logs() == []

0 commit comments

Comments
 (0)