After a lot of trial and error I cannot get RTL to render any components from react-router-dom. I am using [email protected], @testing-library/[email protected], @testing-library/[email protected], [email protected] and [email protected] (which I have tried upgrading but cannot get my dom to unstick from the [email protected] inbuilt [email protected] even with a number of workaround attempts in setup files).
As far as I can see online these versions should be compatible but I am not even able to render a link component in a test without this error (below). The same error comes up for any other react-router-dom component that I have tried (BrowserRouter and MemoryRouter). The same error appears when trying to import the components from react-router.
The original component I was trying to render (which works when rendering normally i.e. non testing env) =>
import {BrowserRouter, Routes, Route, Link } from "react-router-dom";
import NavBar from './components/NavBar';
import Home from "./Pages/Home.jsx";
// ^ I left these in to show the context of my own use but you can comment these
// out and put a div in the browser router or leave it empty. I won't be able to
// add these files in this post.
function App() {
return (
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
export default App;
The App itself is rendered within standard index.js =>
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
The test I originally wanted =>
import { render } from '@testing-library/react';
import App from './App';
import React from "react";
import { BrowserRouter, MemoryRouter, Link } from 'react-router-dom';
test('renders App', () => {
render(<App />); // it fails on this line
expect(<App />).toBeDefined();
});
The minimal tests for narrowing down the problem source =>
import { render } from '@testing-library/react';
import App from './App';
import React from "react";
import { BrowserRouter, MemoryRouter, Link } from 'react-router-dom';
test('renders BrowserRouter', () => {
render(<BrowserRouter />);
});
test('renders MemoryRouter', () => {
render(<MemoryRouter />);
});
// in a function to re-create the context
function TestComponent() {
return <BrowserRouter></BrowserRouter>;
}
test('renders TestComponent', () => {
const { container } = render(<TestComponent />); // also failing on this line
expect(container).toBeDefined();
});
All these tests have the same error type:
output:
console.error
Error: Uncaught [TypeError: Cannot read properties of null (reading 'useRef')]
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See for tips about how to debug and fix this problem.
console.error
The above error occurred in the <BrowserRouter> component:
at fn (/.../packages/react-router-dom/index.tsx:136:3)
The react-router-dom elements never cause any such problems when I run the application outside testing environment so I suspect there is some issue with jest but I have exhausted everything I/internet research could think to try so I'm really hoping anyone can help! If anyone has seen this issue or knows anything about it please let me know.
For more context, these errors do not appear when rendering non-react-router-dom components with hooks in them!
Steps to recreate: Install the same package versions and create the example test above.
What did I try: Tried ensuring no version mismatch, upgrading many packages (to the ones above), adding various settings to package.json to try to use upgraded version of jsdom including trying to explicitly set it as global dom in setupTests.js which did not work..., setting TextEncoders and TextDecoders, and rendering many different variants (React.StrictMode wrapped, using ReactDOM root rendering, putting it inside container, importing from react-router instead of react-router-dom) to see if it was anything in my set up.
After a lot of trial and error I cannot get RTL to render any components from react-router-dom. I am using [email protected], @testing-library/[email protected], @testing-library/[email protected], [email protected] and [email protected] (which I have tried upgrading but cannot get my dom to unstick from the [email protected] inbuilt [email protected] even with a number of workaround attempts in setup files).
As far as I can see online these versions should be compatible but I am not even able to render a link component in a test without this error (below). The same error comes up for any other react-router-dom component that I have tried (BrowserRouter and MemoryRouter). The same error appears when trying to import the components from react-router.
The original component I was trying to render (which works when rendering normally i.e. non testing env) =>
import {BrowserRouter, Routes, Route, Link } from "react-router-dom";
import NavBar from './components/NavBar';
import Home from "./Pages/Home.jsx";
// ^ I left these in to show the context of my own use but you can comment these
// out and put a div in the browser router or leave it empty. I won't be able to
// add these files in this post.
function App() {
return (
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
export default App;
The App itself is rendered within standard index.js =>
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
The test I originally wanted =>
import { render } from '@testing-library/react';
import App from './App';
import React from "react";
import { BrowserRouter, MemoryRouter, Link } from 'react-router-dom';
test('renders App', () => {
render(<App />); // it fails on this line
expect(<App />).toBeDefined();
});
The minimal tests for narrowing down the problem source =>
import { render } from '@testing-library/react';
import App from './App';
import React from "react";
import { BrowserRouter, MemoryRouter, Link } from 'react-router-dom';
test('renders BrowserRouter', () => {
render(<BrowserRouter />);
});
test('renders MemoryRouter', () => {
render(<MemoryRouter />);
});
// in a function to re-create the context
function TestComponent() {
return <BrowserRouter></BrowserRouter>;
}
test('renders TestComponent', () => {
const { container } = render(<TestComponent />); // also failing on this line
expect(container).toBeDefined();
});
All these tests have the same error type:
output:
console.error
Error: Uncaught [TypeError: Cannot read properties of null (reading 'useRef')]
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs./link/invalid-hook-call for tips about how to debug and fix this problem.
console.error
The above error occurred in the <BrowserRouter> component:
at fn (/.../packages/react-router-dom/index.tsx:136:3)
The react-router-dom elements never cause any such problems when I run the application outside testing environment so I suspect there is some issue with jest but I have exhausted everything I/internet research could think to try so I'm really hoping anyone can help! If anyone has seen this issue or knows anything about it please let me know.
For more context, these errors do not appear when rendering non-react-router-dom components with hooks in them!
Steps to recreate: Install the same package versions and create the example test above.
What did I try: Tried ensuring no version mismatch, upgrading many packages (to the ones above), adding various settings to package.json to try to use upgraded version of jsdom including trying to explicitly set it as global dom in setupTests.js which did not work..., setting TextEncoders and TextDecoders, and rendering many different variants (React.StrictMode wrapped, using ReactDOM root rendering, putting it inside container, importing from react-router instead of react-router-dom) to see if it was anything in my set up.
Share Improve this question asked Mar 11 at 12:55 rdnrdn 11 bronze badge 1- Well, as I said in your post in the Staging Ground, React-Router works much the same in unit testing as it does in regular UI files. Here's a running CodeSandbox of the code and dependency versions you provided, and as you can see the unit tests run without issue. Perhaps you have some issue elsewhere. Feel free to fork my sandbox or create one of your own and add more of your actual code/setup/configs/versions/etc. to see if you can reproduce the issue that readers here could then inspect live. – Drew Reese Commented Mar 11 at 15:19
1 Answer
Reset to default 0If anyone else has a similar issue, what I found worked for me is either
- Downgrading react-router-dom to any 6.x.x
or
- Migrating from Create React App/react-scripts to Vite
There maybe some fiddly workarounds possible with setting global TextEncoders and TextDecoders that I've seen suggested but this didn't work for me.