Skip to content

Commit c00509d

Browse files
committed
Add test for button
1 parent 6d48e26 commit c00509d

1 file changed

Lines changed: 227 additions & 0 deletions

File tree

  • components/dash-core-components/tests/integration/button
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
from dash import Dash, Input, Output, dcc, html
2+
from selenium.webdriver.common.action_chains import ActionChains
3+
from selenium.webdriver.common.keys import Keys
4+
5+
6+
def test_btev001_clicks_and_blur(dash_dcc):
7+
"""Test that n_clicks, n_clicks_timestamp, n_blur, and n_blur_timestamp work correctly"""
8+
app = Dash(__name__)
9+
app.layout = html.Div(
10+
[
11+
dcc.Button(
12+
"Click Me",
13+
id="test-button",
14+
className="custom-button-class",
15+
),
16+
html.Div(id="click-output"),
17+
html.Div(id="blur-output"),
18+
html.Div(id="click-timestamp-output"),
19+
html.Div(id="blur-timestamp-output"),
20+
# Add a second element to blur to
21+
html.Button("Other Element", id="other-element"),
22+
]
23+
)
24+
25+
@app.callback(
26+
Output("click-output", "children"),
27+
Input("test-button", "n_clicks"),
28+
)
29+
def update_clicks(n_clicks):
30+
if n_clicks is None:
31+
return "Clicks: 0"
32+
return f"Clicks: {n_clicks}"
33+
34+
@app.callback(
35+
Output("blur-output", "children"),
36+
Input("test-button", "n_blur"),
37+
)
38+
def update_blur(n_blur):
39+
if n_blur is None:
40+
return "Blurs: 0"
41+
return f"Blurs: {n_blur}"
42+
43+
@app.callback(
44+
Output("click-timestamp-output", "children"),
45+
Input("test-button", "n_clicks_timestamp"),
46+
)
47+
def update_click_timestamp(n_clicks_timestamp):
48+
if n_clicks_timestamp is None or n_clicks_timestamp == -1:
49+
return "Click timestamp: None"
50+
return f"Click timestamp: {n_clicks_timestamp}"
51+
52+
@app.callback(
53+
Output("blur-timestamp-output", "children"),
54+
Input("test-button", "n_blur_timestamp"),
55+
)
56+
def update_blur_timestamp(n_blur_timestamp):
57+
if n_blur_timestamp is None or n_blur_timestamp == -1:
58+
return "Blur timestamp: None"
59+
return f"Blur timestamp: {n_blur_timestamp}"
60+
61+
dash_dcc.start_server(app)
62+
63+
# Verify custom class is applied
64+
button = dash_dcc.find_element(".custom-button-class")
65+
assert button is not None, "Custom className should be applied"
66+
67+
# Check initial state
68+
dash_dcc.wait_for_text_to_equal("#click-output", "Clicks: 0")
69+
dash_dcc.wait_for_text_to_equal("#blur-output", "Blurs: 0")
70+
dash_dcc.wait_for_text_to_equal("#click-timestamp-output", "Click timestamp: None")
71+
dash_dcc.wait_for_text_to_equal("#blur-timestamp-output", "Blur timestamp: None")
72+
73+
# Click the button
74+
button.click()
75+
dash_dcc.wait_for_text_to_equal("#click-output", "Clicks: 1")
76+
77+
# Verify click timestamp is set
78+
click_timestamp_text = dash_dcc.find_element("#click-timestamp-output").text
79+
assert "Click timestamp: " in click_timestamp_text
80+
assert click_timestamp_text != "Click timestamp: None"
81+
82+
# Click again
83+
button.click()
84+
dash_dcc.wait_for_text_to_equal("#click-output", "Clicks: 2")
85+
86+
# Blur by clicking on other element
87+
other_element = dash_dcc.find_element("#other-element")
88+
other_element.click()
89+
90+
# Check blur was registered
91+
dash_dcc.wait_for_text_to_equal("#blur-output", "Blurs: 1")
92+
93+
# Verify blur timestamp is set
94+
blur_timestamp_text = dash_dcc.find_element("#blur-timestamp-output").text
95+
assert "Blur timestamp: " in blur_timestamp_text
96+
assert blur_timestamp_text != "Blur timestamp: None"
97+
98+
# Click the button again to focus it
99+
button.click()
100+
dash_dcc.wait_for_text_to_equal("#click-output", "Clicks: 3")
101+
102+
# Blur again by clicking other element
103+
other_element.click()
104+
dash_dcc.wait_for_text_to_equal("#blur-output", "Blurs: 2")
105+
106+
assert dash_dcc.get_logs() == []
107+
108+
109+
def test_btev002_disabled_button(dash_dcc):
110+
"""Test that disabled button doesn't trigger click or blur events"""
111+
app = Dash(__name__)
112+
app.layout = html.Div(
113+
[
114+
dcc.Button(
115+
"Disabled Button",
116+
id="disabled-button",
117+
className="disabled-test-button",
118+
disabled=True,
119+
),
120+
html.Div(id="click-output"),
121+
html.Div(id="blur-output"),
122+
html.Button("Other Element", id="other-element"),
123+
]
124+
)
125+
126+
@app.callback(
127+
Output("click-output", "children"),
128+
Input("disabled-button", "n_clicks"),
129+
)
130+
def update_clicks(n_clicks):
131+
return f"Clicks: {n_clicks or 0}"
132+
133+
@app.callback(
134+
Output("blur-output", "children"),
135+
Input("disabled-button", "n_blur"),
136+
)
137+
def update_blur(n_blur):
138+
return f"Blurs: {n_blur or 0}"
139+
140+
dash_dcc.start_server(app)
141+
142+
button = dash_dcc.find_element(".disabled-test-button")
143+
other_element = dash_dcc.find_element("#other-element")
144+
145+
# Verify button is disabled
146+
assert button.get_attribute("disabled") is not None
147+
148+
# Initial state
149+
dash_dcc.wait_for_text_to_equal("#click-output", "Clicks: 0")
150+
dash_dcc.wait_for_text_to_equal("#blur-output", "Blurs: 0")
151+
152+
# Try to click - should not increment
153+
button.click()
154+
155+
# Give it a moment and verify it's still 0
156+
import time
157+
158+
time.sleep(0.5)
159+
160+
click_text = dash_dcc.find_element("#click-output").text
161+
assert click_text == "Clicks: 0", "Disabled button should not trigger clicks"
162+
163+
# Try to blur by clicking other element - should not increment
164+
other_element.click()
165+
166+
time.sleep(0.5)
167+
168+
blur_text = dash_dcc.find_element("#blur-output").text
169+
assert blur_text == "Blurs: 0", "Disabled button should not trigger blur events"
170+
171+
assert dash_dcc.get_logs() == []
172+
173+
174+
def test_btev003_button_states_visual(dash_dcc):
175+
"""Visual test for button states: base, hover, and focus in one snapshot"""
176+
app = Dash(__name__)
177+
app.layout = html.Div(
178+
[
179+
html.Div(
180+
[
181+
html.H3("Base State"),
182+
dcc.Button("Base Button", id="base-button", className="state-base"),
183+
],
184+
style={"marginBottom": "30px"},
185+
),
186+
html.Div(
187+
[
188+
html.H3("Hover State"),
189+
dcc.Button(
190+
"Hover Button", id="hover-button", className="state-hover"
191+
),
192+
],
193+
style={"marginBottom": "30px"},
194+
),
195+
html.Div(
196+
[
197+
html.H3("Focus State"),
198+
dcc.Button(
199+
"Focus Button", id="focus-button", className="state-focus"
200+
),
201+
],
202+
style={"marginBottom": "30px"},
203+
),
204+
],
205+
style={"padding": "40px"},
206+
)
207+
208+
dash_dcc.start_server(app)
209+
210+
# Wait for all buttons to render
211+
dash_dcc.wait_for_element(".state-base")
212+
213+
# Set up each state
214+
# Tab to focus the focus button (using keyboard navigation)
215+
body = dash_dcc.find_element("body")
216+
body.send_keys(Keys.TAB) # Focus base button
217+
body.send_keys(Keys.TAB) # Focus hover button
218+
body.send_keys(Keys.TAB) # Focus focus button
219+
220+
# Hover over the hover button
221+
hover_button = dash_dcc.find_element(".state-hover")
222+
ActionChains(dash_dcc.driver).move_to_element(hover_button).perform()
223+
224+
# Take single snapshot showing all states
225+
dash_dcc.percy_snapshot("Button States - Base, Hover, Focus")
226+
227+
assert dash_dcc.get_logs() == []

0 commit comments

Comments
 (0)