测试带有功能的React Components setState重载

时间:2019-01-24 18:14:03

标签: javascript reactjs jestjs

我正在尝试测试一个使用setState重载之一的React组件,但是不确定如何正确断言该调用。一个示例组件是:

git show [<options>] [<object>...] [--] [<path>...]

这里的假设是此方法将被异步调用,因此不能依赖于当前状态,而不会调用setState(因为在setState执行之前它可能会更改)。谁能建议您如何主张此通话?以下测试失败了,因为它只是在比较函数名称。

# use the .dot method for shortness' sake
anom_winter_av_npi.rolling(window=7).apply(lambda x: wts.dot(x) / wts.sum())

编辑:鉴于下面yohai的回答,我将添加一些进一步的上下文,因为我认为我可能已经过度简化了该问题,但是为了清晰起见,我不想重写整个问题。

在我的实际组件中,要编辑的状态值不是一个简单的数字,它是具有以下结构的对象数组:

class CounterComponent extends React.Component {

    updateCounter() {
        this.setState((state) => {
            return {
                counterValue: state.counterValue + 1
            };
        });
    }
}

和其他一些属性。当用户单击“保存”时,将为数组中的每个项目触发一个异步操作,然后在该操作返回或被拒绝时更新相应的条目。例如,save方法如下所示:

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);
        });

句柄成功和错误方法只是更新对象并调用replaceItem:

{ isSaving: false, hasError: false, errorMessage: ''}

然后replaceItem替换数组中的项目:

onSave() {
    const { myItems } = this.state;

    myItems.forEach(item => {
        api.DoStuff(item)
            .then(response => this.handleSuccess(response, item))
            .catch(error => this.handleError(error, item));
    });
}

replaceItem是我要测试的方法,并试图验证它以正确的重载和正确更新状态的函数调用setState。

下面的答案详细说明了如何为自己解决此问题,但是欢迎发表评论和答案=)

@Vallerii:测试结果状态确实看起来更简单,但是如果我这样做,则测试无法知道该方法没有执行此操作:

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未对setState使用正确的重载时,此代码将在重复调用时失败,因为(我认为)react是批处理更新,并且此版本使用的状态是陈旧的。

2 个答案:

答案 0 :(得分:2)

我认为您应该测试一些不同的东西,它看起来像这样(我正在使用酶):

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);
});

答案 1 :(得分:0)

经过进一步思考,我想出了一个解决方案。我不确定这是否是最佳解决方案,但是鉴于上例中的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);
});