Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions packages/react-router/tests/loaders.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: () => <Link to="/foo">To foo</Link>,
})
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 <h1>Foo index page</h1>
},
pendingComponent: () => 'loading',
})
const routeTree = rootRoute.addChildren([
indexRoute,
fooRoute
])
const router = createRouter({
routeTree,
history,
defaultPreload: 'intent',
defaultPendingMs: 0,
})

render(<RouterProvider router={router} />)
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)
})
Loading