You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Enzyme如何测试React组件本地状态是否更新?代码问题求助

问题:React组件本地状态更新的单元测试失败

我正在测试下拉框选项选中时触发的函数,该函数会在ListOfTemplates列表变化时更新组件本地state的value字段。但测试时发现调用onChange(2)后,组件state的value仍为初始值1,而非预期的2。请问如何正确测试本地状态是否更新?我的代码哪里出错了?


容器组件代码

import React from 'react'; 
import { connect } from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import * as getData from '../../services/DataService'; 

class Container extends React.Component { 
  constructor(props){ 
    super(props) 
    this.props.actions.getTemplates(1); 
    this.state = { value: 1 } 
  } 

  handlelistOfTemplates = (value, index) => { 
    this.setState({ value }); 
  }; 

  componentDidMount() { } 

  render() { 
    return( 
      <ListOfTemplates 
        listOfTemplates={this.props.listOfTemplates} 
        value={this.state.value} 
        onChange={this.handlelistOfTemplates}
      /> 
    ); 
  } 
} 

function mapStateToProps({state}) { 
  return { listOfTemplates: state.listOfTemplates } 
} 

function mapDispatchToProps(dispatch) { 
  return { actions: bindActionCreators(getData, dispatch) }; 
} 

module.exports = connect(mapStateToProps, mapDispatchToProps)(Container); 

测试代码

import React from 'react'; 
import sinon from 'sinon'; 
import expect from 'expect'; 
import { shallow } from 'enzyme'; 
import PropTypes from 'prop-types'; 
import getMuiTheme from 'material-ui/styles/getMuiTheme'; 
import { createMockStore, createMockDispatch } from 'redux-test-utils'; 
import Container from './Container'; 

const shallowWithStore = (component, store) => { 
  const context = { store, muiTheme: getMuiTheme(), }; 
  const childContextTypes = { 
    muiTheme: React.PropTypes.object.isRequired, 
    store: PropTypes.object.isRequired 
  } 
  return shallow(component, { context, childContextTypes }); 
}; 

let store; 
const loadComponent = (testState) => { 
  const props = { 
    actions: { getTemplates: () => {return Promise.resolve()} } 
  } 
  store = createMockStore(testState) 
  return shallowWithStore(<Container {...props}/>, store); 
} 

const getFakeState = () => { 
  return { listOfTemplates: [], }; 
} 

export default shallowWithStore; 

describe('Container', () => { 
  let testState, component; 

  describe("when Appeal template is selected from select template dropdown", () => { 
    beforeAll(() => { 
      testState = getFakeState(); 
      component = loadComponent(testState); 
    }); 

    fit('should update the content in editor', (done) => { 
      component.dive().find('ListOfTemplates').props().onChange(2); 
      component.update(); 
      expect(component.dive().state().value).toEqual(2); // 实际返回1而非预期的2
      done(); 
    }); 
  }); 
}); 

问题分析与解决方案

核心问题:多次dive()导致操作不同组件实例

你每次调用component.dive()都会生成一个全新的浅渲染组件实例。第一次dive()调用onChange时,更新的是这个临时实例的状态,但第二次dive()又重新创建了一个初始状态的实例,所以断言时拿到的还是初始值1。

修复步骤

  1. 复用dive()后的实例:把component.dive()的结果存储到变量中,后续的事件触发和状态断言都使用这个同一个实例。
  2. 处理setState的异步性:setState是异步操作,调用后需要用update()强制组件同步更新状态,再进行断言。

修改后的测试代码

fit('should update the content in editor', () => { 
  // 保存dive后的组件实例,后续操作都基于它
  const containerInstance = component.dive(); 
  // 触发下拉框的onChange事件
  containerInstance.find('ListOfTemplates').props().onChange(2); 
  // 强制组件同步更新状态
  containerInstance.update(); 
  // 断言同一个实例的状态值
  expect(containerInstance.state().value).toEqual(2); 
}); 

额外提示

  • 你的测试中原本使用了done回调,但当前场景没有异步逻辑(除非handlelistOfTemplates内部有异步操作),可以直接去掉,让测试同步执行。
  • 如果后续遇到涉及异步状态更新的测试,可以结合async/await或者setState的回调函数来确保状态更新完成后再断言。

内容的提问来源于stack exchange,提问作者Sinha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:17:18