How to make a unit testing helper?
I'm trying to come up with a reusable unit testing helper that wraps components in the necessary RouteTree + QueryClientProvider. However I'm finding that hooks like
useParams are not returning expected results, so I can tell I'm not getting it totally right.
The issue seems to be that the params object is returning a key of ** instead of workflowId, although the value for the param is actually right.
I've created a basic reproduction in StackBlitz @ https://stackblitz.com/edit/vitejs-vite-5wm5gn?file=src%2FWorkflows.spec.tsx. You can run the tests via npm run test in the terminal.
For those who dont want to check out the stackblitz, I'm using a test helper which is almost a direct copy-paste of one shared previously in this Discord @ https://discord.com/channels/719702312431386674/1235917869620133938/1236040157506043954 . I'll put the code in the comment below this one due to Discord character limits.
In general, if someone has a viable render setup that works for unit testing components and enabling all the TSR hooks I'd love to see how you're solving that. All of the example tests I found in the TSR GitHub (eg https://github.com/TanStack/router/blob/main/packages/react-router/tests/link.test.tsx#L840) involve manually creating a route tree for each test, which seems like a sizable amount of boilerplate for devs to write in every test file
12 Replies
foreign-sapphireOP•2y ago
helper code:
rare-sapphire•2y ago
Looking at your helper, you aren't taking the returned route-tree from
root.addChildren()
A typical router definition looks like this.
Your route-tree is the returned value of rootRoute.addChildren.
You may want to first get your helper working in a way that you are generating your route-tree the correct way.foreign-sapphireOP•2y ago
Hey @Sean Cassiere , thanks for looking at this on a Sunday.
If Im understanding you right, the only change necessary here is captured in this git diff (Ive also updated the original StackBlitz with the change). Even with this change, I still see the same issue with
params from useParams in my component logging as {"**": "4"}
Im also reviewing the createChildRoute helper to see if I have any obvious problems there since its mostly copy-pasted from the previous Discord post about this topic. Havent found any obvious issue yet, but Im also not experienced enough with TSR to be sure
rare-sapphire•2y ago
If I'm not mistaken
** identifier is a possible splat which means you don't have a route that's configured for the useParams caller.
Also, the let value should be let routeTree = root.addChildren([])foreign-sapphireOP•2y ago
It looks like that might be a factor here, but I'd be confused why its showing as no route being configured for the component invoking
useParams . I wonder if maybe the createChildRoute helper needs to include something like component: ({children}) => <div>{children}</div> for all of the fake parent paths other than the final path that is meant to render the component being tested.
Let me try that out in the stackblitzrare-sapphire•2y ago
Oh I also noticed that your rootRoute doesn't ever render the
<Outlet /> componentforeign-sapphireOP•2y ago
Yeah I was thinking thatd be a problem as well when I was reading the other person's original version of this code. Im working on a local refactor to use the
Outlet and update the createChildRoute helper to hopefully make that work as expected. Will update the stackblitz + this thread when Ive got that knocked outrare-sapphire•2y ago
Cool stuff, best of luck
I played around with this and found out that happy-dom was being abit wonky. Using jsdom worked.
You may want to try substituting it and giving your original example a shot.
rare-sapphire•2y ago
I only found out the happy-dom thing later on though. I've used a bit of recursion and got this working. I haven't implemented layout routes, but currently that "Workflow ID is 4" test does pass.
https://github.com/SeanCassiere/super-duper-octo-barnacle/blob/master/src/renderWithTanstack.tsx
GitHub
super-duper-octo-barnacle/src/renderWithTanstack.tsx at master · Se...
Contribute to SeanCassiere/super-duper-octo-barnacle development by creating an account on GitHub.
rare-sapphire•2y ago
Nvm, i got layout routes also working
foreign-sapphireOP•2y ago
You're a real one Sean, just sent you a small donation on GH for your help 🫡 I did wind up making a few small tweaks and it seemed to work fine with happy-dom.
Not really sure whether jsdom would make a meaningful difference, but all I changed was adding an
await router.load() before invoking the return render(<RouterProvider router={router} />) because I was seeing a React error in the console about a state update not being wrapped in act.
This did require adding an act and await in the test itself, but this seemed to be necessary to remove the warning. Its possible theres a better solution here and I just didnt dig deep enough.
---
Unrelated to my original post since your solution seems to work fine for everything Ive tested so far, but would it make sense for the Tanstack team to add something like your helper into the Guides (similar to what Redux has https://redux.js.org/usage/writing-tests#setting-up-a-reusable-test-render-function) or create a dedicated package for it (similar to the Remix testing package https://remix.run/docs/en/main/other-api/testing )?
When I was initially diving into this testing work I spent a decent amount of time reading through the docs, github issues, and the discord history to try and find a reusable solution but was surprised that there wasn't really any official solution. I know integration/e2e testing in a browser is usually preferable, but unit testing w/ Vite or Jest definitely has its place and it seems like a recommended solution would help the communityrare-sapphire•2y ago
Thanks!
The issue would be the type-safety sides of things. Plus having to worry about jest vs vitest vs chai vs etc... for the time being I don't think we'll be adding it, but I'll link others to this when they ask