diff --git a/packages/react-router/tests/redirect.test.tsx b/packages/react-router/tests/redirect.test.tsx index 3009c9ddd1..d490d08c23 100644 --- a/packages/react-router/tests/redirect.test.tsx +++ b/packages/react-router/tests/redirect.test.tsx @@ -191,6 +191,73 @@ describe('redirect', () => { expect(nestedFooLoaderMock).toHaveBeenCalled() }) + test('when `redirect` is thrown during preload', async () => { + let signedIn = false // Simulate user authentication state + const beforeRedirectMock = vi.fn() + const afterRedirectMock = vi.fn() + + const rootRoute = createRootRoute({}) + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () => { + return ( +
+

Index page

+ link to protected +
+ ) + }, + }) + const protectedRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/protected', + beforeLoad: () => { + beforeRedirectMock() + if (!signedIn) throw redirect({ to: '/login' }) + afterRedirectMock() + }, + component: () =>
Protected page
, + }) + const signInRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/login', + component: () =>
Sign In page
, + }) + const routeTree = rootRoute.addChildren([ + signInRoute, + protectedRoute, + indexRoute, + ]) + const router = createRouter({ + routeTree, + history, + defaultPreload: 'intent', + }) + + render() + + const linkToProtected = await screen.findByText('link to protected') + expect(linkToProtected).toBeInTheDocument() + + // preload + fireEvent.focus(linkToProtected) + await sleep(WAIT_TIME) + + // sign-in + signedIn = true + + // navigate + fireEvent.click(linkToProtected) + + const protectedElement = await screen.findByText('Protected page') + expect(protectedElement).toBeInTheDocument() + expect(router.state.location.href).toBe('/protected') + expect(window.location.pathname).toBe('/protected') + expect(beforeRedirectMock).toHaveBeenCalledTimes(2) + expect(afterRedirectMock).toHaveBeenCalledTimes(1) + }) + test('when `redirect` is thrown in `loader` after `router.invalidate()`', async () => { let shouldRedirect = false diff --git a/packages/router-core/src/router.ts b/packages/router-core/src/router.ts index c4409961b8..8293da6cd2 100644 --- a/packages/router-core/src/router.ts +++ b/packages/router-core/src/router.ts @@ -507,6 +507,7 @@ export type SubscribeFn = ( export interface MatchRoutesOpts { preload?: boolean throwOnError?: boolean + /** @internal */ _buildLocation?: boolean dest?: BuildNextOptions } @@ -909,14 +910,14 @@ export class RouterCore< if (!this.__store) { this.__store = new Store(getInitialRouterState(this.latestLocation), { - onUpdate: () => { - this.__store.state = { - ...this.state, - cachedMatches: this.state.cachedMatches.filter( - (d) => !['redirected'].includes(d.status), - ), - } - }, + // onUpdate: () => { + // this.__store.state = { + // ...this.state, + // cachedMatches: this.state.cachedMatches.filter( + // (d) => !['redirected'].includes(d.status), + // ), + // } + // }, }) setupScrollRestoration(this)