diff --git a/packages/react-router/tests/errorComponent.test.tsx b/packages/react-router/tests/errorComponent.test.tsx
index 2c0062a9ac..7835ca9e3a 100644
--- a/packages/react-router/tests/errorComponent.test.tsx
+++ b/packages/react-router/tests/errorComponent.test.tsx
@@ -5,6 +5,7 @@ import {
Link,
RouterProvider,
createBrowserHistory,
+ createLazyRoute,
createRootRoute,
createRoute,
createRouter,
@@ -38,110 +39,135 @@ afterEach(() => {
cleanup()
})
-describe.each([{ preload: false }, { preload: 'intent' }] as const)(
- 'errorComponent is rendered when the preload=$preload',
- (options) => {
- describe.each([true, false])('with async=%s', (isAsync) => {
- const throwableFn = isAsync ? asyncToThrowFn : throwFn
-
- const callers = [
- { caller: 'beforeLoad', testFn: throwableFn },
- { caller: 'loader', testFn: throwableFn },
- ]
-
- test.each(callers)(
- 'an Error is thrown on navigate in the route $caller function',
- async ({ caller, testFn }) => {
- const rootRoute = createRootRoute()
- const indexRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/',
- component: function Home() {
- return (
-
- link to about
-
+describe.each([true, false])(
+ 'with lazy errorComponent=%s',
+ (isUsingLazyError) => {
+ describe.each([{ preload: false }, { preload: 'intent' }] as const)(
+ 'errorComponent is rendered when the preload=$preload',
+ (options) => {
+ describe.each([true, false])('with async=%s', (isAsync) => {
+ const throwableFn = isAsync ? asyncToThrowFn : throwFn
+
+ const callers = [
+ { caller: 'beforeLoad', testFn: throwableFn },
+ { caller: 'loader', testFn: throwableFn },
+ ]
+
+ test.each(callers)(
+ 'an Error is thrown on navigate in the route $caller function',
+ async ({ caller, testFn }) => {
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ component: function Home() {
+ return (
+
+ link to about
+
+ )
+ },
+ })
+ const aboutRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/about',
+ beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
+ loader: caller === 'loader' ? testFn : undefined,
+ component: function Home() {
+ return About route content
+ },
+ errorComponent: isUsingLazyError ? undefined : MyErrorComponent,
+ })
+
+ if (isUsingLazyError) {
+ aboutRoute.lazy(() =>
+ Promise.resolve(
+ createLazyRoute('/about')({
+ errorComponent: MyErrorComponent,
+ }),
+ ),
+ )
+ }
+
+ const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
+
+ const router = createRouter({
+ routeTree,
+ defaultPreload: options.preload,
+ history,
+ })
+
+ render()
+
+ const linkToAbout = await screen.findByRole('link', {
+ name: 'link to about',
+ })
+
+ expect(linkToAbout).toBeInTheDocument()
+ fireEvent.mouseOver(linkToAbout)
+ fireEvent.focus(linkToAbout)
+ fireEvent.click(linkToAbout)
+
+ const errorComponent = await screen.findByText(
+ `Error: error thrown`,
+ undefined,
+ { timeout: 1500 },
)
+ await expect(
+ screen.findByText('About route content'),
+ ).rejects.toThrow()
+ expect(errorComponent).toBeInTheDocument()
},
- })
- const aboutRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/about',
- beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
- loader: caller === 'loader' ? testFn : undefined,
- component: function Home() {
- return About route content
- },
- errorComponent: MyErrorComponent,
- })
-
- const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
-
- const router = createRouter({
- routeTree,
- defaultPreload: options.preload,
- history,
- })
-
- render()
-
- const linkToAbout = await screen.findByRole('link', {
- name: 'link to about',
- })
-
- expect(linkToAbout).toBeInTheDocument()
- fireEvent.mouseOver(linkToAbout)
- fireEvent.focus(linkToAbout)
- fireEvent.click(linkToAbout)
-
- const errorComponent = await screen.findByText(
- `Error: error thrown`,
- undefined,
- { timeout: 1500 },
)
- await expect(
- screen.findByText('About route content'),
- ).rejects.toThrow()
- expect(errorComponent).toBeInTheDocument()
- },
- )
-
- test.each(callers)(
- 'an Error is thrown on first load in the route $caller function',
- async ({ caller, testFn }) => {
- const rootRoute = createRootRoute()
- const indexRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/',
- beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
- loader: caller === 'loader' ? testFn : undefined,
- component: function Home() {
- return Index route content
- },
- errorComponent: MyErrorComponent,
- })
-
- const routeTree = rootRoute.addChildren([indexRoute])
-
- const router = createRouter({
- routeTree,
- defaultPreload: options.preload,
- history,
- })
- render()
-
- const errorComponent = await screen.findByText(
- `Error: error thrown`,
- undefined,
- { timeout: 750 },
+ test.each(callers)(
+ 'an Error is thrown on first load in the route $caller function',
+ async ({ caller, testFn }) => {
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
+ loader: caller === 'loader' ? testFn : undefined,
+ component: function Home() {
+ return Index route content
+ },
+ errorComponent: isUsingLazyError ? undefined : MyErrorComponent,
+ })
+
+ if (isUsingLazyError) {
+ indexRoute.lazy(() =>
+ Promise.resolve(
+ createLazyRoute('/')({
+ errorComponent: MyErrorComponent,
+ }),
+ ),
+ )
+ }
+
+ const routeTree = rootRoute.addChildren([indexRoute])
+
+ const router = createRouter({
+ routeTree,
+ defaultPreload: options.preload,
+ history,
+ })
+
+ render()
+
+ const errorComponent = await screen.findByText(
+ `Error: error thrown`,
+ undefined,
+ { timeout: 750 },
+ )
+ await expect(
+ screen.findByText('Index route content'),
+ ).rejects.toThrow()
+ expect(errorComponent).toBeInTheDocument()
+ },
)
- await expect(
- screen.findByText('Index route content'),
- ).rejects.toThrow()
- expect(errorComponent).toBeInTheDocument()
- },
- )
- })
+ })
+ },
+ )
},
)
diff --git a/packages/react-router/tests/store-updates-during-navigation.test.tsx b/packages/react-router/tests/store-updates-during-navigation.test.tsx
index d68373ff4e..f7323a4ce0 100644
--- a/packages/react-router/tests/store-updates-during-navigation.test.tsx
+++ b/packages/react-router/tests/store-updates-during-navigation.test.tsx
@@ -182,7 +182,7 @@ describe("Store doesn't update *too many* times during navigation", () => {
// that needs to be done during a navigation.
// Any change that increases this number should be investigated.
expect(updates).toBeGreaterThanOrEqual(6) // WARN: this is flaky, and sometimes (rarely) is 7
- expect(updates).toBeLessThanOrEqual(7)
+ expect(updates).toBeLessThanOrEqual(8)
})
test('not found in beforeLoad', async () => {
@@ -197,7 +197,7 @@ describe("Store doesn't update *too many* times during navigation", () => {
// This number should be as small as possible to minimize the amount of work
// that needs to be done during a navigation.
// Any change that increases this number should be investigated.
- expect(updates).toBe(7)
+ expect(updates).toBe(8)
})
test('hover preload, then navigate, w/ async loaders', async () => {
diff --git a/packages/router-core/src/load-matches.ts b/packages/router-core/src/load-matches.ts
index 0ea5068ad0..5c943523c0 100644
--- a/packages/router-core/src/load-matches.ts
+++ b/packages/router-core/src/load-matches.ts
@@ -466,13 +466,22 @@ const executeBeforeLoad = (
if (isPromise(beforeLoadContext)) {
pending()
return beforeLoadContext
- .catch((err) => {
+ .catch(async (err) => {
+ if (!isRedirect(err)) {
+ await loadRouteChunk(route)
+ }
handleSerialError(inner, index, err, 'BEFORE_LOAD')
})
.then(updateContext)
}
} catch (err) {
pending()
+ if (!isRedirect(err)) {
+ return loadRouteChunk(route).then(() => {
+ handleSerialError(inner, index, err, 'BEFORE_LOAD')
+ updateContext(undefined)
+ })
+ }
handleSerialError(inner, index, err, 'BEFORE_LOAD')
}
diff --git a/packages/solid-router/tests/errorComponent.test.tsx b/packages/solid-router/tests/errorComponent.test.tsx
index b9ccd941a6..4ee1abf3f1 100644
--- a/packages/solid-router/tests/errorComponent.test.tsx
+++ b/packages/solid-router/tests/errorComponent.test.tsx
@@ -4,6 +4,7 @@ import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library'
import {
Link,
RouterProvider,
+ createLazyRoute,
createRootRoute,
createRoute,
createRouter,
@@ -29,108 +30,133 @@ afterEach(() => {
cleanup()
})
-describe.each([{ preload: false }, { preload: 'intent' }] as const)(
- 'errorComponent is rendered when the preload=$preload',
- (options) => {
- describe.each([true, false])('with async=%s', (isAsync) => {
- const throwableFn = isAsync ? asyncToThrowFn : throwFn
-
- const callers = [
- { caller: 'beforeLoad', testFn: throwableFn },
- { caller: 'loader', testFn: throwableFn },
- ]
-
- test.each(callers)(
- 'an Error is thrown on navigate in the route $caller function',
- async ({ caller, testFn }) => {
- const rootRoute = createRootRoute()
- const indexRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/',
- component: function Home() {
- return (
-
- link to about
-
+describe.each([true, false])(
+ 'with lazy errorComponent=%s',
+ (isUsingLazyError) => {
+ describe.each([{ preload: false }, { preload: 'intent' }] as const)(
+ 'errorComponent is rendered when the preload=$preload',
+ (options) => {
+ describe.each([true, false])('with async=%s', (isAsync) => {
+ const throwableFn = isAsync ? asyncToThrowFn : throwFn
+
+ const callers = [
+ { caller: 'beforeLoad', testFn: throwableFn },
+ { caller: 'loader', testFn: throwableFn },
+ ]
+
+ test.each(callers)(
+ 'an Error is thrown on navigate in the route $caller function',
+ async ({ caller, testFn }) => {
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ component: function Home() {
+ return (
+
+ link to about
+
+ )
+ },
+ })
+ const aboutRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/about',
+ beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
+ loader: caller === 'loader' ? testFn : undefined,
+ component: function Home() {
+ return About route content
+ },
+ errorComponent: isUsingLazyError ? undefined : MyErrorComponent,
+ })
+
+ if (isUsingLazyError) {
+ aboutRoute.lazy(() =>
+ Promise.resolve(
+ createLazyRoute('/about')({
+ errorComponent: MyErrorComponent,
+ }),
+ ),
+ )
+ }
+
+ const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
+
+ const router = createRouter({
+ routeTree,
+ defaultPreload: options.preload,
+ })
+
+ render(() => )
+
+ const linkToAbout = await screen.findByRole('link', {
+ name: 'link to about',
+ })
+
+ expect(linkToAbout).toBeInTheDocument()
+ fireEvent.mouseOver(linkToAbout)
+ fireEvent.focus(linkToAbout)
+ fireEvent.click(linkToAbout)
+
+ const errorComponent = await screen.findByText(
+ `Error: error thrown`,
+ undefined,
+ { timeout: 1500 },
)
+ await expect(
+ screen.findByText('About route content'),
+ ).rejects.toThrow()
+ expect(errorComponent).toBeInTheDocument()
},
- })
- const aboutRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/about',
- beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
- loader: caller === 'loader' ? testFn : undefined,
- component: function Home() {
- return About route content
- },
- errorComponent: MyErrorComponent,
- })
-
- const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
-
- const router = createRouter({
- routeTree,
- defaultPreload: options.preload,
- })
-
- render(() => )
-
- const linkToAbout = await screen.findByRole('link', {
- name: 'link to about',
- })
-
- expect(linkToAbout).toBeInTheDocument()
- fireEvent.mouseOver(linkToAbout)
- fireEvent.focus(linkToAbout)
- fireEvent.click(linkToAbout)
-
- const errorComponent = await screen.findByText(
- `Error: error thrown`,
- undefined,
- { timeout: 1500 },
)
- await expect(
- screen.findByText('About route content'),
- ).rejects.toThrow()
- expect(errorComponent).toBeInTheDocument()
- },
- )
-
- test.each(callers)(
- 'an Error is thrown on first load in the route $caller function',
- async ({ caller, testFn }) => {
- const rootRoute = createRootRoute()
- const indexRoute = createRoute({
- getParentRoute: () => rootRoute,
- path: '/',
- beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
- loader: caller === 'loader' ? testFn : undefined,
- component: function Home() {
- return Index route content
- },
- errorComponent: MyErrorComponent,
- })
-
- const routeTree = rootRoute.addChildren([indexRoute])
-
- const router = createRouter({
- routeTree,
- defaultPreload: options.preload,
- })
- render(() => )
-
- const errorComponent = await screen.findByText(
- `Error: error thrown`,
- undefined,
- { timeout: 750 },
+ test.each(callers)(
+ 'an Error is thrown on first load in the route $caller function',
+ async ({ caller, testFn }) => {
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ beforeLoad: caller === 'beforeLoad' ? testFn : undefined,
+ loader: caller === 'loader' ? testFn : undefined,
+ component: function Home() {
+ return Index route content
+ },
+ errorComponent: isUsingLazyError ? undefined : MyErrorComponent,
+ })
+
+ if (isUsingLazyError) {
+ indexRoute.lazy(() =>
+ Promise.resolve(
+ createLazyRoute('/')({
+ errorComponent: MyErrorComponent,
+ }),
+ ),
+ )
+ }
+
+ const routeTree = rootRoute.addChildren([indexRoute])
+
+ const router = createRouter({
+ routeTree,
+ defaultPreload: options.preload,
+ })
+
+ render(() => )
+
+ const errorComponent = await screen.findByText(
+ `Error: error thrown`,
+ undefined,
+ { timeout: 750 },
+ )
+ await expect(
+ screen.findByText('Index route content'),
+ ).rejects.toThrow()
+ expect(errorComponent).toBeInTheDocument()
+ },
)
- await expect(
- screen.findByText('Index route content'),
- ).rejects.toThrow()
- expect(errorComponent).toBeInTheDocument()
- },
- )
- })
+ })
+ },
+ )
},
)