11import pytest
22import dash
3- from dash import Dash , dcc , html
3+ from dash import Dash , Input , State , dcc , html
4+ from dash .dash import _ID_LOCATION
45from dash .exceptions import NoLayoutException
56
67
@@ -59,38 +60,33 @@ def test_pala001_layout(dash_duo, clear_pages_state):
5960 assert dash_duo .driver .title == page ["title" ], "check that page title updates"
6061
6162 # 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" )
6364 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" )
6566 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"
7068
7169 # test redirect with button and user defined dcc.Location
7270 # 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" )
7472 dash_duo .find_element ("#btn1" ).click ()
7573 dash_duo .wait_for_text_to_equal ("#text_page2" , "text for page2" )
7674
7775 # 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" )
8177 assert (
8278 dash_duo .find_element ("#velocity" ).get_attribute ("value" ) == "10"
8379 ), "query string passed to layout"
8480
8581 # 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" )
8783 dash_duo .wait_for_text_to_equal ("#path_vars" , "variables from pathname:none none" )
8884
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" )
9086 dash_duo .wait_for_text_to_equal ("#path_vars" , "variables from pathname:var1 var2" )
9187
9288 # 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" )
9490 dash_duo .wait_for_text_to_equal ("#text_not_found_404" , "text for not_found_404" )
9591
9692 # test `validation_layout` exists when suppress_callback_exceptions=False`
@@ -121,20 +117,20 @@ def test_pala002_meta_tags_default(dash_duo, clear_pages_state):
121117 {"property" : "twitter:card" , "content" : "summary_large_image" },
122118 {
123119 "property" : "twitter:url" ,
124- "content" : f"http://localhost: { dash_duo .server . port } /" ,
120+ "content" : f"{ dash_duo .server_url } /" ,
125121 },
126122 {"property" : "twitter:title" , "content" : "Multi layout2" },
127123 {"property" : "twitter:description" , "content" : "" },
128124 {
129125 "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" ,
131127 },
132128 {"property" : "og:title" , "content" : "Multi layout2" },
133129 {"property" : "og:type" , "content" : "website" },
134130 {"property" : "og:description" , "content" : "" },
135131 {
136132 "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" ,
138134 },
139135 ]
140136
@@ -149,7 +145,7 @@ def test_pala003_meta_tags_custom(dash_duo, clear_pages_state):
149145 {"property" : "twitter:card" , "content" : "summary_large_image" },
150146 {
151147 "property" : "twitter:url" ,
152- "content" : f"http://localhost: { dash_duo .server . port } /" ,
148+ "content" : f"{ dash_duo .server_url } /" ,
153149 },
154150 {"property" : "twitter:title" , "content" : "Supplied Title" },
155151 {
@@ -158,14 +154,14 @@ def test_pala003_meta_tags_custom(dash_duo, clear_pages_state):
158154 },
159155 {
160156 "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" ,
162158 },
163159 {"property" : "og:title" , "content" : "Supplied Title" },
164160 {"property" : "og:type" , "content" : "website" },
165161 {"property" : "og:description" , "content" : "This is the supplied description" },
166162 {
167163 "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" ,
169165 },
170166 ]
171167
@@ -179,3 +175,63 @@ def test_pala004_no_layout_exception(clear_pages_state):
179175 Dash (__name__ , use_pages = True , pages_folder = "pages_error" )
180176
181177 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