React 测试库不变量失败:您不应该在 <Router> 之外使用 <Route>

Posted

技术标签:

【中文标题】React 测试库不变量失败:您不应该在 <Router> 之外使用 <Route>【英文标题】:React Testing Library Invariant failed: You should not use <Route> outside a <Router> 【发布时间】:2020-12-10 07:11:03 【问题描述】:

我正在测试我的组件是否使用 React 测试库成功使用 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 />);
);

我尝试了Invariant failed: You should not use <Route> outside a <Router> 的解决方案,但无济于事。感谢您的帮助,谢谢。

【问题讨论】:

【参考方案1】:

将被测组件渲染到路由器中

import  MemoryRouter  from 'react-router-dom';

const renderWithRedux = ( children ) => render(
    <Provider store=myStore>
        children
    </Provider>
);

it('renders with Redux', () => 
    const  = renderWithRedux(
      <MemoryRouter>
        <AuthRoute />
      </MemoryRouter>
    );
);

【讨论】:

谢谢,但我收到了Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. @kennjamin 在您的renderWithRedux 中您是否真的打算在测试中包装传递给它的任何组件(即渲染传递给它的子组件)?我更新了我的答案。 成功了!你是对的,我应该改变包装 App 组件,而不是用孩子包装。谢谢!【参考方案2】:

就像 Provider 包装 redux 的东西一样,您必须使用 MemoryRouter 的路由包装您的组件以进行测试。

import MemoryRouter from 'react-router';

【讨论】:

谢谢,但我收到了Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.【参考方案3】:

基本上,您有两个包装器元素。它应该是这样的,例如,renderWithReduxWrapp => renderWithRouter => YourTestingComponent

我在尝试根据 props 测试 Button 渲染(有一个链接)时遇到了类似的问题,并且能够通过创建一些辅助函数来解决它。

示例如下:

这是主要组件,UserCard.js,它从redux渲染用户数据,并且只有在传递withButton props时才会显示一个按钮。

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 测试库不变量失败:您不应该在 <Router> 之外使用 <Route>的主要内容,如果未能解决你的问题,请参考以下文章

不变式失败:您不应该在 <Router> 之外使用 <Link>

开玩笑 - 不变式失败:您不应该在 <Router> 之外使用 <Link>

使用 Enzyme 测试 React 组件时出错:'不变违规:您不应在 <Router> 外使用 <Link>'

从共享组件库导出`react-router`重定向

不变违规:您不应该在 <Router> 之外使用 <Switch>

不变违规:您不应该在 <Router> 之外使用 withRouter() (使用最少的工作示例)