1
1
import pytest
2
2
import dash
3
- from dash import Dash , dcc , html
3
+ from dash import Dash , Input , State , dcc , html
4
+ from dash .dash import _ID_LOCATION
4
5
from dash .exceptions import NoLayoutException
5
6
6
7
@@ -59,38 +60,33 @@ def test_pala001_layout(dash_duo, clear_pages_state):
59
60
assert dash_duo .driver .title == page ["title" ], "check that page title updates"
60
61
61
62
# test redirects
62
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /v2" )
63
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /v2" )
63
64
dash_duo .wait_for_text_to_equal ("#text_redirect" , "text for redirect" )
64
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /old-home-page" )
65
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /old-home-page" )
65
66
dash_duo .wait_for_text_to_equal ("#text_redirect" , "text for redirect" )
66
- assert (
67
- dash_duo .driver .current_url
68
- == f"http://localhost:{ dash_duo .server .port } /redirect"
69
- )
67
+ assert dash_duo .driver .current_url == f"{ dash_duo .server_url } /redirect"
70
68
71
69
# test redirect with button and user defined dcc.Location
72
70
# note: dcc.Location must be defined in app.py
73
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /page1" )
71
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /page1" )
74
72
dash_duo .find_element ("#btn1" ).click ()
75
73
dash_duo .wait_for_text_to_equal ("#text_page2" , "text for page2" )
76
74
77
75
# test query strings
78
- dash_duo .wait_for_page (
79
- url = f"http://localhost:{ dash_duo .server .port } /query-string?velocity=10"
80
- )
76
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /query-string?velocity=10" )
81
77
assert (
82
78
dash_duo .find_element ("#velocity" ).get_attribute ("value" ) == "10"
83
79
), "query string passed to layout"
84
80
85
81
# test path variables
86
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /a/none/b/none" )
82
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /a/none/b/none" )
87
83
dash_duo .wait_for_text_to_equal ("#path_vars" , "variables from pathname:none none" )
88
84
89
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /a/var1/b/var2" )
85
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /a/var1/b/var2" )
90
86
dash_duo .wait_for_text_to_equal ("#path_vars" , "variables from pathname:var1 var2" )
91
87
92
88
# test page not found
93
- dash_duo .wait_for_page (url = f"http://localhost: { dash_duo .server . port } /find_me" )
89
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /find_me" )
94
90
dash_duo .wait_for_text_to_equal ("#text_not_found_404" , "text for not_found_404" )
95
91
96
92
# test `validation_layout` exists when suppress_callback_exceptions=False`
@@ -121,20 +117,20 @@ def test_pala002_meta_tags_default(dash_duo, clear_pages_state):
121
117
{"property" : "twitter:card" , "content" : "summary_large_image" },
122
118
{
123
119
"property" : "twitter:url" ,
124
- "content" : f"http://localhost: { dash_duo .server . port } /" ,
120
+ "content" : f"{ dash_duo .server_url } /" ,
125
121
},
126
122
{"property" : "twitter:title" , "content" : "Multi layout2" },
127
123
{"property" : "twitter:description" , "content" : "" },
128
124
{
129
125
"property" : "twitter:image" ,
130
- "content" : f"http://localhost: { dash_duo .server . port } /assets/app.jpeg" ,
126
+ "content" : f"{ dash_duo .server_url } /assets/app.jpeg" ,
131
127
},
132
128
{"property" : "og:title" , "content" : "Multi layout2" },
133
129
{"property" : "og:type" , "content" : "website" },
134
130
{"property" : "og:description" , "content" : "" },
135
131
{
136
132
"property" : "og:image" ,
137
- "content" : f"http://localhost: { dash_duo .server . port } /assets/app.jpeg" ,
133
+ "content" : f"{ dash_duo .server_url } /assets/app.jpeg" ,
138
134
},
139
135
]
140
136
@@ -149,7 +145,7 @@ def test_pala003_meta_tags_custom(dash_duo, clear_pages_state):
149
145
{"property" : "twitter:card" , "content" : "summary_large_image" },
150
146
{
151
147
"property" : "twitter:url" ,
152
- "content" : f"http://localhost: { dash_duo .server . port } /" ,
148
+ "content" : f"{ dash_duo .server_url } /" ,
153
149
},
154
150
{"property" : "twitter:title" , "content" : "Supplied Title" },
155
151
{
@@ -158,14 +154,14 @@ def test_pala003_meta_tags_custom(dash_duo, clear_pages_state):
158
154
},
159
155
{
160
156
"property" : "twitter:image" ,
161
- "content" : f"http://localhost: { dash_duo .server . port } /assets/birds.jpeg" ,
157
+ "content" : f"{ dash_duo .server_url } /assets/birds.jpeg" ,
162
158
},
163
159
{"property" : "og:title" , "content" : "Supplied Title" },
164
160
{"property" : "og:type" , "content" : "website" },
165
161
{"property" : "og:description" , "content" : "This is the supplied description" },
166
162
{
167
163
"property" : "og:image" ,
168
- "content" : f"http://localhost: { dash_duo .server . port } /assets/birds.jpeg" ,
164
+ "content" : f"{ dash_duo .server_url } /assets/birds.jpeg" ,
169
165
},
170
166
]
171
167
@@ -179,3 +175,63 @@ def test_pala004_no_layout_exception(clear_pages_state):
179
175
Dash (__name__ , use_pages = True , pages_folder = "pages_error" )
180
176
181
177
assert error_msg in err .value .args [0 ]
178
+
179
+
180
+ def get_routing_inputs_app ():
181
+ app = Dash (
182
+ __name__ ,
183
+ use_pages = True ,
184
+ routing_callback_inputs = {
185
+ "hash" : State (_ID_LOCATION , "hash" ),
186
+ "language" : Input ("language" , "value" ),
187
+ },
188
+ )
189
+ # Page with layout from a variable: should render and not be impacted
190
+ # by routing callback inputs
191
+ dash .register_page (
192
+ "home" ,
193
+ layout = html .Div ("Home" , id = "contents" ),
194
+ path = "/" ,
195
+ )
196
+
197
+ # Page with a layout function, should see the routing callback inputs
198
+ # as keyword arguments
199
+ def layout1 (hash : str = None , language : str = "en" , ** kwargs ):
200
+ translations = {
201
+ "en" : "Hash says: {}" ,
202
+ "fr" : "Le hash dit: {}" ,
203
+ }
204
+ return html .Div (translations [language ].format (hash ), id = "contents" )
205
+
206
+ dash .register_page (
207
+ "function_layout" ,
208
+ path = "/function-layout" ,
209
+ layout = layout1 ,
210
+ )
211
+ app .layout = html .Div (
212
+ [
213
+ dcc .Dropdown (id = "language" , options = ["en" , "fr" ], value = "en" ),
214
+ dash .page_container ,
215
+ ]
216
+ )
217
+ return app
218
+
219
+
220
+ def test_pala005_routing_inputs (dash_duo , clear_pages_state ):
221
+ dash_duo .start_server (get_routing_inputs_app ())
222
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } #123" )
223
+ dash_duo .wait_for_text_to_equal ("#contents" , "Home" )
224
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /" )
225
+ dash_duo .wait_for_text_to_equal ("#contents" , "Home" )
226
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /function-layout" )
227
+ dash_duo .wait_for_text_to_equal ("#contents" , "Hash says:" )
228
+ # hash is a State therefore navigating to the same page with hash will not
229
+ # re-render the layout function
230
+ dash_duo .wait_for_page (url = f"{ dash_duo .server_url } /function-layout#123" )
231
+ dash_duo .wait_for_text_to_equal ("#contents" , "Hash says:" )
232
+ # Refreshing the page re-runs the layout function
233
+ dash_duo .driver .refresh ()
234
+ dash_duo .wait_for_text_to_equal ("#contents" , "Hash says: #123" )
235
+ # Changing the language Input re-runs the layout function
236
+ dash_duo .select_dcc_dropdown ("#language" , "fr" )
237
+ dash_duo .wait_for_text_to_equal ("#contents" , "Le hash dit: #123" )
0 commit comments