I'm trying to test that my router is working as expected. But I can't get the router to point to another location than /
Here's my simplified test code.
App.tsx
import React from 'react';
import {Route, Switch, BrowserRouter} from 'react-router-dom';
const App: React.FC = () => {
return (
<div>
<BrowserRouter>
<Switch>
<Route path={'/test'}>test</Route>
<Route path={'/'}>index</Route>
</Switch>
</BrowserRouter>
</div>
);
};
export default App;
App.test.tsx
import React from 'react';
import App from './App';
import {MemoryRouter} from 'react-router-dom';
import {render} from '#testing-library/react';
test('renders /test route', async () => {
const app = render(
<MemoryRouter initialEntries={['/test']} initialIndex={0}>
<App/>
</MemoryRouter>);
expect(app.getByText(/test/i)).toBeInTheDocument();
});
I get the following error message
Error: Unable to find an element with the text: /test/i. 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>
<div>
index
</div>
</div>
</body>
What am I doing wrong?
The problem is, that the component I wanted to test already has a router declared.
To solve this issue I had to split up the App Component into App and Routes.
For the testing I just have to render the Routes component and everything works as expected.
App.tsx
import React from 'react';
import {Route, Switch, BrowserRouter} from 'react-router-dom';
export const Routes = () => {
return (
<>
<Switch>
<Route path={'/test'}> test</Route>
<Route path={'/'}> index</Route>
</Switch>
</>
)
};
const App: React.FC = () => {
return (
<div>
<BrowserRouter>
<Routes/>
</BrowserRouter>
</div>
);
};
export default App;
App.test.tsx
import React from 'react';
import {Routes} from './App';
import {MemoryRouter} from 'react-router-dom';
import {render} from '#testing-library/react';
test('renders routes correct', async () => {
const app = render(
<MemoryRouter initialEntries={['/test']} initialIndex={0}>
<Routes/>
</MemoryRouter>
);
expect(app.getByText(/test/i)).toBeInTheDocument();
});
If you're loading App from index.js, which was the case when I was running into this issue on a Create React App app, you can also wrap App in a Router there and then test App routes as you'd expect without having to export Routes as you've done.
For example (otherwise a stock CRA index.js):
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import './index.css';
import App from './app';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
Related
I am learning react and the course I am learning from uses a previous version of react. The tutor calls routing inside ReactDom.render(). I am not able to figure out how to get it to work inside root.render(). i end up getting a blank page instead of App component.
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { Route, Link, Switch, BrowserRouter as Router } from "react-router-dom";
import "./index.css";
import App from "./App";
const routing = (
<Router>
<Route path="/" component={App} />
</Router>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<h1>{routing}</h1>
</React.StrictMode>
);
App.js
import React from "react";
const App = () => {
return (
<div>
<h1>App component</h1>
</div>
);
};
export default App;
Applies to React Router v6:
You need to wrap <App /> with the <Router /> component
Delete the const routing: ... and do this instead:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter as Router } from "react-router-dom";
import "./index.css";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>
);
Now in your app component wrap the component you want to render with a specific route in <Routes />:
import React from "react";
import { Routes, Route } from "react-router-dom";
const App = () => {
return (
<Routes>
<Route path="/" element={<ANY_COMPONENT_YOU_WANT/>} />
</Routes>
);
};
export default App;
First of all, I want to say that none of the other answers to the questions in this category were able to resolve my issue.
During the npm test, I get the following error:
FAIL src/App.test.js
× renders App (74 ms)
● renders App
**Could not find "store" in the context of "Connect(App)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(App) in connect options.**
6 | test('renders App', () => {
7 | const div = document.createElement('div');
8 | ReactDOM.render(, div);
| ^
9 | ReactDOM.unmountComponentAtNode(div);
10 | });
11 |
This is the test code:
import React from 'react';
import '#testing-library/jest-dom';
import App from './App';
import * as ReactDOM from "react-dom";
test('renders App', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
This is the App.jsx (I also tried with the extension .js but no difference):
import React from 'react';
import './App.css';
import {Switch, Route, Redirect} from 'react-router-dom';
import Header from "./components/header/header.component";
import HomePage from "./components/homepage/homepage.component";
import Categories from "./components/categories/categories.component";
import Jokes from "./components/jokes/jokes.component";
import Search from "./components/search/search.component";
import SignIn from "./components/sign-in/sign-in.component";
import {connect} from "react-redux";
class App extends React.Component {
render() {
const {currentUser} = this.props;
return (
<div>
<Header/>
<Switch>
<Route exact path='/' render={() => <HomePage/>}/>
<Route path='/categories' render={() => <Categories/>}/>
<Route path='/jokes' render={() => <Jokes/>}/>
<Route path='/search' render={() => <Search/>}/>
<Route
exact
path='/sign-in'
render={() =>
currentUser
? <Redirect to='/'/>
: <SignIn/>}
/>
</Switch>
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.user.currentUser
})
export default connect(mapStateToProps)(App);
The index.js file is as follows:
import React from 'react';
import './index.css';
import App from './App';
import {BrowserRouter} from "react-router-dom";
import {Provider} from "react-redux";
import store from "./redux/store";
import * as ReactDOM from "react-dom";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<React.StrictMode>
<App/>
</React.StrictMode>
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
Trying to use React Router and I keep getting an error that my Route must be inside a Router, even though it already is. I've already tried running npm install again, and removing and readding the react router npm package. The error message is
Invariant failed: You should not use <Route> outside a <Router>
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter as Router } from 'react-router-dom';
ReactDOM.render(
<Router>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById('root')
);
app.js
import logo from './logo.svg';
import './App.css';
import Main from './Components/Main/main';
import {BrowserRouter, Route,Link } from 'react-router-dom';
function App() {
return (
<div className="App">
<Route exact path='/'>
<Main />
</Route>
</div>
);
}
export default App;
main.js
export default function Main(props) {
const [anim,setAnim] = useState(false);
return (
<MainSection>
</MainSection>
)
}
I am a beginner in React and trying to understand routing. I have created a learning project and want to render three different components each with a different path. However, all the paths result in the display of the App component.
I've tried finding solutions on multiple sources, but not able to figure out the issue! Please have a look. Thanks in advance.
Root.jsx
import React, { Component } from 'react';
import { Router } from 'react-router';
import { Redirect, Route, Switch } from 'react-router-dom';
import ScreensList from './List';
import ScreensWeather from './Weather';
import App from '../App';
const ScreensRoot = () => (
<Router>
<Switch>
<Route exact path='/' component={App}/>
<Route path="/list" component={ScreensList} />
<Route path="/weather" component={ScreensWeather} />
</Switch>
</Router>
);
export default ScreensRoot;
App.js
import React, {Component} from 'react';
import './App.css';
class App extends React.Component {
render(){
return (
<div>
Hello from App!
</div>
)
}
}
export default App;
List.jsx
import React from 'react';
import List from '../components/List';
const ScreensList = () => (
<div>
<List/>
</div>
);
export default ScreensList;
List.jsx
import React from 'react';
const List = (
<div>Hello from List Component!</div>
);
export default List;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import './screens/Root';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
1.Insted of
import { Router } from 'react-router';
use
import { BrowserRouter as Router } from "react-router-dom";
2.change
const List = (
<div>Hello from List Component!</div>
);
to
const List = () => (
<div>Hello from List Component!</div>
);
3. As others mentioned
ReactDOM.render(<ScreensRoot />, rootElement);
Temporary codesandbox
As far as I can see, you've defined a ScreensRoot component but you're not using anywhere. Assuming you want that to be the actual root of your project, then in your index.js you must use it instead of App:
ReactDOM.render(<ScreensRoot/>, document.getElementById('root'));
(Note that you'll need to import ScreensRoot in your index.js in order for this to work).
In my application, I am trying to provide store to Router as shown in below code. but It seems like not working as per expectation. Can anyone suggest me the correct way to do it? I have provided my code below.
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import store from "./store";
import { Provider } from 'react-redux'
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById("root"));
App.js
import React, { Component } from "react";
import "./App.css";
import SectionIndicator from "./components/SectionIndicator/SectionIndicator";
import Section from "./components/Section/Section";
import { BrowserRouter as Router, Route, Switch, browserHistory } from "react-router-dom";
import Section2 from "./components/Section/Section2"; import CheckUpButton from "./components/CheckUpButton/CheckUpButton";
import AppContent from "./AppContent";
import createHistory from "history/createBrowserHistory";
class App extends Component {
render() {
const history = createHistory({ basename: '/' });
return (
<Router history={history} >
<div>
<Switch>
<Route path="/" exact component={CheckUpButton} />
<Route path="/assess" exact component={AppContent} />
<Route path="/section2" component={Section2} />
</Switch>
</div>
</Router>
)
}
}
export default App;
error ::
You should call your App component inside your ReactDOM.Render:
ReactDOM.render(<App />, document.getElementById('root'));
Then, wrap your app with the provider component and call your router inside :
<Provider store={store}>
<Router history={history}>
<Routes />
<Router />
<Provider />
Don't forget to pass history to Router component.
Try it this way :)