【问题标题】:React test with Enzyme, cannot read property 'route' of undefined用酶反应测试,无法读取未定义的属性“路线”
【发布时间】:2017-12-14 02:45:59
【问题描述】:

在我的 React 应用程序(无通量/redux)中,我正在尝试使用 enzyme 对组件进行单元测试,浅渲染效果很好,我能够检索它的状态等等,但是mount rendering给我一个cannot read property 'route' of undefined的错误。

我的App.js 看起来像这样

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Switch>
          <MyCustomLayout>
            <Route path="/mypath" component={myComponent} />
          </MyCustomLayout>
        </Switch>
      </BrowserRouter>
    )
  }

这是myComponent的代码

import React, { Component } from 'react';
import './index.css';
import { getList } from './apiService.js';
 
class myComponent extends Component {
  constructor(props) {
      super(props);
      this.state = {
        myList: [],
      };
  }
  
  componentDidMount() {
  // get list ajax call
    getList().then(response => {
      this.setState({
        myList: response.data
      })
    });
  }
  
  handleClick = () => {
    this.props.history.push('/home');
  }
  
  renderMyList() {
    /*
      Code for rendering list of items from myList state
    */
  }
  
  render() {
    return (
      <div>
        <h1>Hello World</h1>
        <button onClick={this.handleClick}>Click me</button>
        {this.renderMyList()}
      </div>
    )
  }
}

export default myComponent

这是我的测试代码

import React from 'react';
import myComponent from './myComponent';
import renderer from 'react-test-renderer';
import { shallow, mount } from 'enzyme';
import sinon from 'sinon';

test('Initial state of myList should be empty array ', () => {
  const component = shallow(<myComponent/>);
  expect(component.state().myList).toEqual([]);
});

test('Make sure the componentDidMount being called after mount', () => {
  sinon.spy(myComponent.prototype, 'componentDidMount');
  const component = mount(<myComponent/>);
  expect(myComponent.prototype.componentDidMount.calledOnce).toEqual(true);
});

错误是什么?

【问题讨论】:

  • 您应该使用MemoryRouter 而不是BrowserRouter 进行单元测试。您的问题可能与此有关。你能展示一下你的测试代码吗?
  • 那么你的意思是我应该为了单元测试而改变真正的实现?我不认为这是一个好主意。反正我加了测试,请看@LukeVella
  • 看看myComponent中的内容会很有用。
  • @LukeVella 再次编辑
  • 我什么也没看到,但你一定是在某个地方指的是route。也许发布错误的堆栈跟踪。

标签: unit-testing reactjs enzyme


【解决方案1】:

前几天在这里遇到了这个问题 - 您收到此错误的原因是因为您尝试安装 &lt;Route /&gt;&lt;Link /&gt; 或使用 withRouter() 包裹的组件,而没有 &lt;Router /&gt;围绕代码。这些组件期望存在特定的上下文(&lt;Router /&gt; 提供),因此为了测试这些组件,您必须将组件安装在 &lt;MemoryRouter /&gt; 内。

这是为您执行此操作的函数:

const mountWithRouter = Component => mount(
  <MemoryRouter>
    {Component}
  </MemoryRouter>
);

这是你如何使用它的:

test('Make sure the componentDidMount being called after mount', () => {
  sinon.spy(myComponent.prototype, 'componentDidMount');
  const component = mountWithRouter(<myComponent/>);
  expect(myComponent.prototype.componentDidMount.calledOnce).toEqual(true);
});

话虽如此,当我迁移到react-router@^4.0.0 时,我最终试图删除大部分已安装的测试代码——这很麻烦。这样做的主要缺点是您在此测试中的const component 不再是myComponent,而是MemoryRouter。这意味着您不能那么容易地深入了解它的状态等。

编辑:

当我确实需要检查我“必须”安装的组件的状态时,我所做的一个示例是,我改为浅渲染它,然后手动运行我需要的生命周期方法,如下所示:

test('populates state on componentDidMount', () => {
  const wrapper = shallow(<MyComponent />);
  wrapper.instance().componentDidMount();
  expect(wrapper.state()).toBe({ some: 'state' });
});

这样,我根本不需要处理路由器问题(因为没有挂载),我仍然可以测试我需要测试的内容。

【讨论】:

  • 我知道它不在主题范围内,但是现在,我遇到了你所说的问题,如果它被包裹在 MemoryRouter 中,我无法检索组件的状态,你能告诉我如何处理这个问题?
  • @MattDowney - 我添加了另一个关于我如何应对这一挑战的示例。不确定这是否是最好的方法,但这是我想出的。
  • 酷,我不知道你可以在浅渲染组件中调用componentDidMount
  • 对我来说也是新闻!但它是一个简单的方法——即使 React 为我们调用它,它仍然是原型的一部分 :)
猜你喜欢
  • 2016-11-30
  • 2017-09-24
  • 2018-03-06
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
  • 2020-06-04
  • 1970-01-01
  • 2017-06-18
相关资源
最近更新 更多