@@ -15,10 +15,12 @@ def test_rdls001_multi_loading_components(dash_duo):
15
15
app .layout = html .Div (
16
16
children = [
17
17
html .H3 ("Edit text input to see loading state" ),
18
- dcc .Input (id = "input-3" , value = 'Input triggers the loading states' ),
19
- dcc .Loading (className = "loading-1" , children = [
20
- html .Div (id = "loading-output-1" )
21
- ], type = "default" ),
18
+ dcc .Input (id = "input-3" , value = "Input triggers the loading states" ),
19
+ dcc .Loading (
20
+ className = "loading-1" ,
21
+ children = [html .Div (id = "loading-output-1" )],
22
+ type = "default" ,
23
+ ),
22
24
html .Div (
23
25
[
24
26
dcc .Loading (
@@ -28,9 +30,9 @@ def test_rdls001_multi_loading_components(dash_duo):
28
30
),
29
31
dcc .Loading (
30
32
className = "loading-3" ,
31
- children = dcc .Graph (id = ' graph' ),
33
+ children = dcc .Graph (id = " graph" ),
32
34
type = "cube" ,
33
- )
35
+ ),
34
36
]
35
37
),
36
38
],
@@ -42,18 +44,19 @@ def test_rdls001_multi_loading_components(dash_duo):
42
44
Output ("loading-output-1" , "children" ),
43
45
Output ("loading-output-2" , "children" ),
44
46
],
45
- [Input ("input-3" , "value" )])
47
+ [Input ("input-3" , "value" )],
48
+ )
46
49
def input_triggers_nested (value ):
47
50
with lock :
48
51
return dict (data = [dict (y = [1 , 4 , 2 , 3 ])]), value , value
49
52
50
53
def wait_for_all_spinners ():
51
- dash_duo .find_element (' .loading-1 .dash-spinner.dash-default-spinner' )
52
- dash_duo .find_element (' .loading-2 .dash-spinner.dash-sk-circle' )
53
- dash_duo .find_element (' .loading-3 .dash-spinner.dash-cube-container' )
54
+ dash_duo .find_element (" .loading-1 .dash-spinner.dash-default-spinner" )
55
+ dash_duo .find_element (" .loading-2 .dash-spinner.dash-sk-circle" )
56
+ dash_duo .find_element (" .loading-3 .dash-spinner.dash-cube-container" )
54
57
55
58
def wait_for_no_spinners ():
56
- dash_duo .wait_for_no_elements (' .dash-spinner' )
59
+ dash_duo .wait_for_no_elements (" .dash-spinner" )
57
60
58
61
with lock :
59
62
dash_duo .start_server (app )
@@ -62,7 +65,105 @@ def wait_for_no_spinners():
62
65
wait_for_no_spinners ()
63
66
64
67
with lock :
65
- dash_duo .find_element (' #input-3' ).send_keys ('X' )
68
+ dash_duo .find_element (" #input-3" ).send_keys ("X" )
66
69
wait_for_all_spinners ()
67
70
68
71
wait_for_no_spinners ()
72
+
73
+
74
+ def test_rdls002_chained_loading_states (dash_duo ):
75
+ lock1 , lock2 , lock34 = Lock (), Lock (), Lock ()
76
+ app = dash .Dash (__name__ )
77
+
78
+ def loading_wrapped_div (_id , color ):
79
+ return html .Div (
80
+ dcc .Loading (
81
+ html .Div (
82
+ id = _id ,
83
+ style = {"width" : 200 , "height" : 200 , "backgroundColor" : color },
84
+ ),
85
+ className = _id ,
86
+ ),
87
+ style = {"display" : "inline-block" },
88
+ )
89
+
90
+ app .layout = html .Div (
91
+ [
92
+ html .Button (id = "button" , children = "Start" , n_clicks = 0 ),
93
+ loading_wrapped_div ("output-1" , "hotpink" ),
94
+ loading_wrapped_div ("output-2" , "rebeccapurple" ),
95
+ loading_wrapped_div ("output-3" , "green" ),
96
+ loading_wrapped_div ("output-4" , "#FF851B" ),
97
+ ]
98
+ )
99
+
100
+ @app .callback (Output ("output-1" , "children" ), [Input ("button" , "n_clicks" )])
101
+ def update_output_1 (n_clicks ):
102
+ with lock1 :
103
+ return "Output 1: {}" .format (n_clicks )
104
+
105
+ @app .callback (Output ("output-2" , "children" ), [Input ("output-1" , "children" )])
106
+ def update_output_2 (children ):
107
+ with lock2 :
108
+ return "Output 2: {}" .format (children )
109
+
110
+ @app .callback (
111
+ [Output ("output-3" , "children" ), Output ("output-4" , "children" )],
112
+ [Input ("output-2" , "children" )],
113
+ )
114
+ def update_output_34 (children ):
115
+ with lock34 :
116
+ return "Output 3: {}" .format (children ), "Output 4: {}" .format (children )
117
+
118
+ dash_duo .start_server (app )
119
+
120
+ def find_spinners (* nums ):
121
+ if not nums :
122
+ dash_duo .wait_for_no_elements (".dash-spinner" )
123
+ return
124
+
125
+ for n in nums :
126
+ dash_duo .find_element (".output-{} .dash-spinner" .format (n ))
127
+
128
+ assert len (dash_duo .find_elements (".dash-spinner" )) == len (nums )
129
+
130
+ def find_text (spec ):
131
+ templates = [
132
+ "Output 1: {}" ,
133
+ "Output 2: Output 1: {}" ,
134
+ "Output 3: Output 2: Output 1: {}" ,
135
+ "Output 4: Output 2: Output 1: {}" ,
136
+ ]
137
+ for n , v in spec .items ():
138
+ dash_duo .wait_for_text_to_equal (
139
+ "#output-{}" .format (n ), templates [n - 1 ].format (v )
140
+ )
141
+
142
+ find_text ({1 : 0 , 2 : 0 , 3 : 0 , 4 : 0 })
143
+ find_spinners ()
144
+
145
+ btn = dash_duo .find_element ("#button" )
146
+ # Can't use lock context managers here, because we want to acquire the
147
+ # second lock before releasing the first
148
+ lock1 .acquire ()
149
+ btn .click ()
150
+
151
+ find_spinners (1 )
152
+ find_text ({2 : 0 , 3 : 0 , 4 : 0 })
153
+
154
+ lock2 .acquire ()
155
+ lock1 .release ()
156
+
157
+ find_spinners (2 )
158
+ find_text ({1 : 1 , 3 : 0 , 4 : 0 })
159
+
160
+ lock34 .acquire ()
161
+ lock2 .release ()
162
+
163
+ find_spinners (3 , 4 )
164
+ find_text ({1 : 1 , 2 : 1 })
165
+
166
+ lock34 .release ()
167
+
168
+ find_spinners ()
169
+ find_text ({1 : 1 , 2 : 1 , 3 : 1 , 4 : 1 })
0 commit comments