我正在尝试测试一个使用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: ''}
和其他一些属性。当用户单击“保存”时,将为数组中的每个项目触发一个异步操作,然后在该操作返回或被拒绝时更新相应的条目。例如,save方法如下所示:
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是批处理更新,并且此版本使用的状态是陈旧的。
经过进一步思考,我想出了一个解决方案。我不确定这是否是最佳解决方案,但是鉴于updateCounter
上面示例中的方法将一个函数传递给setState
调用,因此我可以简单地获取对该函数的引用,以已知状态执行该函数并检查返回值是否正确。
结果测试如下:
it("Should call setState with the expected parameters", () => {
let updateStateFunction = null;
const component = new CounterComponent();
component.setState = jest.fn((func) => { updateStateFunction = func;});
component.updateCounter();
const originalState = { counterValue: 10 };
const expectedState = { counterValue: 11};
expect(component.setState).toHaveBeenCalled();
expect(updateStateFunction(originalState)).toEqual(expectedState);
});
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句