【问题标题】:jest enzyme mount - Cannot ready property of undefined when checking this.props.location.query开玩笑酶安装 - 检查 this.props.location.query 时无法读取未定义的属性
【发布时间】:2017-03-27 22:46:40
【问题描述】:

我有一个具有以下 componentDidMount() 方法的组件:

componentDidMount() {
    let seconds = 0;

    if(this.props.location.query.seconds) {
     seconds = parseInt(this.props.location.query.seconds, 10);
    }

    if (seconds > 0) {
      this.setState({count:seconds});
      window.location.hash = '#/timer';
    }
  }

我也在构造函数中设置状态:

constructor(props) {
    super(props);

    this.state = {
      count: 180,
      countdownStatus: 'stopped'
    };

    this.handleStatusChange = this.handleStatusChange.bind(this);
    this.handleSetCountdown = this.handleSetCountdown.bind(this);
    this.handleSliderInput = this.handleSliderInput.bind(this);
  }

然后我通过渲染将状态传递给另一个组件

function:
  render() {
    let {count, countdownStatus} = this.state;
    return(
      <div className="content-card timer-card">
        <h1 className="title">Tea timer</h1>
        <Clock totalSeconds={count} status={countdownStatus}/>
        {renderStartStop()}
      </div>
    )
  }

现在我想编写一个测试来检查 props 是否正确传递:

import React from 'react';
import {shallow, mount} from 'enzyme';
import sinon from 'sinon';

import Timer from './Timer.component';

describe('<Timer/>', () => {
  it('pass count to Clock as totalSeconds', () => {
    const wrapper = mount(<Timer />);
    wrapper.instance().props.location.query.seconds = 180;
    expect(wrapper.find('Clock').prop('totalSeconds').toEqual(180));
  })
});

但我收到以下错误:

TypeError:无法读取未定义的属性“查询”

  at Timer.componentDidMount (src/Timer/Timer.component.js:26:28)
  at node_modules/react-dom/lib/ReactCompositeComponent.js:265:25
  at measureLifeCyclePerf (node_modules/react-dom/lib/ReactCompositeComponent.js:75:12)
  at node_modules/react-dom/lib/ReactCompositeComponent.js:264:11
  at CallbackQueue.notifyAll (node_modules/react-dom/lib/CallbackQueue.js:76:22)
  at ReactReconcileTransaction.close (node_modules/react-dom/lib/ReactReconcileTransaction.js:80:26)
  at ReactReconcileTransaction.closeAll (node_modules/react-dom/lib/Transaction.js:206:25)
  at ReactReconcileTransaction.perform (node_modules/react-dom/lib/Transaction.js:153:16)
  at batchedMountComponentIntoNode (node_modules/react-dom/lib/ReactMount.js:126:15)
  at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:140:20)
  at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26)
  at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27)
  at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:320:18)
  at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:401:32)
  at Object.render (node_modules/react-dom/lib/ReactMount.js:422:23)
  at Object.renderIntoDocument (node_modules/react-dom/lib/ReactTestUtils.js:79:21)
  at renderWithOptions (node_modules/enzyme/build/react-compat.js:187:26)
  at new ReactWrapper (node_modules/enzyme/build/ReactWrapper.js:94:59)
  at mount (node_modules/enzyme/build/mount.js:19:10)
  at Object.it (src/Timer/Timer.test.js:13:65)
  at process._tickCallback (internal/process/next_tick.js:103:7)

不应该通过if(this.props.location.query.seconds) 检查来缓解这种情况吗?

我只发布了相关部分,因为这个组件有点大,但如果您需要更多信息,整个组件是here。如果需要一些关键信息,也请发表评论,以便我更新问题。

【问题讨论】:

    标签: javascript reactjs jestjs enzyme


    【解决方案1】:

    所以,这里有几点需要注意:

    第一个是初始检查是错误的——我首先需要检查 this.props 是否是一个对象,以及它是否有嵌套在任何地方的 seconds 键。于是我修改了componentDidMount方法:

      componentDidMount() {
        // function for checking if an argument is a object
        let isObj = (variable) => (variable !== null) && (typeof variable === 'object');
        // function for checking if an object has a specific nested key
        let objHasKey = (obj, key) => {
          return isObj(obj) ? (key in obj) || Object.values(obj).filter(nestedObj => objHasKey(nestedObj, key)).length > 0 : false;
        };
    
        let seconds = 0;
        if(objHasKey(this.props, 'seconds')) {
         seconds = parseInt(this.props.location.query.seconds, 10);
        }
        if (seconds > 0) {
          this.setState({count:seconds});
          window.location.hash = '#/timer';
        }
      }
    

    然后我将测试分为两类,一类是在将 props 传递给组件时,一类是没有:

      it('pass state countdownStatus to Clock as status', () => {
        const wrapper = mount(<Timer />);
        const status = wrapper.state('countdownStatus');
        expect(wrapper.find('Clock').prop('status')).toEqual(status);
      });
      it('set this.props.location.query.seconds as state.count when passed', () => {
        const mockUrl = {
          query : {
            seconds: '100'
          }
        }
        const wrapper = mount(<Timer location={mockUrl}/>);
        expect(wrapper.state('count')).toEqual(100);
      })
    

    【讨论】:

      猜你喜欢
      • 2018-09-05
      • 2020-06-26
      • 2022-01-18
      • 2023-03-03
      • 2020-11-19
      • 2018-06-17
      • 1970-01-01
      • 2020-07-10
      • 2017-12-15
      相关资源
      最近更新 更多