diff --git a/packages/react-router/tests/loaders.test.tsx b/packages/react-router/tests/loaders.test.tsx
index 7eccb96a13..8f6c63b89b 100644
--- a/packages/react-router/tests/loaders.test.tsx
+++ b/packages/react-router/tests/loaders.test.tsx
@@ -729,3 +729,76 @@ test('clears pendingTimeout when match resolves', async () => {
expect(nestedPendingComponentOnMountMock).not.toHaveBeenCalled()
expect(fooPendingComponentOnMountMock).not.toHaveBeenCalled()
})
+
+
+test('reproducer #4998 - beforeLoad is awaited before rendering', async () => {
+ const beforeLoad = vi.fn()
+ const select = vi.fn()
+ let resolved = 0
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ component: () => To foo,
+ })
+ const fooRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/foo',
+ beforeLoad: async (...args) => {
+ beforeLoad(...args)
+ await new Promise((resolve) => setTimeout(resolve, 20))
+ resolved += 1
+ return { foo: 'bar' }
+ },
+ component: () => {
+ fooRoute.useRouteContext({ select })
+ return
Foo index page
+ },
+ pendingComponent: () => 'loading',
+ })
+ const routeTree = rootRoute.addChildren([
+ indexRoute,
+ fooRoute
+ ])
+ const router = createRouter({
+ routeTree,
+ history,
+ defaultPreload: 'intent',
+ defaultPendingMs: 0,
+ })
+
+ render()
+ const linkToFoo = await screen.findByText('To foo')
+
+ fireEvent.focus(linkToFoo)
+ await sleep(100)
+
+ expect(resolved).toBe(1)
+
+ expect(beforeLoad).toHaveBeenCalledTimes(1)
+ expect(beforeLoad).toHaveBeenNthCalledWith(1, expect.objectContaining({
+ cause: 'preload',
+ preload: true,
+ }))
+
+ expect(select).not.toHaveBeenCalled()
+
+ fireEvent.click(linkToFoo)
+ await screen.findByText('Foo index page')
+
+ expect(beforeLoad).toHaveBeenCalledTimes(2)
+ expect(beforeLoad).toHaveBeenNthCalledWith(2, expect.objectContaining({
+ cause: 'enter',
+ preload: false,
+ }))
+
+ expect(select).toHaveBeenNthCalledWith(1, expect.objectContaining({
+ foo: 'bar',
+ }))
+
+ // I'm not 100% sure this should be 2 here,
+ // maybe we can re-use the cached beforeLoad from preload in some cases
+ // but since we assert a 2nd beforeLoad call above,
+ // then we should have awaited its resolution too
+ expect(resolved).toBe(2)
+})
\ No newline at end of file