99
1010from __future__ import annotations
1111
12+ import re
1213from collections .abc import Generator
1314
1415import httpx
@@ -107,6 +108,25 @@ def _chunk(chunk_type: bytes, data: bytes) -> bytes:
107108
108109 # ---- Pages ----
109110
111+ def _router_info ():
112+ return rx .fragment (
113+ rx .input (
114+ value = FPState .router .url ,
115+ read_only = True ,
116+ id = "router-url" ,
117+ ),
118+ rx .input (
119+ value = FPState .router .url .path ,
120+ read_only = True ,
121+ id = "router-url-path" ,
122+ ),
123+ rx .input (
124+ value = FPState .router .page .raw_path , # pyright: ignore[reportDeprecated]
125+ read_only = True ,
126+ id = "router-page-raw-path" ,
127+ ),
128+ )
129+
110130 @rx .page ("/" , on_load = FPState .on_load_index )
111131 def index ():
112132 return rx .box (
@@ -117,6 +137,7 @@ def index():
117137 read_only = True ,
118138 id = "token" ,
119139 ),
140+ _router_info (),
120141 # Links to app-relative paths.
121142 rx .link ("go to static" , href = "/static-page" , id = "link-static" ),
122143 rx .link ("go to dynamic 7" , href = "/dynamic/7" , id = "link-dynamic" ),
@@ -169,6 +190,7 @@ def static_page():
169190 read_only = True ,
170191 id = "token" ,
171192 ),
193+ _router_info (),
172194 rx .link ("go home" , href = "/" , id = "link-home" ),
173195 rx .link ("go to dynamic 7" , href = "/dynamic/7" , id = "link-dynamic" ),
174196 rx .box (
@@ -186,6 +208,7 @@ def dynamic_page():
186208 read_only = True ,
187209 id = "token" ,
188210 ),
211+ _router_info (),
189212 rx .link ("go home" , href = "/" , id = "link-home" ),
190213 rx .link ("go to static" , href = "/static-page" , id = "link-static" ),
191214 rx .box (
@@ -458,6 +481,56 @@ def test_navigate_back_and_forth(frontend_path_app: AppHarness, page: Page):
458481 expect (log ).to_contain_text ("dynamic-7" )
459482
460483
484+ def test_router_includes_frontend_path (
485+ frontend_path_app : AppHarness , page : Page , frontend_path : str
486+ ):
487+ """State.router.url and State.router.page expose paths prefixed with frontend_path."""
488+ base = _navigate (frontend_path_app , page )
489+
490+ prefix = "/" + frontend_path .strip ("/" ) if frontend_path else ""
491+
492+ # Index page: in-app path is "/".
493+ expected_path = f"{ prefix } /"
494+ expect (page .locator ("#router-url-path" )).to_have_value (expected_path )
495+ expect (page .locator ("#router-page-raw-path" )).to_have_value (expected_path )
496+ expect (page .locator ("#router-url" )).to_have_value (
497+ re .compile (rf".+{ re .escape (expected_path )} $" )
498+ )
499+ expect (page .locator ("#router-url" )).to_have_value (f"{ base } /" )
500+
501+ # Client-side navigation to static page.
502+ page .click ("#link-static" )
503+ expect (page .locator ("#page-id" )).to_have_text ("static page" )
504+ expected_path = f"{ prefix } /static-page"
505+ expect (page .locator ("#router-url-path" )).to_have_value (expected_path )
506+ expect (page .locator ("#router-page-raw-path" )).to_have_value (expected_path )
507+ expect (page .locator ("#router-url" )).to_have_value (
508+ re .compile (rf".+{ re .escape (expected_path )} $" )
509+ )
510+ expect (page .locator ("#router-url" )).to_have_value (f"{ base } /static-page" )
511+
512+ # Client-side navigation to dynamic page.
513+ page .click ("#link-dynamic" )
514+ expect (page .locator ("#page-id" )).to_contain_text ("dynamic page" )
515+ expected_path = f"{ prefix } /dynamic/7"
516+ expect (page .locator ("#router-url-path" )).to_have_value (expected_path )
517+ expect (page .locator ("#router-page-raw-path" )).to_have_value (expected_path )
518+ expect (page .locator ("#router-url" )).to_have_value (
519+ re .compile (rf".+{ re .escape (expected_path )} $" )
520+ )
521+ expect (page .locator ("#router-url" )).to_have_value (f"{ base } /dynamic/7" )
522+
523+ # Direct (full-page-load) navigation to dynamic page with different id.
524+ _navigate (frontend_path_app , page , "/dynamic/42" )
525+ expected_path = f"{ prefix } /dynamic/42"
526+ expect (page .locator ("#router-url-path" )).to_have_value (expected_path )
527+ expect (page .locator ("#router-page-raw-path" )).to_have_value (expected_path )
528+ expect (page .locator ("#router-url" )).to_have_value (
529+ re .compile (rf".+{ re .escape (expected_path )} $" )
530+ )
531+ expect (page .locator ("#router-url" )).to_have_value (f"{ base } /dynamic/42" )
532+
533+
461534def test_frontend_url_format (frontend_path_app : AppHarness , frontend_path : str ):
462535 """Verify that the frontend_url correctly incorporates the frontend_path."""
463536 url = frontend_path_app .frontend_url
0 commit comments