javascript - 测试带有函数的 React 组件 setState 重载
问题描述
我正在尝试测试一个使用 setState 重载之一的 React 组件,但不确定如何正确断言调用。一个示例组件是:
class CounterComponent extends React.Component {
updateCounter() {
this.setState((state) => {
return {
counterValue: state.counterValue + 1
};
});
}
}
这里的假设是这个方法将被异步调用,所以不能依赖于当前状态,除了调用 setState (因为它可能在 setState 执行之前改变)。谁能建议你如何断言这个电话?以下测试失败,因为它只是比较函数名称。
it("Should call setState with the expected parameters", () => {
const component = new CounterComponent();
component.setState = jest.fn(() => {});
component.state = { counterValue: 10 };
component.updateCounter();
const anonymous = (state) => {
return {
counterValue: state.counterValue + 1
};
};
//expect(component.setState).toHaveBeenCalledWith({ counterValue: 11 });
expect(component.setState).toHaveBeenCalledWith(anonymous);
});
编辑:鉴于 yohai 在下面的回答,我将添加一些进一步的上下文,因为我觉得我可能过度简化了问题,但是为了清楚起见,我不想重写整个问题。
在我的实际组件中,正在编辑的状态值不是一个简单的数字,它是一个具有以下结构的对象数组:
{ isSaving: false, hasError: false, errorMessage: ''}
和其他一些属性。当用户单击保存时,会为数组中的每个项目触发一个异步操作,然后在该操作返回或被拒绝时更新相应的条目。例如,保存方法如下所示:
onSave() {
const { myItems } = this.state;
myItems.forEach(item => {
api.DoStuff(item)
.then(response => this.handleSuccess(response, item))
.catch(error => this.handleError(error, item));
});
}
处理成功和错误方法只是更新对象并调用replaceItem:
handleSuccess(response, item) {
const updated = Object.assign({}, item, { hasSaved: true });
this.replaceItem(updated);
}
handleError(error, item) {
const updated = Object.assign({}, item, { hasError: true });
this.replaceItem(updated);
}
然后 replaceItem 替换数组中的项目:
replaceItem(updatedItem) {
this.setState((state) => {
const { myItems } = state;
const working = [...myItems];
const itemToReplace = working.find(x => x.id == updatedItem.id);
if (itemToReplace) {
working.splice(working.indexOf(itemToReplace), 1, updatedItem);
};
return {
myItems: working
};
});
}
replaceItem 是我要测试的方法,并试图验证它是否使用正确的重载和正确更新状态的函数调用 setState。
我在下面的回答详细说明了我是如何为自己解决这个问题的,但欢迎评论和回答=)
@Vallerii:测试结果状态似乎是一种更简单的方法,但是如果我这样做了,测试就无法知道该方法没有这样做:
replaceItem(updatedItem) {
const { myItems } = state;
const working = [...myItems];
const itemToReplace = working.find(x => x.id == updatedItem.id);
if (itemToReplace) {
working.splice(working.indexOf(itemToReplace), 1, updatedItem);
};
this.setState({ myItems: working });
}
当 replaceItem 没有为 setState 使用正确的重载时,此代码在重复调用时会失败,因为(我假设)react 正在批量更新并且此版本使用的状态已过时。
解决方案
我认为你应该测试一些不同的东西,它看起来像这样(我正在使用酶):
import React from 'react'
import { mount } from 'enzyme'
import CounterComponent from './CounterComponent'
it("Should increase state by one", () => {
const component = mount(<CounterComponent />)
const counter = 10;
component.setState({ counter });
component.instance().updateCounter();
expect(component.state().counter).toEqual(counter + 1);
});
推荐阅读
- javascript - 为什么我的空对象文字记录为假?
- opencart - opencart 管理员没有图像拇指
- android - GoogleMapSnapshot NullPointerException
- firebase - 访问firebase中的相邻数据
- excel - 在常规的非 Office 应用程序中使用 Interop 的正确方法是什么?
- linux - 在本机库调用中找不到产生“CXXABI_1.3.9”的 AWS lambda
- html - Chrome 和 Safari HTML5 视频渲染。挂在第一帧。
- javascript - Javascript - 等待数组完成填充
- python - PyCharm 远程部署:未保存用户名
- ssl - 无法将 .CER 文件转换为 .PEM