I added a search bar using a form and an input to my React app, and I would like to check that it redirects to the right page. I am using react-testing-library and react-router-dom.
Here is my component (simplified):
const SearchBar = () => (
<form action={'/search'}>
<input type="search" name="q" placeholder="search"></input>
</form>
)
So I wrote this test to check that when I type something in the input, I am redirected to the /search page (which happens in my browser). I followed https://testing-library.com/docs/example-react-router/ and came up with this:
it('redirects to search page', async () => {
const history = createMemoryHistory();
const header = render(
<Router history={history}>
<Switch>
<Route exact path="/">
<SearchBar />
</Route>
<Route path="/search">
<div>this is the search page</div>
</Route>
</Switch>
</Router>
);
const searchBar = header.getByPlaceholderText('search');
fireEvent.change(searchBar, { target: { value: 'myQuery' } });
fireEvent.submit(searchBar);
expect(screen.getAllByText('this is the search page')).toBeInTheDocument();
});
Unfortunately it fails with the following error:
TestingLibraryElementError: Unable to find an element with the text: this is the search page. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
<body>
<div>
<form
action="/search"
>
<input
name="q"
placeholder="search"
type="search"
/>
</form>
</div>
</body>
91 | fireEvent.change(searchBar, { target: { value: 'myQuery' } });
92 | fireEvent.submit(searchBar);
> 93 | expect(screen.getAllByText('this is the search page')).toBeInTheDocument();
| ^
94 | });
95 | });
96 |
at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:37:19)
at node_modules/@testing-library/dom/dist/query-helpers.js:92:38
at getAllByText (node_modules/@testing-library/dom/dist/query-helpers.js:127:15)
at Object.<anonymous> (src/components/Header/Header.test.tsx:93:19)
From what I understand, I believe that submitting a form does not change the location of my router.
Is there a way to make the test pass without changing my code? Or should I forget relying on the action
of the form
and instead implement a custom onSubmit
property that handles the redirection - which I could more easily test?
Thanks :)
The form action does not use React Router DOM but instead the native method.
<form action={'/search'}>
If you want to use React Router for this, consider using a React onSubmit
handler. Then your original test should more or less work after integrating with your actual implementation.
const SearchBar = () => {
const history = useHistory();
const handleSubmit = (event) => {
// Prevent default native behavior of submit
event.preventDefault();
// Push the new location to React Router DOM
history.push("/search");
};
return (
<form onSubmit={handleSubmit}>
<input type="search" name="q" placeholder="search"></input>
</form>
);
};
If you are not looking to change the implementation to use the router, I think a good solution would be to test if the action
property is correct and not test native behavior, especially since it's hard to test non-router navigation changes in (example) and form submission isn't fully implemented into JSDOM.
it('has form action for the search page', () => {
const history = createMemoryHistory();
const header = render(
<Router history={history}>
<SearchBar />
</Router>
);
const searchBar = header.getByPlaceholderText('search');
expect(searchBar).toHaveAttribute('action', '/search');
});