@@ -1366,6 +1366,220 @@ test('<Navigate> navigates only once in <StrictMode>', async () => {
1366
1366
expect ( navigateSpy . mock . calls . length ) . toBe ( 1 )
1367
1367
} )
1368
1368
1369
+ test ( 'should navigate to current route with search params when using "." in nested route structure' , async ( ) => {
1370
+ const rootRoute = createRootRoute ( )
1371
+
1372
+ const IndexComponent = ( ) => {
1373
+ const navigate = useNavigate ( )
1374
+ return (
1375
+ < >
1376
+ < button
1377
+ data-testid = "posts-btn"
1378
+ onClick = { ( ) => {
1379
+ navigate ( {
1380
+ to : '/post' ,
1381
+ } )
1382
+ } }
1383
+ >
1384
+ Post
1385
+ </ button >
1386
+ < button
1387
+ data-testid = "search-btn"
1388
+ onClick = { ( ) =>
1389
+ navigate ( {
1390
+ to : '.' ,
1391
+ search : {
1392
+ param1 : 'value1' ,
1393
+ } ,
1394
+ } )
1395
+ }
1396
+ >
1397
+ Search
1398
+ </ button >
1399
+ < button
1400
+ data-testid = "search2-btn"
1401
+ onClick = { ( ) =>
1402
+ navigate ( {
1403
+ to : '/post' ,
1404
+ search : {
1405
+ param1 : 'value2' ,
1406
+ } ,
1407
+ } )
1408
+ }
1409
+ >
1410
+ Search2
1411
+ </ button >
1412
+ < Outlet />
1413
+ </ >
1414
+ )
1415
+ }
1416
+
1417
+ const indexRoute = createRoute ( {
1418
+ getParentRoute : ( ) => rootRoute ,
1419
+ path : '/' ,
1420
+ component : IndexComponent ,
1421
+ validateSearch : z . object ( {
1422
+ param1 : z . string ( ) . optional ( ) ,
1423
+ } ) ,
1424
+ } )
1425
+
1426
+ const postRoute = createRoute ( {
1427
+ getParentRoute : ( ) => indexRoute ,
1428
+ path : 'post' ,
1429
+ component : ( ) => < div > Post</ div > ,
1430
+ } )
1431
+
1432
+ const router = createRouter ( {
1433
+ routeTree : rootRoute . addChildren ( [ indexRoute , postRoute ] ) ,
1434
+ history,
1435
+ } )
1436
+
1437
+ render ( < RouterProvider router = { router } /> )
1438
+
1439
+ const postButton = await screen . findByTestId ( 'posts-btn' )
1440
+
1441
+ fireEvent . click ( postButton )
1442
+
1443
+ expect ( router . state . location . pathname ) . toBe ( '/post' )
1444
+
1445
+ const searchButton = await screen . findByTestId ( 'search-btn' )
1446
+
1447
+ fireEvent . click ( searchButton )
1448
+
1449
+ expect ( router . state . location . pathname ) . toBe ( '/post' )
1450
+ expect ( router . state . location . search ) . toEqual ( { param1 : 'value1' } )
1451
+
1452
+ const searchButton2 = await screen . findByTestId ( 'search2-btn' )
1453
+
1454
+ fireEvent . click ( searchButton2 )
1455
+
1456
+ expect ( router . state . location . pathname ) . toBe ( '/post' )
1457
+ expect ( router . state . location . search ) . toEqual ( { param1 : 'value2' } )
1458
+ } )
1459
+
1460
+ test ( 'should navigate to current route with changing path params when using "." in nested route structure' , async ( ) => {
1461
+ const rootRoute = createRootRoute ( )
1462
+
1463
+ const IndexComponent = ( ) => {
1464
+ const navigate = useNavigate ( )
1465
+ return (
1466
+ < >
1467
+ < h1 data-testid = "index-heading" > Index</ h1 >
1468
+ < button
1469
+ data-testid = "posts-btn"
1470
+ onClick = { ( ) => navigate ( { to : '/posts' } ) }
1471
+ >
1472
+ Posts
1473
+ </ button >
1474
+ </ >
1475
+ )
1476
+ }
1477
+
1478
+ const indexRoute = createRoute ( {
1479
+ getParentRoute : ( ) => rootRoute ,
1480
+ path : '/' ,
1481
+ component : IndexComponent ,
1482
+ } )
1483
+
1484
+ const layoutRoute = createRoute ( {
1485
+ getParentRoute : ( ) => rootRoute ,
1486
+ id : '_layout' ,
1487
+ component : ( ) => {
1488
+ return (
1489
+ < >
1490
+ < h1 > Layout</ h1 >
1491
+ < Outlet />
1492
+ </ >
1493
+ )
1494
+ } ,
1495
+ } )
1496
+
1497
+ const PostsComponent = ( ) => {
1498
+ const navigate = postsRoute . useNavigate ( )
1499
+ return (
1500
+ < >
1501
+ < h1 data-testid = "posts-index-heading" > Posts</ h1 >
1502
+ < button
1503
+ data-testid = "first-post-btn"
1504
+ onClick = { ( ) =>
1505
+ navigate ( {
1506
+ to : '$postId' ,
1507
+ params : { postId : 'id1' } ,
1508
+ } )
1509
+ }
1510
+ >
1511
+ To first post
1512
+ </ button >
1513
+ < button
1514
+ data-testid = "second-post-btn"
1515
+ onClick = { ( ) =>
1516
+ navigate ( {
1517
+ to : '.' ,
1518
+ params : { postId : 'id2' } ,
1519
+ } )
1520
+ }
1521
+ >
1522
+ To second post
1523
+ </ button >
1524
+ < Outlet />
1525
+ </ >
1526
+ )
1527
+ }
1528
+
1529
+ const postsRoute = createRoute ( {
1530
+ getParentRoute : ( ) => layoutRoute ,
1531
+ path : 'posts' ,
1532
+ component : PostsComponent ,
1533
+ } )
1534
+
1535
+ const PostComponent = ( ) => {
1536
+ const params = useParams ( { strict : false } )
1537
+ return (
1538
+ < >
1539
+ < span data-testid = { `post-${ params . postId } ` } >
1540
+ Params: { params . postId }
1541
+ </ span >
1542
+ </ >
1543
+ )
1544
+ }
1545
+
1546
+ const postRoute = createRoute ( {
1547
+ getParentRoute : ( ) => postsRoute ,
1548
+ path : '$postId' ,
1549
+ component : PostComponent ,
1550
+ } )
1551
+
1552
+ const router = createRouter ( {
1553
+ routeTree : rootRoute . addChildren ( [
1554
+ indexRoute ,
1555
+ layoutRoute . addChildren ( [ postsRoute . addChildren ( [ postRoute ] ) ] ) ,
1556
+ ] ) ,
1557
+ } )
1558
+
1559
+ render ( < RouterProvider router = { router } /> )
1560
+
1561
+ const postsButton = await screen . findByTestId ( 'posts-btn' )
1562
+
1563
+ fireEvent . click ( postsButton )
1564
+
1565
+ expect ( await screen . findByTestId ( 'posts-index-heading' ) ) . toBeInTheDocument ( )
1566
+ expect ( window . location . pathname ) . toEqual ( '/posts' )
1567
+
1568
+ const firstPostButton = await screen . findByTestId ( 'first-post-btn' )
1569
+
1570
+ fireEvent . click ( firstPostButton )
1571
+
1572
+ expect ( await screen . findByTestId ( 'post-id1' ) ) . toBeInTheDocument ( )
1573
+ expect ( window . location . pathname ) . toEqual ( '/posts/id1' )
1574
+
1575
+ const secondPostButton = await screen . findByTestId ( 'second-post-btn' )
1576
+
1577
+ fireEvent . click ( secondPostButton )
1578
+
1579
+ expect ( await screen . findByTestId ( 'post-id2' ) ) . toBeInTheDocument ( )
1580
+ expect ( window . location . pathname ) . toEqual ( '/posts/id2' )
1581
+ } )
1582
+
1369
1583
describe ( 'when on /posts/$postId and navigating to ../ with default `from` /posts' , ( ) => {
1370
1584
async function runTest ( navigateVia : 'Route' | 'RouteApi' ) {
1371
1585
const rootRoute = createRootRoute ( )
0 commit comments