11import {
2+ act ,
23 cleanup ,
34 configure ,
45 fireEvent ,
@@ -17,6 +18,7 @@ import {
1718 createRootRoute ,
1819 createRoute ,
1920 createRouter ,
21+ useRouter ,
2022} from '../src'
2123
2224import { sleep } from './utils'
@@ -380,7 +382,7 @@ test('reproducer #4245', async () => {
380382
381383 render ( < RouterProvider router = { router } /> )
382384 // We wait for the initial loader to complete
383- await router . load ( )
385+ await act ( ( ) => router . load ( ) )
384386 const fooLink = await screen . findByTestId ( 'link-to-foo' )
385387
386388 expect ( fooLink ) . toBeInTheDocument ( )
@@ -389,27 +391,257 @@ test('reproducer #4245', async () => {
389391 fireEvent . click ( fooLink )
390392
391393 // We immediately see the content of the foo route
392- const indexLink = await screen . findByTestId ( 'link-to-index' )
394+ const indexLink = await screen . findByTestId ( 'link-to-index' , undefined , {
395+ timeout : WAIT_TIME ,
396+ } )
393397 expect ( indexLink ) . toBeInTheDocument ( )
394398
395399 // We navigate to the index route
396400 fireEvent . click ( indexLink )
397401
398402 // We immediately see the content of the index route because the stale data is still available
399- const fooLink2 = await screen . findByTestId ( 'link-to-foo' )
403+ const fooLink2 = await screen . findByTestId ( 'link-to-foo' , undefined , {
404+ timeout : WAIT_TIME ,
405+ } )
400406 expect ( fooLink2 ) . toBeInTheDocument ( )
401407
402408 // We navigate to the foo route again
403409 fireEvent . click ( fooLink2 )
404410
405411 // We immediately see the content of the foo route
406- const indexLink2 = await screen . findByTestId ( 'link-to-index' )
412+ const indexLink2 = await screen . findByTestId ( 'link-to-index' , undefined , {
413+ timeout : WAIT_TIME ,
414+ } )
407415 expect ( indexLink2 ) . toBeInTheDocument ( )
408416
409417 // We navigate to the index route again
410418 fireEvent . click ( indexLink2 )
411419
412420 // We now should see the content of the index route immediately because the stale data is still available
413- const fooLink3 = await screen . findByTestId ( 'link-to-foo' )
421+ const fooLink3 = await screen . findByTestId ( 'link-to-foo' , undefined , {
422+ timeout : WAIT_TIME ,
423+ } )
414424 expect ( fooLink3 ) . toBeInTheDocument ( )
415425} )
426+
427+ test ( 'reproducer #4546' , async ( ) => {
428+ const rootRoute = createRootRoute ( {
429+ component : ( ) => {
430+ return (
431+ < >
432+ < div className = "p-2 flex gap-2 text-lg" >
433+ < Link
434+ data-testid = "link-to-index"
435+ to = "/"
436+ activeProps = { {
437+ className : 'font-bold' ,
438+ } }
439+ activeOptions = { { exact : true } }
440+ >
441+ Home
442+ </ Link > { ' ' }
443+ < Link
444+ data-testid = "link-to-id"
445+ to = "$id"
446+ params = { {
447+ id : '1' ,
448+ } }
449+ activeProps = { {
450+ className : 'font-bold' ,
451+ } }
452+ >
453+ /1
454+ </ Link >
455+ </ div >
456+ < hr />
457+ < Outlet />
458+ </ >
459+ )
460+ } ,
461+ } )
462+
463+ let counter = 0
464+ const appRoute = createRoute ( {
465+ getParentRoute : ( ) => rootRoute ,
466+ id : '_app' ,
467+ beforeLoad : ( ) => {
468+ counter += 1
469+ return {
470+ counter,
471+ }
472+ } ,
473+ component : ( ) => {
474+ return (
475+ < div >
476+ < Header />
477+ < Outlet />
478+ </ div >
479+ )
480+ } ,
481+ } )
482+
483+ function Header ( ) {
484+ const router = useRouter ( )
485+ const { counter } = appRoute . useRouteContext ( )
486+
487+ return (
488+ < div >
489+ Header Counter: < p data-testid = "header-counter" > { counter } </ p >
490+ < button
491+ onClick = { ( ) => {
492+ router . invalidate ( )
493+ } }
494+ data-testid = "invalidate-router"
495+ style = { {
496+ border : '1px solid blue' ,
497+ } }
498+ >
499+ Invalidate router
500+ </ button >
501+ </ div >
502+ )
503+ }
504+
505+ const indexRoute = createRoute ( {
506+ getParentRoute : ( ) => appRoute ,
507+ path : '/' ,
508+ loader : ( { context } ) => {
509+ return {
510+ counter : context . counter ,
511+ }
512+ } ,
513+
514+ component : ( ) => {
515+ const data = indexRoute . useLoaderData ( )
516+ const ctx = indexRoute . useRouteContext ( )
517+
518+ return (
519+ < div
520+ style = { {
521+ display : 'flex' ,
522+ flexDirection : 'column' ,
523+ } }
524+ >
525+ < div > Index route</ div >
526+ < div >
527+ route context:{ ' ' }
528+ < p data-testid = "index-route-context" > { ctx . counter } </ p >
529+ </ div >
530+ < div >
531+ loader data: < p data-testid = "index-loader-data" > { data . counter } </ p >
532+ </ div >
533+ </ div >
534+ )
535+ } ,
536+ } )
537+ const idRoute = createRoute ( {
538+ getParentRoute : ( ) => appRoute ,
539+ path : '$id' ,
540+ loader : ( { context } ) => {
541+ return {
542+ counter : context . counter ,
543+ }
544+ } ,
545+
546+ component : ( ) => {
547+ const data = idRoute . useLoaderData ( )
548+ const ctx = idRoute . useRouteContext ( )
549+
550+ return (
551+ < div
552+ style = { {
553+ display : 'flex' ,
554+ flexDirection : 'column' ,
555+ } }
556+ >
557+ < div > $id route</ div >
558+ < div >
559+ route context: < p data-testid = "id-route-context" > { ctx . counter } </ p >
560+ </ div >
561+ < div >
562+ loader data: < p data-testid = "id-loader-data" > { data . counter } </ p >
563+ </ div >
564+ </ div >
565+ )
566+ } ,
567+ } )
568+
569+ const routeTree = rootRoute . addChildren ( [
570+ appRoute . addChildren ( [ indexRoute , idRoute ] ) ,
571+ ] )
572+ const router = createRouter ( { routeTree } )
573+
574+ render ( < RouterProvider router = { router } /> )
575+
576+ const indexLink = await screen . findByTestId ( 'link-to-index' )
577+ expect ( indexLink ) . toBeInTheDocument ( )
578+
579+ const idLink = await screen . findByTestId ( 'link-to-id' )
580+ expect ( idLink ) . toBeInTheDocument ( )
581+
582+ const invalidateRouterButton = await screen . findByTestId ( 'invalidate-router' )
583+ expect ( invalidateRouterButton ) . toBeInTheDocument ( )
584+
585+ {
586+ const headerCounter = await screen . findByTestId ( 'header-counter' )
587+ expect ( headerCounter ) . toHaveTextContent ( '1' )
588+
589+ const routeContext = await screen . findByTestId ( 'index-route-context' )
590+ expect ( routeContext ) . toHaveTextContent ( '1' )
591+
592+ const loaderData = await screen . findByTestId ( 'index-loader-data' )
593+ expect ( loaderData ) . toHaveTextContent ( '1' )
594+ }
595+
596+ fireEvent . click ( idLink )
597+
598+ {
599+ const headerCounter = await screen . findByTestId ( 'header-counter' )
600+ expect ( headerCounter ) . toHaveTextContent ( '2' )
601+
602+ const routeContext = await screen . findByTestId ( 'id-route-context' )
603+ expect ( routeContext ) . toHaveTextContent ( '2' )
604+
605+ const loaderData = await screen . findByTestId ( 'id-loader-data' )
606+ expect ( loaderData ) . toHaveTextContent ( '2' )
607+ }
608+
609+ fireEvent . click ( indexLink )
610+
611+ {
612+ const headerCounter = await screen . findByTestId ( 'header-counter' )
613+ expect ( headerCounter ) . toHaveTextContent ( '3' )
614+
615+ const routeContext = await screen . findByTestId ( 'index-route-context' )
616+ expect ( routeContext ) . toHaveTextContent ( '3' )
617+
618+ const loaderData = await screen . findByTestId ( 'index-loader-data' )
619+ expect ( loaderData ) . toHaveTextContent ( '3' )
620+ }
621+
622+ fireEvent . click ( invalidateRouterButton )
623+
624+ {
625+ const headerCounter = await screen . findByTestId ( 'header-counter' )
626+ expect ( headerCounter ) . toHaveTextContent ( '4' )
627+
628+ const routeContext = await screen . findByTestId ( 'index-route-context' )
629+ expect ( routeContext ) . toHaveTextContent ( '4' )
630+
631+ const loaderData = await screen . findByTestId ( 'index-loader-data' )
632+ expect ( loaderData ) . toHaveTextContent ( '4' )
633+ }
634+
635+ fireEvent . click ( idLink )
636+
637+ {
638+ const headerCounter = await screen . findByTestId ( 'header-counter' )
639+ expect ( headerCounter ) . toHaveTextContent ( '5' )
640+
641+ const routeContext = await screen . findByTestId ( 'id-route-context' )
642+ expect ( routeContext ) . toHaveTextContent ( '5' )
643+
644+ const loaderData = await screen . findByTestId ( 'id-loader-data' )
645+ expect ( loaderData ) . toHaveTextContent ( '5' )
646+ }
647+ } )
0 commit comments