-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
test: added (currently failing) unit test to reproduce regression introduced in 1.123.2 #4726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
936b8ae
2fcd4dc
1da38b1
82df257
2667339
6631a00
e7b3dd3
35c6f86
15dcce3
d9b8213
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -16,6 +16,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||
Outlet, | ||||||||||||||||||||||||||||||||||||||||||||||
RouterProvider, | ||||||||||||||||||||||||||||||||||||||||||||||
createBrowserHistory, | ||||||||||||||||||||||||||||||||||||||||||||||
createMemoryHistory, | ||||||||||||||||||||||||||||||||||||||||||||||
createRootRoute, | ||||||||||||||||||||||||||||||||||||||||||||||
createRoute, | ||||||||||||||||||||||||||||||||||||||||||||||
createRouter, | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -729,3 +730,87 @@ test('clears pendingTimeout when match resolves', async () => { | |||||||||||||||||||||||||||||||||||||||||||||
expect(nestedPendingComponentOnMountMock).not.toHaveBeenCalled() | ||||||||||||||||||||||||||||||||||||||||||||||
expect(fooPendingComponentOnMountMock).not.toHaveBeenCalled() | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
test('reproducer for #4696', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
const rootRoute = createRootRoute({ | ||||||||||||||||||||||||||||||||||||||||||||||
beforeLoad: async ({ context }) => { | ||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||
...context, | ||||||||||||||||||||||||||||||||||||||||||||||
isAuthenticated: true, | ||||||||||||||||||||||||||||||||||||||||||||||
isAdmin: false, | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||
loader: ({ context }) => context, | ||||||||||||||||||||||||||||||||||||||||||||||
pendingComponent: () => 'Loading...', | ||||||||||||||||||||||||||||||||||||||||||||||
wrapInSuspense: true, | ||||||||||||||||||||||||||||||||||||||||||||||
component: RootRouteContent, | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
function RootRouteContent() { | ||||||||||||||||||||||||||||||||||||||||||||||
const routeData = rootRoute.useLoaderData() | ||||||||||||||||||||||||||||||||||||||||||||||
const isAuthenticated = routeData.isAuthenticated | ||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||
<> | ||||||||||||||||||||||||||||||||||||||||||||||
{!!isAuthenticated && ( | ||||||||||||||||||||||||||||||||||||||||||||||
<nav data-testid="nav" style={{ display: 'flex', gap: 8 }}> | ||||||||||||||||||||||||||||||||||||||||||||||
<Link data-testid="link-index" to="/"> | ||||||||||||||||||||||||||||||||||||||||||||||
Index | ||||||||||||||||||||||||||||||||||||||||||||||
</Link> | ||||||||||||||||||||||||||||||||||||||||||||||
<Link data-testid="link-dashboard" to="/dashboard"> | ||||||||||||||||||||||||||||||||||||||||||||||
Dashboard | ||||||||||||||||||||||||||||||||||||||||||||||
</Link> | ||||||||||||||||||||||||||||||||||||||||||||||
</nav> | ||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||
<hr /> | ||||||||||||||||||||||||||||||||||||||||||||||
<Outlet /> | ||||||||||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const indexRoute = createRoute({ | ||||||||||||||||||||||||||||||||||||||||||||||
getParentRoute: () => rootRoute, | ||||||||||||||||||||||||||||||||||||||||||||||
path: '/', | ||||||||||||||||||||||||||||||||||||||||||||||
component: () => <h1 data-testid="heading-index">Index</h1>, | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const dashboardRoute = createRoute({ | ||||||||||||||||||||||||||||||||||||||||||||||
getParentRoute: () => rootRoute, | ||||||||||||||||||||||||||||||||||||||||||||||
path: '/dashboard', | ||||||||||||||||||||||||||||||||||||||||||||||
pendingComponent: () => 'Loading dashboard...', | ||||||||||||||||||||||||||||||||||||||||||||||
validateSearch: () => { | ||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||
page: 0, | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||
component: () => <h1 data-testid="heading-dashboard">Dashboard</h1>, | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const routeTree = rootRoute.addChildren([indexRoute, dashboardRoute]) | ||||||||||||||||||||||||||||||||||||||||||||||
const router = createRouter({ routeTree }) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
render(<RouterProvider router={router} />) | ||||||||||||||||||||||||||||||||||||||||||||||
await act(async () => {}) | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('heading-index')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('nav')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
cleanup() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const historyWithSearchParam = createMemoryHistory({ | ||||||||||||||||||||||||||||||||||||||||||||||
initialEntries: ['/dashboard?page=0'], | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
render(<RouterProvider history={historyWithSearchParam} router={router} />) | ||||||||||||||||||||||||||||||||||||||||||||||
await act(async () => {}) | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('heading-dashboard')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('nav')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
cleanup() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const historyWithoutSearchParam = createMemoryHistory({ | ||||||||||||||||||||||||||||||||||||||||||||||
initialEntries: ['/dashboard'], | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
render(<RouterProvider history={historyWithoutSearchParam} router={router} />) | ||||||||||||||||||||||||||||||||||||||||||||||
await act(async () => {}) | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('heading-dashboard')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
// Fails here! | ||||||||||||||||||||||||||||||||||||||||||||||
expect(screen.getByTestId('nav')).toBeInTheDocument() | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+806
to
+816
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Apply the same fix for the no-search-param case. Create a third router with - const historyWithoutSearchParam = createMemoryHistory({
- initialEntries: ['/dashboard'],
- })
- render(<RouterProvider history={historyWithoutSearchParam} router={router} />)
- await act(async () => {})
- expect(screen.getByTestId('heading-dashboard')).toBeInTheDocument()
- // Fails here!
- expect(screen.getByTestId('nav')).toBeInTheDocument()
+ const router3 = createRouter({
+ routeTree,
+ history: createMemoryHistory({ initialEntries: ['/dashboard'] }),
+ })
+ render(<RouterProvider router={router3} />)
+ await act(() => router3.latestLoadPromise)
+ expect(await screen.findByTestId('heading-dashboard')).toBeInTheDocument()
+ expect(await screen.findByTestId('nav')).toBeInTheDocument() 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Don’t reuse the same router while swapping histories via
RouterProvider
; create a new router per history.Passing
history
intoRouterProvider
while keeping the samerouter
instance can desynchronize the router’s internal history from the Provider and cause loaders/Suspense not to resolve as expected. Build a fresh router with the target memory history for each scenario and awaitlatestLoadPromise
.📝 Committable suggestion
🤖 Prompt for AI Agents