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();
});