用酶反应测试,无法读取未定义的属性'route'

Mat*_*ney 2 unit-testing reactjs enzyme

在我的React App(No flux/redux)中,我正在尝试对组件进行单元测试enzyme,浅渲染效果很好,我能够检索它的状态等,但是挂载渲染会给我一个错误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>
    )
  }
Run Code Online (Sandbox Code Playgroud)

这是代码 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
Run Code Online (Sandbox Code Playgroud)

这是我测试的代码

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);
});
Run Code Online (Sandbox Code Playgroud)

错误是什么?

Kri*_*ekk 7

之前有这个问题 - 你得到这个错误的原因是因为你试图在没有代码的情况下安装一个<Route />或一个<Link />或一个组件.这些组件期望存在某个上下文(提供),因此为了测试这些组件,您必须将组件安装在一个组件中.withRouter()<Router /><Router /><MemoryRouter />

这是一个为您完成此功能的功能:

const mountWithRouter = Component => mount(
  <MemoryRouter>
    {Component}
  </MemoryRouter>
);
Run Code Online (Sandbox Code Playgroud)

这是你如何使用它:

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);
});
Run Code Online (Sandbox Code Playgroud)

话虽这么说,我最终试图在迁移时删除大部分已安装的测试代码react-router@^4.0.0- 这很麻烦.这方面的主要缺点是你const component在这个测试中不再是a myComponent,而是a MemoryRouter.这意味着你不能轻易地挖掘它的状态等.

编辑:

我做的事情的一个例子需要检查我"安装"的组件的状态是我浅薄地渲染它,然后运行我需要的生命周期方法,如下所示:

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

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

  • @MattDowney - 我在如何应对这一挑战时添加了另一个例子.不确定它是否是最佳方法,但这是我想出的. (2认同)