T
TanStack2y ago
like-gold

How to unit test individual components that rely on routerState?

I'm attempting to unit test a component that relies on useMatchRoute. Unfortunately I'm met with
TypeError: Cannot read properties of null (reading '__store')
❯ Module.useRouterState node_modules/@tanstack/react-router/dist/esm/useRouterState.js:9:98
10| useRouterState
11| };
12| //# sourceMappingURL=useRouterState.js.map
| ^
13|
❯ Outlet2 node_modules/@tanstack/react-router/src/Matches.tsx:307:41
TypeError: Cannot read properties of null (reading '__store')
❯ Module.useRouterState node_modules/@tanstack/react-router/dist/esm/useRouterState.js:9:98
10| useRouterState
11| };
12| //# sourceMappingURL=useRouterState.js.map
| ^
13|
❯ Outlet2 node_modules/@tanstack/react-router/src/Matches.tsx:307:41
Typically I would have a general wrapper that includes the Router with Routes, but this approach doesn't exactly work. I've referenced other examples, but that also doesn't work. Having the flexibility to test components as is would be nice without having to mock hooks that react-router provides
Discord
Discord - A New Way to Chat with Friends & Communities
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
7 Replies
deep-jade
deep-jade2y ago
do you know how this works in other router libraries?
like-gold
like-goldOP2y ago
with react-router I've set up a custom render function with a MemoryRouter that wraps around the component I'm testing. e.g.
const renderWithProviders = (
ui,
initialPath = '/',
) => {

const Wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={[initialPath]}>
<Localization>{children}</Localization>
</MemoryRouter>
</QueryClientProvider>
);

return render(ui, { wrapper: Wrapper });
};
const renderWithProviders = (
ui,
initialPath = '/',
) => {

const Wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={[initialPath]}>
<Localization>{children}</Localization>
</MemoryRouter>
</QueryClientProvider>
);

return render(ui, { wrapper: Wrapper });
};
deep-jade
deep-jade2y ago
and can't you do the same with tanstack router? if not, what's missing?
correct-apricot
correct-apricot2y ago
MemoryRouter is missing. And RouterProvider does not take children (Which means using this type of Wrapper won't work). And there isn't an easy way to set an initial path or initial search params.
frail-apricot
frail-apricot2y ago
Thats exactly my problem right now. Im searching a way to get this RouterProvider work within a bun unit test. Can someone help? 🤔
deep-jade
deep-jade2y ago
We do have an equivalent for memory router by the way.
import { createMemoryHistory } from '@tanstack/react-router';

const history = createMemoryHistory({
initialEntries: ['/']
});

const router = createRouter({
routeTree,
history
})
import { createMemoryHistory } from '@tanstack/react-router';

const history = createMemoryHistory({
initialEntries: ['/']
});

const router = createRouter({
routeTree,
history
})
This can be augmented to have a createAppRouter() function which returns the router instance. And during testing, you can inject the memory history instance.
deep-jade
deep-jade2y ago
Its understandable, why you wouldn't have been able to find this in the docs with the search functionality currently in its borked state. https://tanstack.com/router/latest/docs/framework/react/guide/history-types
History Types | TanStack Router Docs
While it's not required to know the @tanstack/history API itself to use TanStack Router, it's a good idea to understand how it works. Under the hood, TanStack Router requires and uses a history abstraction to manage the routing history. If you don't create a history instance, a browser-oriented instance of this API is created for you when the ...

Did you find this page helpful?