Background
In the react channel on Spectrum, someone asked how to test that a component displayed data provided by location.state
from react-router-dom
. I had never done this before, so I sought to find out how to do it.
After some investigation, and trial and error, I came up with the following...
import * as React from "react";
import { render } from "@testing-library/react";
import { Router } from "react-router-dom";
import { createMemoryHistory } from "history";
import { App } from "./App";
it("renders location state", () => {
const history = createMemoryHistory();
const state = { a: 123, b: 456 }
history.push("/", state);
const { getByText } = render(
<Router history={history}>
<App />
</Router>
);
getByText(state.a);
getByText(state.b);
});
Other Interesting Tidbits
<MemoryRouter history={createMemoryHistory(...)}>
doesn't work<BrowserRouter history={createBrowserHistory(...)}>
does work, but doesn't typecheckAccording to the docs
Note: Location state is only supported in createBrowserHistory and createMemoryHistory.
location.state - Some extra state for this location that does not reside in the URL (supported in createBrowserHistory and createMemoryHistory)
Conclusion
So, this seems to work. It passes the tests.
Know of a better way? See any problems? Let me know, thanks.
Top comments (3)
That sort of worked for me, but I still had code in my component that was throwing an error "cannot access property .state of null value", in this case the null value was
location
.I did come up with a solution, which is to first grab the history of the component I'm rendering to test and then
rerender
that component with alocation
prop equal tohistory.location
. Looking like:That way, my code in the
<Component/>
that callsthis.props.location.state
doesn't fail.Sidenote:
renderWithRouter
is a utility function I built that uses similar logic to what you have above and returnshistory
along with...render(<Component />
Thanks for the post!
A heads up: eslint will throw
Don't do it - stackoverflow.com/a/66787971/863110.
How to solve this beside make eslint ignoring the line? I have no idea 😕
That worked perfectly for me! Thanks for the writeup!