React 测试库不变量失败:你不应该在 <Router> 之外使用 <Route>
React Testing Library Invariant failed: You should not use <Route> outside a <Router>
我正在使用 React Testing Library 测试我的组件是否成功地使用 Redux 呈现。我无法让我的实用程序组件通过 renderWithRedux 测试。这是我的 App 组件。
function App() {
return (
<>
<Router>
<NavBar />
<div className="container">
<Switch>
<Route exact path='/' component={Home}/>
<AuthRoute exact path='/login' component={Login} />
<AuthRoute exact path='/signup' component={Signup} />
<Route exact path='/users/:handle' component={UserProfile} />
<Route exact path='/users/:handle/post/:postId' component={UserProfile} />
</Switch>
</div>
</Router>
</>
);
}
这是我的 AuthRoute 实用程序组件。
const AuthRoute = ({ component: Component, authenticated, ...rest }) => (
// if authenticated, redirect to homepage, otherwise redirect to signup or login
<Route
{...rest}
render={(props) =>
authenticated === true ? <Redirect to='/' /> : <Component {...props} />
}
/>
);
AuthRoute.test.js
const renderWithRedux = () => render(
<Provider store={myStore}>
<AuthRoute />
</Provider>
);
it('renders with Redux', () => {
const {} = renderWithRedux(<AuthRoute />);
});
我尝试了 中的解决方案,但无济于事。感谢您的帮助,谢谢。
就像 Provider
包装 redux 的东西一样,你必须使用 MemoryRouter
的路由来包装你的组件进行测试。
import { MemoryRouter } from 'react-router';
将被测组件渲染到路由器中
import { MemoryRouter } from 'react-router-dom';
const renderWithRedux = ({ children }) => render(
<Provider store={myStore}>
{children}
</Provider>
);
it('renders with Redux', () => {
const {} = renderWithRedux(
<MemoryRouter>
<AuthRoute />
</MemoryRouter>
);
});
基本上,您有两个包装器元素。它应该是这样的,例如,renderWithReduxWrapp => renderWithRouter => YourTestingComponent.
我在尝试根据道具测试按钮渲染(具有 Link)时遇到了类似的问题,并且能够通过创建一些辅助函数来解决它。
示例如下:
这是主要组件,UserCard.js
,它从 redux 呈现用户数据,并且仅在 withButton
时显示一个按钮 道具通过了。
import React from "react";
import { Link } from "react-router-dom";
import { Button } from "react-bootstrap";
const CardComponent = ({ withButton }) => {
const userInfo = useSelector((state) => getUserSelector(state));
return (
<div>
<div>{userInfo}</div>
{withButton && (
<Link to="/settings" className="button-link">
<Button block>EDIT CONTACT INFO</Button>
</Link>
)}
</div>
);
};
export default CardComponent;
这是一个 CardComponent.test.js
文件。
首先,你需要添加这几行代码
const ReduxWrapper = ({ children }) => {
<Provider store={store}>{children} </Provider>;
}
const AppWrapper = ({ children }) => (
<BrowserRouter>
<ReduxWrapper>{children}</ReduxWrapper>
</BrowserRouter>
);
const renderWithRouter = (ui, { route = '/' } = {}) => {
window.history.pushState({}, 'Test page', route);
return render(ui, { wrapper: AppWrapper });
};
之后,您需要使用 renderWithRouter
而不是 render
方法开始测试。
it('should render settings button if prop withButton is passed', () => {
renderWithRouter(<CardComponent withButton />, { wrapper: ReduxWrapper });
// apply you code here. I only needed to check if the button is renederd or not.
const settingsButton = screen.queryByText(/edit contact info/i);
expect(settingsButton).toBeInTheDocument();
});
我正在使用 React Testing Library 测试我的组件是否成功地使用 Redux 呈现。我无法让我的实用程序组件通过 renderWithRedux 测试。这是我的 App 组件。
function App() {
return (
<>
<Router>
<NavBar />
<div className="container">
<Switch>
<Route exact path='/' component={Home}/>
<AuthRoute exact path='/login' component={Login} />
<AuthRoute exact path='/signup' component={Signup} />
<Route exact path='/users/:handle' component={UserProfile} />
<Route exact path='/users/:handle/post/:postId' component={UserProfile} />
</Switch>
</div>
</Router>
</>
);
}
这是我的 AuthRoute 实用程序组件。
const AuthRoute = ({ component: Component, authenticated, ...rest }) => (
// if authenticated, redirect to homepage, otherwise redirect to signup or login
<Route
{...rest}
render={(props) =>
authenticated === true ? <Redirect to='/' /> : <Component {...props} />
}
/>
);
AuthRoute.test.js
const renderWithRedux = () => render(
<Provider store={myStore}>
<AuthRoute />
</Provider>
);
it('renders with Redux', () => {
const {} = renderWithRedux(<AuthRoute />);
});
我尝试了
就像 Provider
包装 redux 的东西一样,你必须使用 MemoryRouter
的路由来包装你的组件进行测试。
import { MemoryRouter } from 'react-router';
将被测组件渲染到路由器中
import { MemoryRouter } from 'react-router-dom';
const renderWithRedux = ({ children }) => render(
<Provider store={myStore}>
{children}
</Provider>
);
it('renders with Redux', () => {
const {} = renderWithRedux(
<MemoryRouter>
<AuthRoute />
</MemoryRouter>
);
});
基本上,您有两个包装器元素。它应该是这样的,例如,renderWithReduxWrapp => renderWithRouter => YourTestingComponent.
我在尝试根据道具测试按钮渲染(具有 Link)时遇到了类似的问题,并且能够通过创建一些辅助函数来解决它。
示例如下:
这是主要组件,UserCard.js
,它从 redux 呈现用户数据,并且仅在 withButton
时显示一个按钮 道具通过了。
import React from "react";
import { Link } from "react-router-dom";
import { Button } from "react-bootstrap";
const CardComponent = ({ withButton }) => {
const userInfo = useSelector((state) => getUserSelector(state));
return (
<div>
<div>{userInfo}</div>
{withButton && (
<Link to="/settings" className="button-link">
<Button block>EDIT CONTACT INFO</Button>
</Link>
)}
</div>
);
};
export default CardComponent;
这是一个 CardComponent.test.js
文件。
首先,你需要添加这几行代码
const ReduxWrapper = ({ children }) => {
<Provider store={store}>{children} </Provider>;
}
const AppWrapper = ({ children }) => (
<BrowserRouter>
<ReduxWrapper>{children}</ReduxWrapper>
</BrowserRouter>
);
const renderWithRouter = (ui, { route = '/' } = {}) => {
window.history.pushState({}, 'Test page', route);
return render(ui, { wrapper: AppWrapper });
};
之后,您需要使用 renderWithRouter
而不是 render
方法开始测试。
it('should render settings button if prop withButton is passed', () => {
renderWithRouter(<CardComponent withButton />, { wrapper: ReduxWrapper });
// apply you code here. I only needed to check if the button is renederd or not.
const settingsButton = screen.queryByText(/edit contact info/i);
expect(settingsButton).toBeInTheDocument();
});